hedgewars/uGearsUtils.pas
branchwebgl
changeset 9521 8054d9d775fd
parent 9160 fc46e75f6b72
parent 9489 0818d14e90be
child 9950 2759212a27de
equal deleted inserted replaced
9282:92af50454cf2 9521:8054d9d775fd
    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 function WorldWrap(var Gear: PGear): boolean;
       
    57 
       
    58 
       
    59 
    44 function MakeHedgehogsStep(Gear: PGear) : boolean;
    60 function MakeHedgehogsStep(Gear: PGear) : boolean;
    45 
    61 
    46 var doStepHandlers: array[TGearType] of TGearStepProcedure;
    62 var doStepHandlers: array[TGearType] of TGearStepProcedure;
    47 
    63 
    48 
    64 
    49 implementation
    65 implementation
    50 uses uFloat, uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc,
    66 uses uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc,
    51     uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore,
    67     uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore,
    52     uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, uGears,
    68     uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, 
    53     uGearsList, Math;
    69     uGearsList, Math, uVisualGearsList, uGearsHandlersMess,
       
    70     uGearsHedgehog;
    54 
    71 
    55 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
    72 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
    56 begin
    73 begin
    57     doMakeExplosion(X, Y, Radius, AttackingHog, Mask, $FFFFFFFF);
    74     doMakeExplosion(X, Y, Radius, AttackingHog, Mask, $FFFFFFFF);
    58 end;
    75 end;
   469             end;
   486             end;
   470         if isSubmersible and (Gear = CurAmmoGear) and (CurAmmoGear^.Pos = 0) then
   487         if isSubmersible and (Gear = CurAmmoGear) and (CurAmmoGear^.Pos = 0) then
   471             CurAmmoGear^.Pos := 1000
   488             CurAmmoGear^.Pos := 1000
   472         end
   489         end
   473     else
   490     else
   474         CheckGearDrowning := false;
   491         begin
       
   492         if (not ((Gear^.Kind = gtJetpack) or (Gear^.Kind = gtBee))) then
       
   493             Gear^.State:= (Gear^.State and (not gstSubmersible));  // making it temporary for most gears is more attractive I think
       
   494         CheckGearDrowning := false
       
   495         end
   475 end;
   496 end;
   476 
   497 
   477 
   498 
   478 procedure ResurrectHedgehog(var gear: PGear);
   499 procedure ResurrectHedgehog(var gear: PGear);
   479 var tempTeam : PTeam;
   500 var tempTeam : PTeam;
   573     ignoreNearObjects, ignoreOverlap, tryAgain: boolean;
   594     ignoreNearObjects, ignoreOverlap, tryAgain: boolean;
   574 begin
   595 begin
   575 ignoreNearObjects:= false; // try not skipping proximity at first
   596 ignoreNearObjects:= false; // try not skipping proximity at first
   576 ignoreOverlap:= false; // this not only skips proximity, but allows overlapping objects (barrels, mines, hogs, crates).  Saving it for a 3rd pass.  With this active, winning AI Survival goes back to virtual impossibility
   597 ignoreOverlap:= false; // this not only skips proximity, but allows overlapping objects (barrels, mines, hogs, crates).  Saving it for a 3rd pass.  With this active, winning AI Survival goes back to virtual impossibility
   577 tryAgain:= true;
   598 tryAgain:= true;
       
   599 if WorldEdge <> weNone then 
       
   600     begin
       
   601     Left:= max(Left,leftX+Gear^.Radius);
       
   602     Right:= min(Right,rightX-Gear^.Radius)
       
   603     end;
   578 while tryAgain do
   604 while tryAgain do
   579     begin
   605     begin
   580     delta:= LAND_WIDTH div 16;
   606     delta:= LAND_WIDTH div 16;
   581     cnt2:= 0;
   607     cnt2:= 0;
   582     repeat
   608     repeat
   771         end
   797         end
   772         end
   798         end
   773         end;
   799         end;
   774 end;
   800 end;
   775 
   801 
       
   802 
       
   803 procedure ShotgunShot(Gear: PGear);
       
   804 var t: PGear;
       
   805     dmg, r, dist: LongInt;
       
   806     dx, dy: hwFloat;
       
   807 begin
       
   808 Gear^.Radius:= cShotgunRadius;
       
   809 t:= GearsList;
       
   810 while t <> nil do
       
   811     begin
       
   812     case t^.Kind of
       
   813         gtHedgehog,
       
   814             gtMine,
       
   815             gtSMine,
       
   816             gtKnife,
       
   817             gtCase,
       
   818             gtTarget,
       
   819             gtExplosives: begin//,
       
   820 //            gtStructure: begin
       
   821 //addFileLog('ShotgunShot radius: ' + inttostr(Gear^.Radius) + ', t^.Radius = ' + inttostr(t^.Radius) + ', distance = ' + inttostr(dist) + ', dmg = ' + inttostr(dmg));
       
   822                     dmg:= 0;
       
   823                     r:= Gear^.Radius + t^.Radius;
       
   824                     dx:= Gear^.X-t^.X;
       
   825                     dx.isNegative:= false;
       
   826                     dy:= Gear^.Y-t^.Y;
       
   827                     dy.isNegative:= false;
       
   828                     if r-hwRound(dx+dy) > 0 then
       
   829                         begin
       
   830                         dist:= hwRound(Distance(dx, dy));
       
   831                         dmg:= ModifyDamage(min(r - dist, 25), t);
       
   832                         end;
       
   833                     if dmg > 0 then
       
   834                         begin
       
   835                         if (not t^.Invulnerable) then
       
   836                             ApplyDamage(t, Gear^.Hedgehog, dmg, dsBullet)
       
   837                         else
       
   838                             Gear^.State:= Gear^.State or gstWinner;
       
   839 
       
   840                         DeleteCI(t);
       
   841                         t^.dX:= t^.dX + Gear^.dX * dmg * _0_01 + SignAs(cHHKick, Gear^.dX);
       
   842                         t^.dY:= t^.dY + Gear^.dY * dmg * _0_01;
       
   843                         t^.State:= t^.State or gstMoving;
       
   844                         if t^.Kind = gtKnife then t^.State:= t^.State and (not gstCollision);
       
   845                         t^.Active:= true;
       
   846                         FollowGear:= t
       
   847                         end
       
   848                     end;
       
   849             gtGrave: begin
       
   850                     dmg:= 0;
       
   851                     r:= Gear^.Radius + t^.Radius;
       
   852                     dx:= Gear^.X-t^.X;
       
   853                     dx.isNegative:= false;
       
   854                     dy:= Gear^.Y-t^.Y;
       
   855                     dy.isNegative:= false;
       
   856                     if r-hwRound(dx+dy) > 0 then
       
   857                         begin
       
   858                         dist:= hwRound(Distance(dx, dy));
       
   859                         dmg:= ModifyDamage(min(r - dist, 25), t);
       
   860                         end;
       
   861                     if dmg > 0 then
       
   862                         begin
       
   863                         t^.dY:= - _0_1;
       
   864                         t^.Active:= true
       
   865                         end
       
   866                     end;
       
   867         end;
       
   868     t:= t^.NextGear
       
   869     end;
       
   870 if (GameFlags and gfSolidLand) = 0 then
       
   871     DrawExplosion(hwRound(Gear^.X), hwRound(Gear^.Y), cShotgunRadius)
       
   872 end;
       
   873 
       
   874 procedure AmmoShove(Ammo: PGear; Damage, Power: LongInt);
       
   875 var t: PGearArray;
       
   876     Gear: PGear;
       
   877     i, j, tmpDmg: LongInt;
       
   878     VGear: PVisualGear;
       
   879 begin
       
   880 t:= CheckGearsCollision(Ammo);
       
   881 // Just to avoid hogs on rope dodging fire.
       
   882 if (CurAmmoGear <> nil) and ((CurAmmoGear^.Kind = gtRope) or (CurAmmoGear^.Kind = gtJetpack) or (CurAmmoGear^.Kind = gtBirdy))
       
   883 and (CurrentHedgehog^.Gear <> nil) and (CurrentHedgehog^.Gear^.CollisionIndex = -1)
       
   884 and (sqr(hwRound(Ammo^.X) - hwRound(CurrentHedgehog^.Gear^.X)) + sqr(hwRound(Ammo^.Y) - hwRound(CurrentHedgehog^.Gear^.Y)) <= sqr(cHHRadius + Ammo^.Radius)) then
       
   885     begin
       
   886     t^.ar[t^.Count]:= CurrentHedgehog^.Gear;
       
   887     inc(t^.Count)
       
   888     end;
       
   889 
       
   890 i:= t^.Count;
       
   891 
       
   892 if (Ammo^.Kind = gtFlame) and (i > 0) then
       
   893     Ammo^.Health:= 0;
       
   894 while i > 0 do
       
   895     begin
       
   896     dec(i);
       
   897     Gear:= t^.ar[i];
       
   898     if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and 
       
   899        (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then
       
   900         Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000);
       
   901     tmpDmg:= ModifyDamage(Damage, Gear);
       
   902     if (Gear^.State and gstNoDamage) = 0 then
       
   903         begin
       
   904 
       
   905         if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then 
       
   906             begin
       
   907             VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit);
       
   908             if VGear <> nil then
       
   909                 VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
       
   910             end;
       
   911 
       
   912         if (Gear^.Kind = gtHedgehog) and (Ammo^.State and gsttmpFlag <> 0) and (Ammo^.Kind = gtShover) then
       
   913             Gear^.FlightTime:= 1;
       
   914 
       
   915 
       
   916         case Gear^.Kind of
       
   917             gtHedgehog,
       
   918             gtMine,
       
   919             gtSMine,
       
   920             gtKnife,
       
   921             gtTarget,
       
   922             gtCase,
       
   923             gtExplosives: //,
       
   924             //gtStructure:
       
   925             begin
       
   926             if (Ammo^.Kind = gtDrill) then
       
   927                 begin
       
   928                 Ammo^.Timer:= 0;
       
   929                 exit;
       
   930                 end;
       
   931             if (not Gear^.Invulnerable) then
       
   932                 begin
       
   933                 if (Ammo^.Kind = gtKnife) and (tmpDmg > 0) then
       
   934                     for j:= 1 to max(1,min(3,tmpDmg div 5)) do
       
   935                         begin
       
   936                         VGear:= AddVisualGear(hwRound(Ammo^.X-((Ammo^.X-Gear^.X)/_2)), hwRound(Ammo^.Y-((Ammo^.Y-Gear^.Y)/_2)), vgtStraightShot);
       
   937                         if VGear <> nil then
       
   938                             with VGear^ do
       
   939                                 begin
       
   940                                 Tint:= $FFCC00FF;
       
   941                                 Angle:= random(360);
       
   942                                 dx:= 0.0005 * (random(100));
       
   943                                 dy:= 0.0005 * (random(100));
       
   944                                 if random(2) = 0 then
       
   945                                     dx := -dx;
       
   946                                 if random(2) = 0 then
       
   947                                     dy := -dy;
       
   948                                 FrameTicks:= 600+random(200);
       
   949                                 State:= ord(sprStar)
       
   950                                 end
       
   951                         end;
       
   952                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove)
       
   953                 end
       
   954             else
       
   955                 Gear^.State:= Gear^.State or gstWinner;
       
   956             if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then 
       
   957                 begin
       
   958                 if (Ammo^.Hedgehog^.Gear <> nil) then
       
   959                     Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable);
       
   960                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
       
   961                 end;
       
   962 
       
   963             if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
       
   964                 begin
       
   965                 Gear^.dX:= Ammo^.dX * Power * _0_005;
       
   966                 Gear^.dY:= Ammo^.dY * Power * _0_005
       
   967                 end
       
   968             else if ((Ammo^.Kind <> gtFlame) or (Gear^.Kind = gtHedgehog)) and (Power <> 0) then
       
   969                 begin
       
   970                 Gear^.dX:= Ammo^.dX * Power * _0_01;
       
   971                 Gear^.dY:= Ammo^.dY * Power * _0_01
       
   972                 end;
       
   973 
       
   974             if (not isZero(Gear^.dX)) or (not isZero(Gear^.dY)) then
       
   975                 begin
       
   976                 Gear^.Active:= true;
       
   977                 DeleteCI(Gear);
       
   978                 Gear^.State:= Gear^.State or gstMoving;
       
   979                 if Gear^.Kind = gtKnife then Gear^.State:= Gear^.State and (not gstCollision);
       
   980                 // move the gear upwards a bit to throw it over tiny obstacles at start
       
   981                 if TestCollisionXwithGear(Gear, hwSign(Gear^.dX)) then
       
   982                     begin
       
   983                     if not (TestCollisionXwithXYShift(Gear, _0, -3, hwSign(Gear^.dX))
       
   984                     or (TestCollisionYwithGear(Gear, -1) <> 0)) then
       
   985                         Gear^.Y:= Gear^.Y - _1;
       
   986                     if not (TestCollisionXwithXYShift(Gear, _0, -2, hwSign(Gear^.dX))
       
   987                     or (TestCollisionYwithGear(Gear, -1) <> 0)) then
       
   988                         Gear^.Y:= Gear^.Y - _1;
       
   989                     if not (TestCollisionXwithXYShift(Gear, _0, -1, hwSign(Gear^.dX))
       
   990                     or (TestCollisionYwithGear(Gear, -1) <> 0)) then
       
   991                         Gear^.Y:= Gear^.Y - _1;
       
   992                     end
       
   993                 end;
       
   994 
       
   995 
       
   996             if (Ammo^.Kind <> gtFlame) or ((Ammo^.State and gsttmpFlag) = 0) then
       
   997                 FollowGear:= Gear
       
   998             end;
       
   999         end
       
  1000         end;
       
  1001     end;
       
  1002 if i <> 0 then
       
  1003     SetAllToActive
       
  1004 end;
       
  1005 
       
  1006 
       
  1007 function CountGears(Kind: TGearType): Longword;
       
  1008 var t: PGear;
       
  1009     count: Longword = 0;
       
  1010 begin
       
  1011 
       
  1012 t:= GearsList;
       
  1013 while t <> nil do
       
  1014     begin
       
  1015     if t^.Kind = Kind then
       
  1016         inc(count);
       
  1017     t:= t^.NextGear
       
  1018     end;
       
  1019 CountGears:= count;
       
  1020 end;
       
  1021 
       
  1022 procedure SetAllToActive;
       
  1023 var t: PGear;
       
  1024 begin
       
  1025 AllInactive:= false;
       
  1026 t:= GearsList;
       
  1027 while t <> nil do
       
  1028     begin
       
  1029     t^.Active:= true;
       
  1030     t:= t^.NextGear
       
  1031     end
       
  1032 end;
       
  1033 
       
  1034 procedure SetAllHHToActive; inline;
       
  1035 begin
       
  1036 SetAllHHToActive(true)
       
  1037 end;
       
  1038 
       
  1039 
       
  1040 procedure SetAllHHToActive(Ice: boolean);
       
  1041 var t: PGear;
       
  1042 begin
       
  1043 AllInactive:= false;
       
  1044 t:= GearsList;
       
  1045 while t <> nil do
       
  1046     begin
       
  1047     if (t^.Kind = gtHedgehog) or (t^.Kind = gtExplosives) then
       
  1048         begin
       
  1049         if (t^.Kind = gtHedgehog) and Ice then CheckIce(t);
       
  1050         t^.Active:= true
       
  1051         end;
       
  1052     t:= t^.NextGear
       
  1053     end
       
  1054 end;
       
  1055 
       
  1056 
       
  1057 var GearsNearArray : TPGearArray;
       
  1058 function GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS;
       
  1059 var
       
  1060     t: PGear;
       
  1061     s: Longword;
       
  1062 begin
       
  1063     r:= r*r;
       
  1064     s:= 0;
       
  1065     SetLength(GearsNearArray, s);
       
  1066     t := GearsList;
       
  1067     while t <> nil do 
       
  1068         begin
       
  1069         if (t^.Kind = Kind) 
       
  1070             and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then
       
  1071             begin
       
  1072             inc(s);
       
  1073             SetLength(GearsNearArray, s);
       
  1074             GearsNearArray[s - 1] := t;
       
  1075             end;
       
  1076         t := t^.NextGear;
       
  1077     end;
       
  1078 
       
  1079     GearsNear.size:= s;
       
  1080     GearsNear.ar:= @GearsNearArray
       
  1081 end;
       
  1082 
       
  1083 
       
  1084 procedure SpawnBoxOfSmth;
       
  1085 var t, aTot, uTot, a, h: LongInt;
       
  1086     i: TAmmoType;
       
  1087 begin
       
  1088 if (PlacingHogs) or
       
  1089     (cCaseFactor = 0)
       
  1090     or (CountGears(gtCase) >= 5)
       
  1091     or (GetRandom(cCaseFactor) <> 0) then
       
  1092        exit;
       
  1093 
       
  1094 FollowGear:= nil;
       
  1095 aTot:= 0;
       
  1096 uTot:= 0;
       
  1097 for i:= Low(TAmmoType) to High(TAmmoType) do
       
  1098     if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
       
  1099         inc(aTot, Ammoz[i].Probability)
       
  1100     else
       
  1101         inc(uTot, Ammoz[i].Probability);
       
  1102 
       
  1103 t:=0;
       
  1104 a:=aTot;
       
  1105 h:= 1;
       
  1106 
       
  1107 if (aTot+uTot) <> 0 then
       
  1108     if ((GameFlags and gfInvulnerable) = 0) then
       
  1109         begin
       
  1110         h:= cHealthCaseProb * 100;
       
  1111         t:= GetRandom(10000);
       
  1112         a:= (10000-h)*aTot div (aTot+uTot)
       
  1113         end
       
  1114     else
       
  1115         begin
       
  1116         t:= GetRandom(aTot+uTot);
       
  1117         h:= 0
       
  1118         end;
       
  1119 
       
  1120 
       
  1121 if t<h then
       
  1122     begin
       
  1123     FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
       
  1124     FollowGear^.Health:= cHealthCaseAmount;
       
  1125     FollowGear^.Pos:= posCaseHealth;
       
  1126     AddCaption(GetEventString(eidNewHealthPack), cWhiteColor, capgrpAmmoInfo);
       
  1127     end
       
  1128 else if (t<a+h) then
       
  1129     begin
       
  1130     t:= aTot;
       
  1131     if (t > 0) then
       
  1132         begin
       
  1133         FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
       
  1134         t:= GetRandom(t);
       
  1135         i:= Low(TAmmoType);
       
  1136         FollowGear^.Pos:= posCaseAmmo;
       
  1137         FollowGear^.AmmoType:= i;
       
  1138         AddCaption(GetEventString(eidNewAmmoPack), cWhiteColor, capgrpAmmoInfo);
       
  1139         end
       
  1140     end
       
  1141 else
       
  1142     begin
       
  1143     t:= uTot;
       
  1144     if (t > 0) then
       
  1145         begin
       
  1146         FollowGear:= AddGear(0, 0, gtCase, 0, _0, _0, 0);
       
  1147         t:= GetRandom(t);
       
  1148         i:= Low(TAmmoType);
       
  1149         FollowGear^.Pos:= posCaseUtility;
       
  1150         FollowGear^.AmmoType:= i;
       
  1151         AddCaption(GetEventString(eidNewUtilityPack), cWhiteColor, capgrpAmmoInfo);
       
  1152         end
       
  1153     end;
       
  1154 
       
  1155 // handles case of no ammo or utility crates - considered also placing booleans in uAmmos and altering probabilities
       
  1156 if (FollowGear <> nil) then
       
  1157     begin
       
  1158     FindPlace(FollowGear, true, 0, LAND_WIDTH);
       
  1159 
       
  1160     if (FollowGear <> nil) then
       
  1161         AddVoice(sndReinforce, CurrentTeam^.voicepack)
       
  1162     end
       
  1163 end;
       
  1164 
       
  1165 
       
  1166 function GetAmmo(Hedgehog: PHedgehog): TAmmoType;
       
  1167 var t, aTot: LongInt;
       
  1168     i: TAmmoType;
       
  1169 begin
       
  1170 Hedgehog:= Hedgehog; // avoid hint
       
  1171 
       
  1172 aTot:= 0;
       
  1173 for i:= Low(TAmmoType) to High(TAmmoType) do
       
  1174     if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
       
  1175         inc(aTot, Ammoz[i].Probability);
       
  1176 
       
  1177 t:= aTot;
       
  1178 i:= Low(TAmmoType);
       
  1179 if (t > 0) then
       
  1180     begin
       
  1181     t:= GetRandom(t);
       
  1182     while t >= 0 do
       
  1183         begin
       
  1184         inc(i);
       
  1185         if (Ammoz[i].Ammo.Propz and ammoprop_Utility) = 0 then
       
  1186             dec(t, Ammoz[i].Probability)
       
  1187         end
       
  1188     end;
       
  1189 GetAmmo:= i
       
  1190 end;
       
  1191 
       
  1192 function GetUtility(Hedgehog: PHedgehog): TAmmoType;
       
  1193 var t, uTot: LongInt;
       
  1194     i: TAmmoType;
       
  1195 begin
       
  1196 
       
  1197 uTot:= 0;
       
  1198 for i:= Low(TAmmoType) to High(TAmmoType) do
       
  1199     if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0)
       
  1200     and ((Hedgehog^.Team^.HedgehogsNumber > 1) or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then
       
  1201         inc(uTot, Ammoz[i].Probability);
       
  1202 
       
  1203 t:= uTot;
       
  1204 i:= Low(TAmmoType);
       
  1205 if (t > 0) then
       
  1206     begin
       
  1207     t:= GetRandom(t);
       
  1208     while t >= 0 do
       
  1209         begin
       
  1210         inc(i);
       
  1211         if ((Ammoz[i].Ammo.Propz and ammoprop_Utility) <> 0) and ((Hedgehog^.Team^.HedgehogsNumber > 1)
       
  1212         or (Ammoz[i].Ammo.AmmoType <> amSwitch)) then
       
  1213             dec(t, Ammoz[i].Probability)
       
  1214         end
       
  1215     end;
       
  1216 GetUtility:= i
       
  1217 end;
       
  1218 
       
  1219 (*
       
  1220 Intended to check Gear X/Y against the map left/right edges and apply one of the world modes
       
  1221 * Normal - infinite world, do nothing
       
  1222 * Wrap (entering left edge exits at same height on right edge)
       
  1223 * Bounce (striking edge is treated as a 100% elasticity bounce)
       
  1224 * From the depths (same as from sky, but from sea, with submersible flag set)
       
  1225 
       
  1226 Trying to make the checks a little broader than on first pass to catch things that don't move normally.
       
  1227 *)
       
  1228 function WorldWrap(var Gear: PGear): boolean;
       
  1229 var tdx: hwFloat;
       
  1230 begin
       
  1231 WorldWrap:= false;
       
  1232 if WorldEdge = weNone then exit(false);
       
  1233 if (hwRound(Gear^.X)-Gear^.Radius < leftX) or
       
  1234    (hwRound(Gear^.X)+Gear^.Radius > rightX) then
       
  1235     begin
       
  1236     if WorldEdge = weWrap then
       
  1237         begin
       
  1238         if (hwRound(Gear^.X)-Gear^.Radius < leftX) then
       
  1239              Gear^.X:= int2hwfloat(rightX-Gear^.Radius)
       
  1240         else Gear^.X:= int2hwfloat(leftX+Gear^.Radius)
       
  1241         end
       
  1242     else if WorldEdge = weBounce then
       
  1243         begin
       
  1244         if (hwRound(Gear^.X)-Gear^.Radius < leftX) then
       
  1245             begin
       
  1246             Gear^.dX.isNegative:= false;
       
  1247             Gear^.X:= int2hwfloat(leftX+Gear^.Radius)
       
  1248             end
       
  1249         else 
       
  1250             begin
       
  1251             Gear^.dX.isNegative:= true;
       
  1252             Gear^.X:= int2hwfloat(rightX-Gear^.Radius)
       
  1253             end
       
  1254         end
       
  1255     else if WorldEdge = weSea then
       
  1256         begin
       
  1257         if (hwRound(Gear^.Y) > cWaterLine) and (Gear^.State and gstSubmersible <> 0) then
       
  1258             Gear^.State:= Gear^.State and (not gstSubmersible)
       
  1259         else
       
  1260             begin
       
  1261             Gear^.State:= Gear^.State or gstSubmersible;
       
  1262             Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
       
  1263             Gear^.Y:= int2hwFloat(cWaterLine+cVisibleWater+Gear^.Radius*2);
       
  1264             tdx:= Gear^.dX;
       
  1265             Gear^.dX:= Gear^.dY;
       
  1266             Gear^.dY:= tdx;
       
  1267             Gear^.dY.isNegative:= true
       
  1268             end
       
  1269         end;
       
  1270 (*
       
  1271 * Window in the sky (Gear moved high into the sky, Y is used to determine X) [unfortunately, not a safe thing to do. shame, I thought aerial bombardment would be kinda neat
       
  1272 This one would be really easy to freeze game unless it was flagged unfortunately.
       
  1273 
       
  1274     else 
       
  1275         begin
       
  1276         Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
       
  1277         Gear^.Y:= -_2048-_256-_256;
       
  1278         tdx:= Gear^.dX;
       
  1279         Gear^.dX:= Gear^.dY;
       
  1280         Gear^.dY:= tdx;
       
  1281         Gear^.dY.isNegative:= false
       
  1282         end
       
  1283 *)
       
  1284     WorldWrap:= true
       
  1285     end;
       
  1286 end;
       
  1287 
   776 end.
  1288 end.