hedgewars/uGearsUtils.pas
changeset 10015 4feced261c68
parent 10012 82dd9f0c88f7
parent 9954 bf51bc7e2808
child 10105 8c5fa1d15bd5
equal deleted inserted replaced
10014:56d2f2d5aad8 10015:4feced261c68
    21 unit uGearsUtils;
    21 unit uGearsUtils;
    22 interface
    22 interface
    23 uses uTypes, uFloat;
    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;
    29 procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
    29 procedure ApplyDamage(Gear: PGear; AttackerHog: PHedgehog; Damage: Longword; Source: TDamageSource);
    30 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword);
    30 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword);
    31 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
    31 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
    45 function  GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS;
    45 function  GearsNear(X, Y: hwFloat; Kind: TGearType; r: LongInt): PGearArrayS;
    46 procedure SpawnBoxOfSmth;
    46 procedure SpawnBoxOfSmth;
    47 procedure ShotgunShot(Gear: PGear);
    47 procedure ShotgunShot(Gear: PGear);
    48 
    48 
    49 procedure SetAllToActive;
    49 procedure SetAllToActive;
    50 procedure SetAllHHToActive; inline;
       
    51 procedure SetAllHHToActive(Ice: boolean);
    50 procedure SetAllHHToActive(Ice: boolean);
       
    51 procedure SetAllHHToActive(); inline;
    52 
    52 
    53 function  GetAmmo(Hedgehog: PHedgehog): TAmmoType;
    53 function  GetAmmo(Hedgehog: PHedgehog): TAmmoType;
    54 function  GetUtility(Hedgehog: PHedgehog): TAmmoType;
    54 function  GetUtility(Hedgehog: PHedgehog): TAmmoType;
    55 
    55 
    56 function WorldWrap(var Gear: PGear): boolean;
    56 function WorldWrap(var Gear: PGear): boolean;
    62 var doStepHandlers: array[TGearType] of TGearStepProcedure;
    62 var doStepHandlers: array[TGearType] of TGearStepProcedure;
    63 
    63 
    64 implementation
    64 implementation
    65 uses uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc,
    65 uses uSound, uCollisions, uUtils, uConsts, uVisualGears, uAIMisc,
    66     uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore,
    66     uVariables, uLandGraphics, uScript, uStats, uCaptions, uTeams, uStore,
    67     uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug, 
    67     uLocale, uTextures, uRenderUtils, uRandom, SDLh, uDebug,
    68     uGearsList, Math, uVisualGearsList, uGearsHandlersMess,
    68     uGearsList, Math, uVisualGearsList, uGearsHandlersMess,
    69     uGearsHedgehog;
    69     uGearsHedgehog;
    70 
    70 
    71 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
    71 procedure doMakeExplosion(X, Y, Radius: LongInt; AttackingHog: PHedgehog; Mask: Longword); inline;
    72 begin
    72 begin
   197    King check should be in here instead of ApplyDamage since Tiy wants them kicked less
   197    King check should be in here instead of ApplyDamage since Tiy wants them kicked less
   198 *)
   198 *)
   199 i:= _1;
   199 i:= _1;
   200 if (CurrentHedgehog <> nil) and CurrentHedgehog^.King then
   200 if (CurrentHedgehog <> nil) and CurrentHedgehog^.King then
   201     i:= _1_5;
   201     i:= _1_5;
   202 if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog <> nil) and 
   202 if (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog <> nil) and
   203    (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
   203    (Gear^.Hedgehog^.King or (Gear^.Hedgehog^.Effects[heFrozen] > 0)) then
   204     ModifyDamage:= hwRound(cDamageModifier * dmg * i * cDamagePercent * _0_5 * _0_01)
   204     ModifyDamage:= hwRound(cDamageModifier * dmg * i * cDamagePercent * _0_5 * _0_01)
   205 else
   205 else
   206     ModifyDamage:= hwRound(cDamageModifier * dmg * i * cDamagePercent * _0_01)
   206     ModifyDamage:= hwRound(cDamageModifier * dmg * i * cDamagePercent * _0_01)
   207 end;
   207 end;
   249                                 end;
   249                                 end;
   250                         inc(i, 5);
   250                         inc(i, 5);
   251                         end;
   251                         end;
   252                     end
   252                     end
   253                 end;
   253                 end;
   254         if (GameFlags and gfKarma <> 0) and (GameFlags and gfInvulnerable = 0) and 
   254         if (GameFlags and gfKarma <> 0) and (GameFlags and gfInvulnerable = 0) and
   255            (CurrentHedgehog^.Effects[heInvulnerable] = 0) then
   255            (CurrentHedgehog^.Effects[heInvulnerable] = 0) then
   256             begin // this cannot just use Damage or it interrupts shotgun and gets you called stupid
   256             begin // this cannot just use Damage or it interrupts shotgun and gets you called stupid
   257             inc(CurrentHedgehog^.Gear^.Karma, tmpDmg);
   257             inc(CurrentHedgehog^.Gear^.Karma, tmpDmg);
   258             CurrentHedgehog^.Gear^.LastDamage := CurrentHedgehog;
   258             CurrentHedgehog^.Gear^.LastDamage := CurrentHedgehog;
   259             spawnHealthTagForHH(CurrentHedgehog^.Gear, tmpDmg);
   259             spawnHealthTagForHH(CurrentHedgehog^.Gear, tmpDmg);
   260             end;
   260             end;
   261         uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false);    
   261         uStats.HedgehogDamaged(Gear, AttackerHog, Damage, false);
   262         end;
   262         end;
   263     end else
   263     end else
   264     //else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure
   264     //else if Gear^.Kind <> gtStructure then // not gtHedgehog nor gtStructure
   265         Gear^.Hedgehog:= AttackerHog;
   265         Gear^.Hedgehog:= AttackerHog;
   266     inc(Gear^.Damage, Damage);
   266     inc(Gear^.Damage, Damage);
   267     
   267 
   268     ScriptCall('onGearDamage', Gear^.UID, Damage);
   268     ScriptCall('onGearDamage', Gear^.UID, Damage);
   269 end;
   269 end;
   270 
   270 
   271 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword);
   271 procedure spawnHealthTagForHH(HHGear: PGear; dmg: Longword);
   272 var tag: PVisualGear;
   272 var tag: PVisualGear;
   275 if (tag <> nil) then
   275 if (tag <> nil) then
   276     tag^.Hedgehog:= HHGear^.Hedgehog; // the tag needs the tag to determine the text color
   276     tag^.Hedgehog:= HHGear^.Hedgehog; // the tag needs the tag to determine the text color
   277 AllInactive:= false;
   277 AllInactive:= false;
   278 HHGear^.Active:= true;
   278 HHGear^.Active:= true;
   279 end;
   279 end;
   280     
   280 
   281 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
   281 procedure HHHurt(Hedgehog: PHedgehog; Source: TDamageSource);
   282 begin
   282 begin
   283 if Hedgehog^.Effects[heFrozen] <> 0 then exit;
   283 if Hedgehog^.Effects[heFrozen] <> 0 then exit;
   284 if (Source = dsFall) or (Source = dsExplosion) then
   284 if (Source = dsFall) or (Source = dsExplosion) then
   285     case random(3) of
   285     case random(3) of
   300         3: PlaySoundV(sndOw4, Hedgehog^.Team^.voicepack);
   300         3: PlaySoundV(sndOw4, Hedgehog^.Team^.voicepack);
   301     end
   301     end
   302 end;
   302 end;
   303 
   303 
   304 procedure CheckHHDamage(Gear: PGear);
   304 procedure CheckHHDamage(Gear: PGear);
   305 var 
   305 var
   306     dmg: LongInt;
   306     dmg: LongInt;
   307     i: LongWord;
   307     i: LongWord;
   308     particle: PVisualGear;
   308     particle: PVisualGear;
   309 begin
   309 begin
   310 if _0_4 < Gear^.dY then
   310 if _0_4 < Gear^.dY then
   338     end
   338     end
   339 end;
   339 end;
   340 
   340 
   341 
   341 
   342 procedure CalcRotationDirAngle(Gear: PGear);
   342 procedure CalcRotationDirAngle(Gear: PGear);
   343 var 
   343 var
   344     dAngle: real;
   344     dAngle: real;
   345 begin
   345 begin
   346     // Frac/Round to be kind to JS as of 2012-08-27 where there is yet no int64/uint64
   346     // Frac/Round to be kind to JS as of 2012-08-27 where there is yet no int64/uint64
   347     //dAngle := (Gear^.dX.QWordValue + Gear^.dY.QWordValue) / $80000000;
   347     //dAngle := (Gear^.dX.QWordValue + Gear^.dY.QWordValue) / $80000000;
   348     dAngle := (Gear^.dX.Round + Gear^.dY.Round) / 2 + (Gear^.dX.Frac/$100000000+Gear^.dY.Frac/$100000000);
   348     dAngle := (Gear^.dX.Round + Gear^.dY.Round) / 2 + (Gear^.dX.Frac/$100000000+Gear^.dY.Frac/$100000000);
   356     else if 360 < Gear^.DirAngle then
   356     else if 360 < Gear^.DirAngle then
   357         Gear^.DirAngle := Gear^.DirAngle - 360
   357         Gear^.DirAngle := Gear^.DirAngle - 360
   358 end;
   358 end;
   359 
   359 
   360 function CheckGearDrowning(var Gear: PGear): boolean;
   360 function CheckGearDrowning(var Gear: PGear): boolean;
   361 var 
   361 var
   362     skipSpeed, skipAngle, skipDecay: hwFloat;
   362     skipSpeed, skipAngle, skipDecay: hwFloat;
   363     i, maxDrops, X, Y: LongInt;
   363     i, maxDrops, X, Y: LongInt;
   364     vdX, vdY: real;
   364     vdX, vdY: real;
   365     particle, splash: PVisualGear;
   365     particle, splash: PVisualGear;
   366     isSubmersible: boolean;
   366     isSubmersible: boolean;
   387         skipDecay := _0_87;
   387         skipDecay := _0_87;
   388         X:= hwRound(Gear^.X);
   388         X:= hwRound(Gear^.X);
   389         vdX:= hwFloat2Float(Gear^.dX);
   389         vdX:= hwFloat2Float(Gear^.dX);
   390         vdY:= hwFloat2Float(Gear^.dY);
   390         vdY:= hwFloat2Float(Gear^.dY);
   391         // this could perhaps be a tiny bit higher.
   391         // this could perhaps be a tiny bit higher.
   392         if  (cWaterLine + 64 + Gear^.Radius > Y) and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed) 
   392         if  (cWaterLine + 64 + Gear^.Radius > Y) and (hwSqr(Gear^.dX) + hwSqr(Gear^.dY) > skipSpeed)
   393         and (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)) then
   393         and (hwAbs(Gear^.dX) > skipAngle * hwAbs(Gear^.dY)) then
   394             begin
   394             begin
   395             Gear^.dY.isNegative := true;
   395             Gear^.dY.isNegative := true;
   396             Gear^.dY := Gear^.dY * skipDecay;
   396             Gear^.dY := Gear^.dY * skipDecay;
   397             Gear^.dX := Gear^.dX * skipDecay;
   397             Gear^.dX := Gear^.dX * skipDecay;
   423                             end
   423                             end
   424                         end
   424                         end
   425                     else
   425                     else
   426                         Gear^.doStep := @doStepDrowningGear;
   426                         Gear^.doStep := @doStepDrowningGear;
   427                         if Gear^.Kind = gtFlake then
   427                         if Gear^.Kind = gtFlake then
   428                             exit // skip splashes 
   428                             exit // skip splashes
   429                 end
   429                 end
   430             else if (Y > cWaterLine + cVisibleWater*4) and 
   430             else if (Y > cWaterLine + cVisibleWater*4) and
   431                     ((Gear <> CurrentHedgehog^.Gear) or (CurAmmoGear = nil) or (CurAmmoGear^.State and gstSubmersible = 0)) then
   431                     ((Gear <> CurrentHedgehog^.Gear) or (CurAmmoGear = nil) or (CurAmmoGear^.State and gstSubmersible = 0)) then
   432                 Gear^.doStep:= @doStepDrowningGear;
   432                 Gear^.doStep:= @doStepDrowningGear;
   433             if ((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius))
   433             if ((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius))
   434             or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and (Gear = CurAmmoGear) and ((CurAmmoGear^.Pos = 0)
   434             or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and (Gear = CurAmmoGear) and ((CurAmmoGear^.Pos = 0)
   435             and (CurAmmoGear^.dY < _0_01))) then
   435             and (CurAmmoGear^.dY < _0_01))) then
   436                 if Gear^.Density * Gear^.dY > _1 then
   436                 if Gear^.Density * Gear^.dY > _1 then
   437                     PlaySound(sndSplash)
   437                     PlaySound(sndSplash)
   438                 else if Gear^.Density * Gear^.dY > _0_5 then 
   438                 else if Gear^.Density * Gear^.dY > _0_5 then
   439                     PlaySound(sndSkip)
   439                     PlaySound(sndSkip)
   440                 else
   440                 else
   441                     PlaySound(sndDroplet2);
   441                     PlaySound(sndDroplet2);
   442             end;
   442             end;
   443 
   443 
   445         and (((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius))
   445         and (((not isSubmersible) and (Y < cWaterLine + 64 + Gear^.Radius))
   446         or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and (Gear = CurAmmoGear) and ((CurAmmoGear^.Pos = 0)
   446         or (isSubmersible and (Y < cWaterLine + 2 + Gear^.Radius) and (Gear = CurAmmoGear) and ((CurAmmoGear^.Pos = 0)
   447         and (CurAmmoGear^.dY < _0_01)))) then
   447         and (CurAmmoGear^.dY < _0_01)))) then
   448             begin
   448             begin
   449             splash:= AddVisualGear(X, cWaterLine, vgtSplash);
   449             splash:= AddVisualGear(X, cWaterLine, vgtSplash);
   450             if splash <> nil then 
   450             if splash <> nil then
   451                 with splash^ do
   451                 with splash^ do
   452                 begin
   452                 begin
   453                 Scale:= hwFloat2Float(Gear^.Density / _3 * Gear^.dY);
   453                 Scale:= hwFloat2Float(Gear^.Density / _3 * Gear^.dY);
   454                 if Scale > 1 then Scale:= power(Scale,0.3333)
   454                 if Scale > 1 then Scale:= power(Scale,0.3333)
   455                 else Scale:= Scale + ((1-Scale) / 2);
   455                 else Scale:= Scale + ((1-Scale) / 2);
   468                         begin
   468                         begin
   469                         dX := dX - vdX / 10;
   469                         dX := dX - vdX / 10;
   470                         dY := dY - vdY / 5;
   470                         dY := dY - vdY / 5;
   471                         if splash <> nil then
   471                         if splash <> nil then
   472                             begin
   472                             begin
   473                             if splash^.Scale > 1 then 
   473                             if splash^.Scale > 1 then
   474                                 begin
   474                                 begin
   475                                 dX:= dX * power(splash^.Scale,0.3333); // tone down the droplet height further
   475                                 dX:= dX * power(splash^.Scale,0.3333); // tone down the droplet height further
   476                                 dY:= dY * power(splash^.Scale, 0.3333)
   476                                 dY:= dY * power(splash^.Scale, 0.3333)
   477                                 end
   477                                 end
   478                             else 
   478                             else
   479                                 begin
   479                                 begin
   480                                 dX:= dX * splash^.Scale;
   480                                 dX:= dX * splash^.Scale;
   481                                 dY:= dY * splash^.Scale
   481                                 dY:= dY * splash^.Scale
   482                                 end
   482                                 end
   483                             end
   483                             end
   487         if isSubmersible and (Gear = CurAmmoGear) and (CurAmmoGear^.Pos = 0) then
   487         if isSubmersible and (Gear = CurAmmoGear) and (CurAmmoGear^.Pos = 0) then
   488             CurAmmoGear^.Pos := 1000
   488             CurAmmoGear^.Pos := 1000
   489         end
   489         end
   490     else
   490     else
   491         begin
   491         begin
   492         if not (Gear^.Kind in [gtJetpack, gtBee]) then Gear^.State:= Gear^.State and not gstSubmersible;  // making it temporary for most gears is more attractive I think
   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
   493         CheckGearDrowning := false
   494         CheckGearDrowning := false
   494         end
   495         end
   495 end;
   496 end;
   496 
   497 
   497 
   498 
   510     gear^.Damage := 0;
   511     gear^.Damage := 0;
   511     gear^.Health := gear^.Hedgehog^.InitialHealth;
   512     gear^.Health := gear^.Hedgehog^.InitialHealth;
   512     gear^.Hedgehog^.Effects[hePoisoned] := 0;
   513     gear^.Hedgehog^.Effects[hePoisoned] := 0;
   513     if (CurrentHedgehog^.Effects[heResurrectable] = 0) or ((CurrentHedgehog^.Effects[heResurrectable] <> 0)
   514     if (CurrentHedgehog^.Effects[heResurrectable] = 0) or ((CurrentHedgehog^.Effects[heResurrectable] <> 0)
   514           and (Gear^.Hedgehog^.Team^.Clan <> CurrentHedgehog^.Team^.Clan)) then
   515           and (Gear^.Hedgehog^.Team^.Clan <> CurrentHedgehog^.Team^.Clan)) then
   515         with CurrentHedgehog^ do 
   516         with CurrentHedgehog^ do
   516             begin
   517             begin
   517             inc(Team^.stats.AIKills);
   518             inc(Team^.stats.AIKills);
   518             FreeTexture(Team^.AIKillsTex);
   519             FreeTexture(Team^.AIKillsTex);
   519             Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16);
   520             Team^.AIKillsTex := RenderStringTex(inttostr(Team^.stats.AIKills), Team^.Clan^.Color, fnt16);
   520             end;
   521             end;
   527     if sparkles <> nil then
   528     if sparkles <> nil then
   528         begin
   529         begin
   529         sparkles^.Tint:= tempTeam^.Clan^.Color shl 8 or $FF;
   530         sparkles^.Tint:= tempTeam^.Clan^.Color shl 8 or $FF;
   530         //sparkles^.Angle:= random(360);
   531         //sparkles^.Angle:= random(360);
   531         end;
   532         end;
   532     FindPlace(gear, false, 0, LAND_WIDTH, true); 
   533     FindPlace(gear, false, 0, LAND_WIDTH, true);
   533     if gear <> nil then
   534     if gear <> nil then
   534         begin
   535         begin
   535         AddVisualGear(hwRound(gear^.X), hwRound(gear^.Y), vgtExplosion);
   536         AddVisualGear(hwRound(gear^.X), hwRound(gear^.Y), vgtExplosion);
   536         PlaySound(sndWarp);
   537         PlaySound(sndWarp);
   537         RenderHealth(gear^.Hedgehog^);
   538         RenderHealth(gear^.Hedgehog^);
   585 procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean);
   586 procedure FindPlace(var Gear: PGear; withFall: boolean; Left, Right: LongInt; skipProximity: boolean);
   586 var x: LongInt;
   587 var x: LongInt;
   587     y, sy: LongInt;
   588     y, sy: LongInt;
   588     ar: array[0..1023] of TPoint;
   589     ar: array[0..1023] of TPoint;
   589     ar2: array[0..2047] of TPoint;
   590     ar2: array[0..2047] of TPoint;
       
   591     temp: TPoint;
   590     cnt, cnt2: Longword;
   592     cnt, cnt2: Longword;
   591     delta: LongInt;
   593     delta: LongInt;
   592     ignoreNearObjects, ignoreOverlap, tryAgain: boolean;
   594     ignoreNearObjects, ignoreOverlap, tryAgain: boolean;
   593 begin
   595 begin
   594 ignoreNearObjects:= false; // try not skipping proximity at first
   596 ignoreNearObjects:= false; // try not skipping proximity at first
   595 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
   596 tryAgain:= true;
   598 tryAgain:= true;
   597 if WorldEdge <> weNone then 
   599 if WorldEdge <> weNone then
   598     begin
   600     begin
   599     Left:= max(Left, LongInt(leftX) + Gear^.Radius);
   601     Left:= max(Left, LongInt(leftX) + Gear^.Radius);
   600     Right:= min(Right,rightX-Gear^.Radius)
   602     Right:= min(Right,rightX-Gear^.Radius)
   601     end;
   603     end;
   602 while tryAgain do
   604 while tryAgain do
   612             while y < cWaterLine do
   614             while y < cWaterLine do
   613                 begin
   615                 begin
   614                 repeat
   616                 repeat
   615                     inc(y, 2);
   617                     inc(y, 2);
   616                 until (y >= cWaterLine) or
   618                 until (y >= cWaterLine) or
   617                         (not ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) = 0)) or 
   619                         ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) = 0)) or
   618                         (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, lfLandMask) = 0));
   620                         (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, lfLandMask) = 0));
   619 
   621 
   620                 sy:= y;
   622                 sy:= y;
   621 
   623 
   622                 repeat
   624                 repeat
   623                     inc(y);
   625                     inc(y);
   624                 until (y >= cWaterLine) or
   626                 until (y >= cWaterLine) or
   625                         (not ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) <> 0)) or 
   627                         ((not ignoreOverlap) and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, $FFFF) <> 0)) or
   626                         (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, lfLandMask) <> 0)); 
   628                         (ignoreOverlap and (CountNonZeroz(x, y, Gear^.Radius - 1, 1, lfLandMask) <> 0));
   627 
   629 
   628                 if (y - sy > Gear^.Radius * 2)
   630                 if (y - sy > Gear^.Radius * 2)
   629                     and (((Gear^.Kind = gtExplosives)
   631                     and (((Gear^.Kind = gtExplosives)
   630                     and (y < cWaterLine)
   632                     and (y < cWaterLine)
   631                     and (ignoreNearObjects or NoGearsToAvoid(x, y - Gear^.Radius, 60, 60))
   633                     and (ignoreNearObjects or NoGearsToAvoid(x, y - Gear^.Radius, 60, 60))
   646 
   648 
   647                 inc(y, 10)
   649                 inc(y, 10)
   648                 end;
   650                 end;
   649 
   651 
   650             if cnt > 0 then
   652             if cnt > 0 then
   651                 with ar[GetRandom(cnt)] do
   653                 begin
       
   654                 temp := ar[GetRandom(cnt)];
       
   655                 with temp do
   652                     begin
   656                     begin
   653                     ar2[cnt2].x:= x;
   657                     ar2[cnt2].x:= x;
   654                     ar2[cnt2].y:= y;
   658                     ar2[cnt2].y:= y;
   655                     inc(cnt2)
   659                     inc(cnt2)
   656                     end
   660                     end
       
   661                 end
   657         until (x + Delta > Right);
   662         until (x + Delta > Right);
   658 
   663 
   659         dec(Delta, 60)
   664         dec(Delta, 60)
   660     until (cnt2 > 0) or (Delta < 70);
   665     until (cnt2 > 0) or (Delta < 70);
   661     // if either of these has not been tried, do another pass
   666     // if either of these has not been tried, do another pass
   665     if ignoreNearObjects then ignoreOverlap:= true;
   670     if ignoreNearObjects then ignoreOverlap:= true;
   666     ignoreNearObjects:= true;
   671     ignoreNearObjects:= true;
   667     end;
   672     end;
   668 
   673 
   669 if cnt2 > 0 then
   674 if cnt2 > 0 then
   670     with ar2[GetRandom(cnt2)] do
   675     begin
       
   676     temp := ar2[GetRandom(cnt2)];
       
   677     with temp do
   671         begin
   678         begin
   672         Gear^.X:= int2hwFloat(x);
   679         Gear^.X:= int2hwFloat(x);
   673         Gear^.Y:= int2hwFloat(y);
   680         Gear^.Y:= int2hwFloat(y);
   674         AddFileLog('Assigned Gear coordinates (' + inttostr(x) + ',' + inttostr(y) + ')');
   681         AddFileLog('Assigned Gear coordinates (' + inttostr(x) + ',' + inttostr(y) + ')');
   675         end
   682         end
       
   683     end
   676     else
   684     else
   677     begin
   685     begin
   678     OutError('Can''t find place for Gear', false);
   686     OutError('Can''t find place for Gear', false);
   679     if Gear^.Kind = gtHedgehog then
   687     if Gear^.Kind = gtHedgehog then
   680         Gear^.Hedgehog^.Effects[heResurrectable] := 0;
   688         Gear^.Hedgehog^.Effects[heResurrectable] := 0;
   716 procedure CheckCollisionWithLand(Gear: PGear); inline;
   724 procedure CheckCollisionWithLand(Gear: PGear); inline;
   717 begin
   725 begin
   718     if (TestCollisionX(Gear, hwSign(Gear^.dX)) <> 0)
   726     if (TestCollisionX(Gear, hwSign(Gear^.dX)) <> 0)
   719     or (TestCollisionY(Gear, hwSign(Gear^.dY)) <> 0) then
   727     or (TestCollisionY(Gear, hwSign(Gear^.dY)) <> 0) then
   720         Gear^.State := Gear^.State or gstCollision
   728         Gear^.State := Gear^.State or gstCollision
   721     else 
   729     else
   722         Gear^.State := Gear^.State and (not gstCollision)
   730         Gear^.State := Gear^.State and (not gstCollision)
   723 end;
   731 end;
   724 
   732 
   725 function MakeHedgehogsStep(Gear: PGear) : boolean;
   733 function MakeHedgehogsStep(Gear: PGear) : boolean;
   726 begin
   734 begin
   885     Ammo^.Health:= 0;
   893     Ammo^.Health:= 0;
   886 while i > 0 do
   894 while i > 0 do
   887     begin
   895     begin
   888     dec(i);
   896     dec(i);
   889     Gear:= t^.ar[i];
   897     Gear:= t^.ar[i];
   890     if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and 
   898     if ((Ammo^.Kind = gtFlame) or (Ammo^.Kind = gtBlowTorch)) and
   891        (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then
   899        (Gear^.Kind = gtHedgehog) and (Gear^.Hedgehog^.Effects[heFrozen] > 255) then
   892         Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000);
   900         Gear^.Hedgehog^.Effects[heFrozen]:= max(255,Gear^.Hedgehog^.Effects[heFrozen]-10000);
   893     tmpDmg:= ModifyDamage(Damage, Gear);
   901     tmpDmg:= ModifyDamage(Damage, Gear);
   894     if (Gear^.State and gstNoDamage) = 0 then
   902     if (Gear^.State and gstNoDamage) = 0 then
   895         begin
   903         begin
   896 
   904 
   897         if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then 
   905         if (Ammo^.Kind = gtDEagleShot) or (Ammo^.Kind = gtSniperRifleShot) then
   898             begin
   906             begin
   899             VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit);
   907             VGear := AddVisualGear(hwround(Ammo^.X), hwround(Ammo^.Y), vgtBulletHit);
   900             if VGear <> nil then
   908             if VGear <> nil then
   901                 VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
   909                 VGear^.Angle := DxDy2Angle(-Ammo^.dX, Ammo^.dY);
   902             end;
   910             end;
   943                         end;
   951                         end;
   944                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove)
   952                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg, dsShove)
   945                 end
   953                 end
   946             else
   954             else
   947                 Gear^.State:= Gear^.State or gstWinner;
   955                 Gear^.State:= Gear^.State or gstWinner;
   948             if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then 
   956             if (Gear^.Kind = gtExplosives) and (Ammo^.Kind = gtBlowtorch) then
   949                 begin
   957                 begin
   950                 if (Ammo^.Hedgehog^.Gear <> nil) then
   958                 if (Ammo^.Hedgehog^.Gear <> nil) then
   951                     Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable);
   959                     Ammo^.Hedgehog^.Gear^.State:= Ammo^.Hedgehog^.Gear^.State and (not gstNotKickable);
   952                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
   960                 ApplyDamage(Gear, Ammo^.Hedgehog, tmpDmg * 100, dsUnknown); // crank up damage for explosives + blowtorch
   953                 end;
   961                 end;
  1054 begin
  1062 begin
  1055     r:= r*r;
  1063     r:= r*r;
  1056     s:= 0;
  1064     s:= 0;
  1057     SetLength(GearsNearArray, s);
  1065     SetLength(GearsNearArray, s);
  1058     t := GearsList;
  1066     t := GearsList;
  1059     while t <> nil do 
  1067     while t <> nil do
  1060         begin
  1068         begin
  1061         if (t^.Kind = Kind) 
  1069         if (t^.Kind = Kind)
  1062             and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then
  1070             and ((X - t^.X)*(X - t^.X) + (Y - t^.Y)*(Y-t^.Y) < int2hwFloat(r)) then
  1063             begin
  1071             begin
  1064             inc(s);
  1072             inc(s);
  1065             SetLength(GearsNearArray, s);
  1073             SetLength(GearsNearArray, s);
  1066             GearsNearArray[s - 1] := t;
  1074             GearsNearArray[s - 1] := t;
  1239             begin
  1247             begin
  1240             LeftImpactTimer:= 333;
  1248             LeftImpactTimer:= 333;
  1241             Gear^.dX.isNegative:= false;
  1249             Gear^.dX.isNegative:= false;
  1242             Gear^.X:= int2hwfloat(LongInt(leftX) + Gear^.Radius)
  1250             Gear^.X:= int2hwfloat(LongInt(leftX) + Gear^.Radius)
  1243             end
  1251             end
  1244         else 
  1252         else
  1245             begin
  1253             begin
  1246             RightImpactTimer:= 333;
  1254             RightImpactTimer:= 333;
  1247             Gear^.dX.isNegative:= true;
  1255             Gear^.dX.isNegative:= true;
  1248             Gear^.X:= int2hwfloat(rightX-Gear^.Radius)
  1256             Gear^.X:= int2hwfloat(rightX-Gear^.Radius)
  1249             end;
  1257             end;
  1251             PlaySound(sndMelonImpact)
  1259             PlaySound(sndMelonImpact)
  1252         end
  1260         end
  1253     else if WorldEdge = weSea then
  1261     else if WorldEdge = weSea then
  1254         begin
  1262         begin
  1255         if (hwRound(Gear^.Y) > cWaterLine) and (Gear^.State and gstSubmersible <> 0) then
  1263         if (hwRound(Gear^.Y) > cWaterLine) and (Gear^.State and gstSubmersible <> 0) then
  1256             Gear^.State:= Gear^.State and not gstSubmersible
  1264             Gear^.State:= Gear^.State and (not gstSubmersible)
  1257         else
  1265         else
  1258             begin
  1266             begin
  1259             Gear^.State:= Gear^.State or gstSubmersible;
  1267             Gear^.State:= Gear^.State or gstSubmersible;
  1260             Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
  1268             Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
  1261             Gear^.Y:= int2hwFloat(cWaterLine+cVisibleWater+Gear^.Radius*2);
  1269             Gear^.Y:= int2hwFloat(cWaterLine+cVisibleWater+Gear^.Radius*2);
  1267         end;
  1275         end;
  1268 (*
  1276 (*
  1269 * 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
  1277 * 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
  1270 This one would be really easy to freeze game unless it was flagged unfortunately.
  1278 This one would be really easy to freeze game unless it was flagged unfortunately.
  1271 
  1279 
  1272     else 
  1280     else
  1273         begin
  1281         begin
  1274         Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
  1282         Gear^.X:= int2hwFloat(PlayWidth)*int2hwFloat(min(max(0,hwRound(Gear^.Y)),PlayHeight))/PlayHeight;
  1275         Gear^.Y:= -_2048-_256-_256;
  1283         Gear^.Y:= -_2048-_256-_256;
  1276         tdx:= Gear^.dX;
  1284         tdx:= Gear^.dX;
  1277         Gear^.dX:= Gear^.dY;
  1285         Gear^.dX:= Gear^.dY;