hedgewars/uGearsUtils.pas
changeset 9285 8e8b908970c2
parent 9283 76e68c136a11
child 9473 a51a69094c24
equal deleted inserted replaced
9283:76e68c136a11 9285:8e8b908970c2
    18 
    18 
    19 {$INCLUDE "options.inc"}
    19 {$INCLUDE "options.inc"}
    20 
    20 
    21 unit uGearsUtils;
    21 unit uGearsUtils;
    22 interface
    22 interface
    23 uses uTypes;
    23 uses uTypes, uFloat;
    24 
    24 
    25 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
    25 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
    26 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord); 
    26 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword; const Tint: LongWord); 
    27 
    27 
    28 function  ModifyDamage(dmg: Longword; Gear: PGear): Longword;
    28 function  ModifyDamage(dmg: Longword; Gear: PGear): Longword;
    39 function  CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear;
    39 function  CheckGearNear(Gear: PGear; Kind: TGearType; rX, rY: LongInt): PGear;
    40 function  CheckGearDrowning(var Gear: PGear): boolean;
    40 function  CheckGearDrowning(var Gear: PGear): boolean;
    41 procedure CheckCollision(Gear: PGear); inline;
    41 procedure CheckCollision(Gear: PGear); inline;
    42 procedure CheckCollisionWithLand(Gear: PGear); inline;
    42 procedure CheckCollisionWithLand(Gear: PGear); inline;
    43 
    43 
       
    44 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
       
    45 function  GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS;
       
    46 procedure SpawnBoxOfSmth;
       
    47 procedure ShotgunShot(Gear: PGear);
       
    48 
       
    49 procedure SetAllToActive;
       
    50 procedure SetAllHHToActive; inline;
       
    51 procedure SetAllHHToActive(Ice: boolean);
       
    52 
       
    53 function  GetAmmo(Hedgehog: PHedgehog): TAmmoType;
       
    54 function  GetUtility(Hedgehog: PHedgehog): TAmmoType;
       
    55 
       
    56 
       
    57 
    44 function MakeHedgehogsStep(Gear: PGear) : boolean;
    58 function MakeHedgehogsStep(Gear: PGear) : boolean;
    45 
    59 
    46 var doStepHandlers: array[TGearType] of TGearStepProcedure;
    60 var doStepHandlers: array[TGearType] of TGearStepProcedure;
    47 
    61 
    48 
    62 
    49 implementation
    63 implementation
    50 uses uFloat, uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc,
    64 uses uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc,
    51     uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore,
    65     uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore,
    52     uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, uGears,
    66     uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, 
    53     uGearsList, Math, uVisualGearsList;
    67     uGearsList, Math, uVisualGearsList, uGearsHandlersMess,
       
    68     uGearsHedgehog;
    54 
    69 
    55 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
    70 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
    56 begin
    71 begin
    57     doMakeExplosion(X, Y, Radius, AttackingHog, Mask, $FFFFFFFF);
    72     doMakeExplosion(X, Y, Radius, AttackingHog, Mask, $FFFFFFFF);
    58 end;
    73 end;
   764         end
   779         end
   765         end
   780         end
   766         end;
   781         end;
   767 end;
   782 end;
   768 
   783 
       
   784 
       
   785 procedure ShotgunShot(Gear: PGear);
       
   786 var t: PGear;
       
   787     dmg, r, dist: LongInt;
       
   788     dx, dy: hwFloat;
       
   789 begin
       
   790 Gear^.Radius:= cShotgunRadius;
       
   791 t:= GearsList;
       
   792 while t <> nil do
       
   793     begin
       
   794     case t^.Kind of
       
   795         gtHedgehog,
       
   796             gtMine,
       
   797             gtSMine,
       
   798             gtKnife,
       
   799             gtCase,
       
   800             gtTarget,
       
   801             gtExplosives: begin//,
       
   802 //            gtStructure: begin
       
   803 //addFileLog('ShotgunShot radius: ' + inttostr(Gear^.Radius) + ', t^.Radius = ' + inttostr(t^.Radius) + ', distance = ' + inttostr(dist) + ', dmg = ' + inttostr(dmg));
       
   804                     dmg:= 0;
       
   805                     r:= Gear^.Radius + t^.Radius;
       
   806                     dx:= Gear^.X-t^.X;
       
   807                     dx.isNegative:= false;
       
   808                     dy:= Gear^.Y-t^.Y;
       
   809                     dy.isNegative:= false;
       
   810                     if r-hwRound(dx+dy) > 0 then
       
   811                         begin
       
   812                         dist:= hwRound(Distance(dx, dy));
       
   813                         dmg:= ModifyDamage(min(r - dist, 25), t);
       
   814                         end;
       
   815                     if dmg > 0 then
       
   816                         begin
       
   817                         if (not t^.Invulnerable) then
       
   818                             ApplyDamage(t, Gear^.Hedgehog, dmg, dsBullet)
       
   819                         else
       
   820                             Gear^.State:= Gear^.State or gstWinner;
       
   821 
       
   822                         DeleteCI(t);
       
   823                         t^.dX:= t^.dX + Gear^.dX * dmg * _0_01 + SignAs(cHHKick, Gear^.dX);
       
   824                         t^.dY:= t^.dY + Gear^.dY * dmg * _0_01;
       
   825                         t^.State:= t^.State or gstMoving;
       
   826                         if t^.Kind = gtKnife then t^.State:= t^.State and (not gstCollision);
       
   827                         t^.Active:= true;
       
   828                         FollowGear:= t
       
   829                         end
       
   830                     end;
       
   831             gtGrave: begin
       
   832                     dmg:= 0;
       
   833                     r:= Gear^.Radius + t^.Radius;
       
   834                     dx:= Gear^.X-t^.X;
       
   835                     dx.isNegative:= false;
       
   836                     dy:= Gear^.Y-t^.Y;
       
   837                     dy.isNegative:= false;
       
   838                     if r-hwRound(dx+dy) > 0 then
       
   839                         begin
       
   840                         dist:= hwRound(Distance(dx, dy));
       
   841                         dmg:= ModifyDamage(min(r - dist, 25), t);
       
   842                         end;
       
   843                     if dmg > 0 then
       
   844                         begin
       
   845                         t^.dY:= - _0_1;
       
   846                         t^.Active:= true
       
   847                         end
       
   848                     end;
       
   849         end;
       
   850     t:= t^.NextGear
       
   851     end;
       
   852 if (GameFlags and gfSolidLand) = 0 then
       
   853     DrawExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cShotgunRadius)
       
   854 end;
       
   855 
       
   856 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
       
   857 var t: PGearArray;
       
   858     Gear: PGear;
       
   859     i, j, tmpDmg: LongInt;
       
   860     VGear: PVisualGear;
       
   861 begin
       
   862 t:= CheckGearsCollision(Ammo);
       
   863 // Just to avoid hogs on rope dodging fire.
       
   864 if (CurAmmoGear <> nil) and ((CurAmmoGear^.Kind = gtRope) or (CurAmmoGear^.Kind = gtJetpack) or (CurAmmoGear^.Kind = gtBirdy))
       
   865 and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.CollisionIndex = -1)
       
   866 and (sqr(hwRound(Ammo^.X) - hwRound(CurrentHedgehog^.Gear^.X)) + sqr(hwRound(Ammo^.Y) - hwRound(CurrentHedgehog^.Gear^.Y)) <= sqr(cHHRadius + Ammo^.Radius)) then
       
   867     begin
       
   868     t^.ar[t^.Count]:= CurrentHedgehog^.Gear;
       
   869     inc(t^.Count)
       
   870     end;
       
   871 
       
   872 i:= t^.Count;
       
   873 
       
   874 if (Ammo^.Kind = gtFlame) and (i > 0) then
       
   875     Ammo^.Health:= 0;
       
   876 while i > 0 do
       
   877     begin
       
   878     dec(i);
       
   879     Gear:= t^.ar[i];
       
   880     if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and 
       
   881        (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then
       
   882         Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000);
       
   883     tmpDmg:= ModifyDamage(Damage, Gear);
       
   884     if (Gear^.State and gstNoDamage) = 0 then
       
   885         begin
       
   886 
       
   887         if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then 
       
   888             begin
       
   889             VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit);
       
   890             if VGear <> nil then
       
   891                 VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
       
   892             end;
       
   893 
       
   894         if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then
       
   895             Gear^.FlightTime:= 1;
       
   896 
       
   897 
       
   898         case Gear^.Kind of
       
   899             gtHedgehog,
       
   900             gtMine,
       
   901             gtSMine,
       
   902             gtKnife,
       
   903             gtTarget,
       
   904             gtCase,
       
   905             gtExplosives: //,
       
   906             //gtStructure:
       
   907             begin
       
   908             if (Ammo^.Kind = gtDrill) then
       
   909                 begin
       
   910                 Ammo^.Timer:= 0;
       
   911                 exit;
       
   912                 end;
       
   913             if (not Gear^.Invulnerable) then
       
   914                 begin
       
   915                 if (Ammo^.Kind = gtKnife) and (tmpDmg > 0) then
       
   916                     for j:= 1 to max(1,min(3,tmpDmg div 5)) do
       
   917                         begin
       
   918                         VGear:= AddVisualGear(hwRound(Ammo^.X-((Ammo^.X-Gear^.X)/_2)), hwRound(Ammo^.Y-((Ammo^.Y-Gear^.Y)/_2)), vgtStraightShot);
       
   919                         if VGear <> nil then
       
   920                             with VGear^ do
       
   921                                 begin
       
   922                                 Tint:= $FFCC00FF;
       
   923                                 Angle:= random(360);
       
   924                                 dx:= 0.0005 * (random(100));
       
   925                                 dy:= 0.0005 * (random(100));
       
   926                                 if random(2) = 0 then
       
   927                                     dx := -dx;
       
   928                                 if random(2) = 0 then
       
   929                                     dy := -dy;
       
   930                                 FrameTicks:= 600+random(200);
       
   931                                 State:= ord(sprStar)
       
   932                                 end
       
   933                         end;
       
   934                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove)
       
   935                 end
       
   936             else
       
   937                 Gear^.State:= Gear^.State or gstWinner;
       
   938             if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then 
       
   939                 begin
       
   940                 if (Ammo^.Hedgehog^.Gear <> nil) then
       
   941                     Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable);
       
   942                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
       
   943                 end;
       
   944 
       
   945             if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
       
   946                 begin
       
   947                 Gear^.dX:= Ammo^.dX * Power * _0_005;
       
   948                 Gear^.dY:= Ammo^.dY * Power * _0_005
       
   949                 end
       
   950             else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then
       
   951                 begin
       
   952                 Gear^.dX:= Ammo^.dX * Power * _0_01;
       
   953                 Gear^.dY:= Ammo^.dY * Power * _0_01
       
   954                 end;
       
   955 
       
   956             if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
       
   957                 begin
       
   958                 Gear^.Active:= true;
       
   959                 DeleteCI(Gear);
       
   960                 Gear^.State:= Gear^.State or gstMoving;
       
   961                 if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and (not gstCollision);
       
   962                 // move the gear upwards a bit to throw it over tiny obstacles at start
       
   963                 if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
       
   964                     begin
       
   965                     if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))
       
   966                     or (TestCollisionYwithGear(Gear, -1) <> 0)) then
       
   967                         Gear^.Y:= Gear^.Y - _1;
       
   968                     if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX))
       
   969                     or (TestCollisionYwithGear(Gear, -1) <> 0)) then
       
   970                         Gear^.Y:= Gear^.Y - _1;
       
   971                     if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX))
       
   972                     or (TestCollisionYwithGear(Gear, -1) <> 0)) then
       
   973                         Gear^.Y:= Gear^.Y - _1;
       
   974                     end
       
   975                 end;
       
   976 
       
   977 
       
   978             if (Ammo^.Kind <> gtFlame) or ((Ammo^.State and gsttmpFlag) = 0) then
       
   979                 FollowGear:= Gear
       
   980             end;
       
   981         end
       
   982         end;
       
   983     end;
       
   984 if i <> 0 then
       
   985     SetAllToActive
       
   986 end;
       
   987 
       
   988 
       
   989 function CountGears(Kind: TGearType): Longword;
       
   990 var t: PGear;
       
   991     count: Longword = 0;
       
   992 begin
       
   993 
       
   994 t:= GearsList;
       
   995 while t <> nil do
       
   996     begin
       
   997     if t^.Kind = Kind then
       
   998         inc(count);
       
   999     t:= t^.NextGear
       
  1000     end;
       
  1001 CountGears:= count;
       
  1002 end;
       
  1003 
       
  1004 procedure SetAllToActive;
       
  1005 var t: PGear;
       
  1006 begin
       
  1007 AllInactive:= false;
       
  1008 t:= GearsList;
       
  1009 while t <> nil do
       
  1010     begin
       
  1011     t^.Active:= true;
       
  1012     t:= t^.NextGear
       
  1013     end
       
  1014 end;
       
  1015 
       
  1016 procedure SetAllHHToActive; inline;
       
  1017 begin
       
  1018 SetAllHHToActive(true)
       
  1019 end;
       
  1020 
       
  1021 
       
  1022 procedure SetAllHHToActive(Ice: boolean);
       
  1023 var t: PGear;
       
  1024 begin
       
  1025 AllInactive:= false;
       
  1026 t:= GearsList;
       
  1027 while t <> nil do
       
  1028     begin
       
  1029     if (t^.Kind = gtHedgehog) or (t^.Kind = gtExplosives) then
       
  1030         begin
       
  1031         if (t^.Kind = gtHedgehog) and Ice then CheckIce(t);
       
  1032         t^.Active:= true
       
  1033         end;
       
  1034     t:= t^.NextGear
       
  1035     end
       
  1036 end;
       
  1037 
       
  1038 
       
  1039 var GearsNearArray : TPGearArray;
       
  1040 function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS;
       
  1041 var
       
  1042     t: PGear;
       
  1043     s: Longword;
       
  1044 begin
       
  1045     r:= r*r;
       
  1046     s:= 0;
       
  1047     SetLength(GearsNearArray, s);
       
  1048     t := GearsList;
       
  1049     while t <> nil do 
       
  1050         begin
       
  1051         if (t^.Kind = Kind) 
       
  1052             and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then
       
  1053             begin
       
  1054             inc(s);
       
  1055             SetLength(GearsNearArray, s);
       
  1056             GearsNearArray[s - 1] := t;
       
  1057             end;
       
  1058         t := t^.NextGear;
       
  1059     end;
       
  1060 
       
  1061     GearsNear.size:= s;
       
  1062     GearsNear.ar:= @GearsNearArray
       
  1063 end;
       
  1064 
       
  1065 
       
  1066 procedure SpawnBoxOfSmth;
       
  1067 var t, aTot, uTot, a, h: LongInt;
       
  1068     i: TAmmoType;
       
  1069 begin
       
  1070 if (PlacingHogs) or
       
  1071     (cCaseFactor = 0)
       
  1072     or (CountGears(gtCase) >= 5)
       
  1073     or (GetRandom(cCaseFactor) <> 0) then
       
  1074        exit;
       
  1075 
       
  1076 FollowGear:= nil;
       
  1077 aTot:= 0;
       
  1078 uTot:= 0;
       
  1079 for i:= Low(TAmmoType) to High(TAmmoType) do
       
  1080     if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
       
  1081         inc(aTot, Ammoz[i].Probability)
       
  1082     else
       
  1083         inc(uTot, Ammoz[i].Probability);
       
  1084 
       
  1085 t:=0;
       
  1086 a:=aTot;
       
  1087 h:= 1;
       
  1088 
       
  1089 if (aTot+uTot) <> 0 then
       
  1090     if ((GameFlags and gfInvulnerable) = 0) then
       
  1091         begin
       
  1092         h:= cHealthCaseProb * 100;
       
  1093         t:= GetRandom(10000);
       
  1094         a:= (10000-h)*aTot div (aTot+uTot)
       
  1095         end
       
  1096     else
       
  1097         begin
       
  1098         t:= GetRandom(aTot+uTot);
       
  1099         h:= 0
       
  1100         end;
       
  1101 
       
  1102 
       
  1103 if t<h then
       
  1104     begin
       
  1105     FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
       
  1106     FollowGear^.Health:= cHealthCaseAmount;
       
  1107     FollowGear^.Pos:= posCaseHealth;
       
  1108     AddCaption(GetEventString(eidNewHealthPack), cWhiteColor, capgrpAmmoInfo);
       
  1109     end
       
  1110 else if (t<a+h) then
       
  1111     begin
       
  1112     t:= aTot;
       
  1113     if (t > 0) then
       
  1114         begin
       
  1115         FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
       
  1116         t:= GetRandom(t);
       
  1117         i:= Low(TAmmoType);
       
  1118         FollowGear^.Pos:= posCaseAmmo;
       
  1119         FollowGear^.AmmoType:= i;
       
  1120         AddCaption(GetEventString(eidNewAmmoPack), cWhiteColor, capgrpAmmoInfo);
       
  1121         end
       
  1122     end
       
  1123 else
       
  1124     begin
       
  1125     t:= uTot;
       
  1126     if (t > 0) then
       
  1127         begin
       
  1128         FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
       
  1129         t:= GetRandom(t);
       
  1130         i:= Low(TAmmoType);
       
  1131         FollowGear^.Pos:= posCaseUtility;
       
  1132         FollowGear^.AmmoType:= i;
       
  1133         AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo);
       
  1134         end
       
  1135     end;
       
  1136 
       
  1137 // handles case of no ammo or utility crates - considered also placing booleans in uAmmos and altering probabilities
       
  1138 if (FollowGear <> nil) then
       
  1139     begin
       
  1140     FindPlace(FollowGear, true, 0, LAND_WIDTH);
       
  1141 
       
  1142     if (FollowGear <> nil) then
       
  1143         AddVoice(sndReinforce, CurrentTeam^.voicepack)
       
  1144     end
       
  1145 end;
       
  1146 
       
  1147 
       
  1148 function GetAmmo(Hedgehog: PHedgehog): TAmmoType;
       
  1149 var t, aTot: LongInt;
       
  1150     i: TAmmoType;
       
  1151 begin
       
  1152 Hedgehog:= Hedgehog; // avoid hint
       
  1153 
       
  1154 aTot:= 0;
       
  1155 for i:= Low(TAmmoType) to High(TAmmoType) do
       
  1156     if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
       
  1157         inc(aTot, Ammoz[i].Probability);
       
  1158 
       
  1159 t:= aTot;
       
  1160 i:= Low(TAmmoType);
       
  1161 if (t > 0) then
       
  1162     begin
       
  1163     t:= GetRandom(t);
       
  1164     while t >= 0 do
       
  1165         begin
       
  1166         inc(i);
       
  1167         if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
       
  1168             dec(t, Ammoz[i].Probability)
       
  1169         end
       
  1170     end;
       
  1171 GetAmmo:= i
       
  1172 end;
       
  1173 
       
  1174 function GetUtility(Hedgehog: PHedgehog): TAmmoType;
       
  1175 var t, uTot: LongInt;
       
  1176     i: TAmmoType;
       
  1177 begin
       
  1178 
       
  1179 uTot:= 0;
       
  1180 for i:= Low(TAmmoType) to High(TAmmoType) do
       
  1181     if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0)
       
  1182     and ((Hedgehog^.Team^.HedgehogsNumber > 1) or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then
       
  1183         inc(uTot, Ammoz[i].Probability);
       
  1184 
       
  1185 t:= uTot;
       
  1186 i:= Low(TAmmoType);
       
  1187 if (t > 0) then
       
  1188     begin
       
  1189     t:= GetRandom(t);
       
  1190     while t >= 0 do
       
  1191         begin
       
  1192         inc(i);
       
  1193         if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) and ((Hedgehog^.Team^.HedgehogsNumber > 1)
       
  1194         or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then
       
  1195             dec(t, Ammoz[i].Probability)
       
  1196         end
       
  1197     end;
       
  1198 GetUtility:= i
       
  1199 end;
       
  1200 
       
  1201 
   769 end.
  1202 end.