hedgewars/uAIAmmoTests.pas
branch0.9.19
changeset 8924 13ac59499066
parent 8903 b35752efd5df
child 8950 3bf81ed1f984
equal deleted inserted replaced
8904:6ea838b8dcd5 8924:13ac59499066
    19 {$INCLUDE "options.inc"}
    19 {$INCLUDE "options.inc"}
    20 
    20 
    21 unit uAIAmmoTests;
    21 unit uAIAmmoTests;
    22 interface
    22 interface
    23 uses SDLh, uConsts, uFloat, uTypes;
    23 uses SDLh, uConsts, uFloat, uTypes;
    24 const 
    24 const
    25     amtest_Rare     = $00000001; // check only several positions
    25     amtest_Rare     = $00000001; // check only several positions
    26     amtest_NoTarget = $00000002; // each pos, but no targetting
    26     amtest_NoTarget = $00000002; // each pos, but no targetting
    27 
    27 
    28 var windSpeed: real;
    28 var windSpeed: real;
    29 
    29 
   161             x:= x + dX;
   161             x:= x + dX;
   162             y:= y + dY;
   162             y:= y + dY;
   163             dX:= dX + windSpeed;
   163             dX:= dX + windSpeed;
   164             dY:= dY + cGravityf;
   164             dY:= dY + cGravityf;
   165             dec(t)
   165             dec(t)
   166         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
   166         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
   167                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t <= 0);
   167                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (t <= 0);
   168         
   168 
   169         EX:= trunc(x);
   169         EX:= trunc(x);
   170         EY:= trunc(y);
   170         EY:= trunc(y);
   171         if Level = 1 then
   171         if Level = 1 then
   172             value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
   172             value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
   173         else value:= RateExplosion(Me, EX, EY, 101);
   173         else value:= RateExplosion(Me, EX, EY, 101);
   182             ap.ExplY:= EY;
   182             ap.ExplY:= EY;
   183             valueResult:= value
   183             valueResult:= value
   184             end;
   184             end;
   185         end
   185         end
   186 //until (value > 204800) or (rTime > 4250); not so useful since adding score to the drowning
   186 //until (value > 204800) or (rTime > 4250); not so useful since adding score to the drowning
   187 until rTime > 4250;
   187 until rTime > 5050 - Level * 800;
   188 TestBazooka:= valueResult
   188 TestBazooka:= valueResult
   189 end;
   189 end;
   190 
   190 
   191 
   191 
   192 function TestDrillRocket(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   192 function TestDrillRocket(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   224                 x:= x + dX;
   224                 x:= x + dX;
   225                 y:= y + dY;
   225                 y:= y + dY;
   226                 dX:= dX + windSpeed;
   226                 dX:= dX + windSpeed;
   227                 dY:= dY + cGravityf;
   227                 dY:= dY + cGravityf;
   228                 dec(t)
   228                 dec(t)
   229             until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
   229             until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
   230                    ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (y > cWaterLine);
   230                    ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (y > cWaterLine);
   231 
   231 
   232             if TestCollWithLand(trunc(x), trunc(y), 5) and (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) > 21) then
   232             if TestCollExcludingObjects(trunc(x), trunc(y), 5) and (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) > 21) then
   233                 begin
   233                 begin
   234                 timer := 500;
   234                 timer := 500;
   235                 t2 := 0.5 / sqrt(sqr(dX) + sqr(dY));
   235                 t2 := 0.5 / sqrt(sqr(dX) + sqr(dY));
   236                 dX := dX * t2;
   236                 dX := dX * t2;
   237                 dY := dY * t2;
   237                 dY := dY * t2;
   242                 until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 22)
   242                 until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 22)
   243                     or (x < 0)
   243                     or (x < 0)
   244                     or (y < 0)
   244                     or (y < 0)
   245                     or (trunc(x) > LAND_WIDTH)
   245                     or (trunc(x) > LAND_WIDTH)
   246                     or (trunc(y) > LAND_HEIGHT)
   246                     or (trunc(y) > LAND_HEIGHT)
   247                     or not TestCollWithLand(trunc(x), trunc(y), 5)
   247                     or not TestCollExcludingObjects(trunc(x), trunc(y), 5)
   248                     or (timer = 0)
   248                     or (timer = 0)
   249                 end;
   249                 end;
   250             EX:= trunc(x);
   250             EX:= trunc(x);
   251             EY:= trunc(y);
   251             EY:= trunc(y);
       
   252             // Try to prevent AI from thinking firing into water will cause a drowning
       
   253             if (EY < cWaterLine-5) and (Timer > 0) and (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) > 21) then exit(BadTurn);
   252             if Level = 1 then
   254             if Level = 1 then
   253                 value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
   255                 value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
   254             else value:= RateExplosion(Me, EX, EY, 101);
   256             else value:= RateExplosion(Me, EX, EY, 101);
   255             if valueResult <= value then
   257             if valueResult <= value then
   256                 begin
   258                 begin
   260                 ap.ExplX:= EX;
   262                 ap.ExplX:= EX;
   261                 ap.ExplY:= EY;
   263                 ap.ExplY:= EY;
   262                 valueResult:= value-2500 // trying to make it slightly less attractive than a bazooka, to prevent waste.  AI could use awareness of weapon count
   264                 valueResult:= value-2500 // trying to make it slightly less attractive than a bazooka, to prevent waste.  AI could use awareness of weapon count
   263                 end;
   265                 end;
   264             end
   266             end
   265     until rTime > 4250;
   267     until rTime > 5050 - Level * 800;
   266     TestDrillRocket:= valueResult
   268     TestDrillRocket:= valueResult
   267 end;
   269 end;
   268 
   270 
   269 
   271 
   270 function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   272 function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   299             x:= x + dX;
   301             x:= x + dX;
   300             y:= y + dY;
   302             y:= y + dY;
   301             dX:= dX + windSpeed;
   303             dX:= dX + windSpeed;
   302             dY:= dY + cGravityf;
   304             dY:= dY + cGravityf;
   303             dec(t)
   305             dec(t)
   304         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
   306         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
   305                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t <= 0);
   307                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (t <= 0);
   306         EX:= trunc(x);
   308         EX:= trunc(x);
   307         EY:= trunc(y);
   309         EY:= trunc(y);
   308 
   310 
   309         value:= RateShove(trunc(x), trunc(y), 5, 1, trunc((abs(dX)+abs(dY))*20), -dX, -dY, afTrackFall);
   311         value:= RateShove(trunc(x), trunc(y), 5, 1, trunc((abs(dX)+abs(dY))*20), -dX, -dY, afTrackFall);
   310         // LOL copypasta: this is score for digging with... snowball
   312         // LOL copypasta: this is score for digging with... snowball
   319             ap.ExplX:= EX;
   321             ap.ExplX:= EX;
   320             ap.ExplY:= EY;
   322             ap.ExplY:= EY;
   321             valueResult:= value
   323             valueResult:= value
   322             end;
   324             end;
   323      end
   325      end
   324 until (rTime > 4250);
   326 until (rTime > 5050 - Level * 800);
   325 TestSnowball:= valueResult
   327 TestSnowball:= valueResult
   326 end;
   328 end;
   327 
   329 
   328 function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   330 function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   329 var Vx, Vy, r: real;
   331 var Vx, Vy, r: real;
   351         repeat
   353         repeat
   352             x:= x + Vx;
   354             x:= x + Vx;
   353             y:= y + dY;
   355             y:= y + dY;
   354             dY:= dY + cGravityf;
   356             dY:= dY + cGravityf;
   355             dec(t)
   357             dec(t)
   356         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or 
   358         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or
   357                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 6))) or (t = 0);
   359                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 6))) or (t = 0);
   358         EX:= trunc(x);
   360         EX:= trunc(x);
   359         EY:= trunc(y);
   361         EY:= trunc(y);
   360         if t < 50 then
   362         if t < 50 then
   361             Score:= RateExplosion(Me, EX, EY, 97)  // average of 17 attempts, most good, but some failing spectacularly
   363             Score:= RateExplosion(Me, EX, EY, 97)  // average of 17 attempts, most good, but some failing spectacularly
   362         else
   364         else
   363             Score:= BadTurn;
   365             Score:= BadTurn;
   364                   
   366 
   365         if valueResult < Score then
   367         if valueResult < Score then
   366             begin
   368             begin
   367             ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
   369             ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
   368             ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
   370             ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
   369             ap.ExplR:= 100;
   371             ap.ExplR:= 100;
   370             ap.ExplX:= EX;
   372             ap.ExplX:= EX;
   371             ap.ExplY:= EY;
   373             ap.ExplY:= EY;
   372             valueResult:= Score
   374             valueResult:= Score
   373             end;
   375             end;
   374         end
   376         end
   375 until (TestTime > 4250);
   377 until (TestTime > 5050 - Level * 800);
   376 TestMolotov:= valueResult
   378 TestMolotov:= valueResult
   377 end;
   379 end;
   378 
   380 
   379 function TestGrenade(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   381 function TestGrenade(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   380 const tDelta = 24;
   382 const tDelta = 24;
   395     Vy:= cGravityf * ((TestTime + tDelta) div 2) - (Targ.Y - meY) / (TestTime + tDelta);
   397     Vy:= cGravityf * ((TestTime + tDelta) div 2) - (Targ.Y - meY) / (TestTime + tDelta);
   396     r:= sqr(Vx) + sqr(Vy);
   398     r:= sqr(Vx) + sqr(Vy);
   397     if not (r > 1) then
   399     if not (r > 1) then
   398         begin
   400         begin
   399         x:= meX;
   401         x:= meX;
   400         y:= meY; 
   402         y:= meY;
   401         dY:= -Vy;
   403         dY:= -Vy;
   402         t:= TestTime;
   404         t:= TestTime;
   403         repeat
   405         repeat
   404             x:= x + Vx;
   406             x:= x + Vx;
   405             y:= y + dY;
   407             y:= y + dY;
   406             dY:= dY + cGravityf;
   408             dY:= dY + cGravityf;
   407             dec(t)
   409             dec(t)
   408         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
   410         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
   409                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t = 0);
   411                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (t = 0);
   410     EX:= trunc(x);
   412     EX:= trunc(x);
   411     EY:= trunc(y);
   413     EY:= trunc(y);
   412     if t < 50 then 
   414     if t < 50 then
   413         if Level = 1 then
   415         if Level = 1 then
   414             Score:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
   416             Score:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
   415         else Score:= RateExplosion(Me, EX, EY, 101)
   417         else Score:= RateExplosion(Me, EX, EY, 101)
   416     else 
   418     else
   417         Score:= BadTurn;
   419         Score:= BadTurn;
   418 
   420 
   419     if (valueResult < Score) and (Score > 0) then
   421     if (valueResult < Score) and (Score > 0) then
   420         begin
   422         begin
   421         ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
   423         ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level * 3));
   422         ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
   424         ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 20);
   423         ap.Time:= TestTime;
   425         ap.Time:= TestTime;
   424         ap.ExplR:= 100;
   426         ap.ExplR:= 100;
   425         ap.ExplX:= EX;
   427         ap.ExplX:= EX;
   426         ap.ExplY:= EY;
   428         ap.ExplY:= EY;
   427         valueResult:= Score
   429         valueResult:= Score
   428         end;
   430         end;
   429     end
   431     end
   430 //until (Score > 204800) or (TestTime > 4000);
   432 //until (Score > 204800) or (TestTime > 4000);
   431 until TestTime > 4000;
   433 until TestTime > 4500 - Level * 512;
   432 TestGrenade:= valueResult
   434 TestGrenade:= valueResult
   433 end;
   435 end;
   434 
   436 
   435 function TestClusterBomb(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   437 function TestClusterBomb(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   436 const tDelta = 24;
   438 const tDelta = 24;
   463     repeat
   465     repeat
   464         x:= x + Vx;
   466         x:= x + Vx;
   465         y:= y + dY;
   467         y:= y + dY;
   466         dY:= dY + cGravityf;
   468         dY:= dY + cGravityf;
   467         dec(t)
   469         dec(t)
   468     until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or 
   470     until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
   469            ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t = 0);
   471            ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (t = 0);
   470     EX:= trunc(x);
   472     EX:= trunc(x);
   471     EY:= trunc(y);
   473     EY:= trunc(y);
   472     if t < 50 then 
   474     if t < 50 then
   473         Score:= RateExplosion(Me, EX, EY, 41)
   475         Score:= RateExplosion(Me, EX, EY, 41)
   474     else 
   476     else
   475         Score:= BadTurn;
   477         Score:= BadTurn;
   476 
   478 
   477      if valueResult < Score then
   479      if valueResult < Score then
   478         begin
   480         begin
   479         ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
   481         ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level * 2));
   480         ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
   482         ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
   481         ap.Time:= TestTime div 1000 * 1000;
   483         ap.Time:= TestTime div 1000 * 1000;
   482         ap.ExplR:= 90;
   484         ap.ExplR:= 90;
   483         ap.ExplX:= EX;
   485         ap.ExplX:= EX;
   484         ap.ExplY:= EY;
   486         ap.ExplY:= EY;
   516         repeat
   518         repeat
   517             x:= x + Vx;
   519             x:= x + Vx;
   518             y:= y + dY;
   520             y:= y + dY;
   519             dY:= dY + cGravityf;
   521             dY:= dY + cGravityf;
   520             dec(t)
   522             dec(t)
   521        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or 
   523        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or
   522                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 6))) or (t = 0);
   524                ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 6))) or (t = 0);
   523         
   525 
   524         EX:= trunc(x);
   526         EX:= trunc(x);
   525         EY:= trunc(y);
   527         EY:= trunc(y);
   526         if t < 50 then 
   528         if t < 50 then
   527             Score:= RateExplosion(Me, EX, EY, 200) + RateExplosion(Me, EX, EY + 120, 200)
   529             Score:= RateExplosion(Me, EX, EY, 200) + RateExplosion(Me, EX, EY + 120, 200)
   528         else 
   530         else
   529             Score:= BadTurn;
   531             Score:= BadTurn;
   530             
   532 
   531         if valueResult < Score then
   533         if valueResult < Score then
   532             begin
   534             begin
   533             ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
   535             ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
   534             ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
   536             ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
   535             ap.Time:= TestTime div 1000 * 1000;
   537             ap.Time:= TestTime div 1000 * 1000;
   562             Solve:= trunc(T)
   564             Solve:= trunc(T)
   563             end
   565             end
   564             else
   566             else
   565                 Solve:= 0
   567                 Solve:= 0
   566     end;
   568     end;
   567     
   569 
   568 function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   570 function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   569 //const tDelta = 24;
   571 //const tDelta = 24;
   570 var Vx, Vy: real;
   572 var Vx, Vy: real;
   571     Score, EX, EY: LongInt;
   573     Score, EX, EY: LongInt;
   572     TestTime: Longword;
   574     TestTime: Longword;
   597         x:= x + Vx;
   599         x:= x + Vx;
   598         y:= y + dY;
   600         y:= y + dY;
   599         dY:= dY + cGravityf;
   601         dY:= dY + cGravityf;
   600         EX:= trunc(x);
   602         EX:= trunc(x);
   601         EY:= trunc(y);
   603         EY:= trunc(y);
   602     until (((Me = CurrentHedgehog^.Gear) and TestColl(EX, EY, 4)) or 
   604     until (((Me = CurrentHedgehog^.Gear) and TestColl(EX, EY, 4)) or
   603            ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, EX, EY, 4))) or (EY > cWaterLine);
   605            ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, EX, EY, 4))) or (EY > cWaterLine);
   604 
   606 
   605     if (EY < cWaterLine) and (dY >= 0) then
   607     if (EY < cWaterLine) and (dY >= 0) then
   606         begin
   608         begin
   607         Score:= RateExplosion(Me, EX, EY, 91);
   609         Score:= RateExplosion(Me, EX, EY, 91);
   608         if (Score = 0) then
   610         if (Score = 0) then
   651 repeat
   653 repeat
   652     x:= x + vX;
   654     x:= x + vX;
   653     y:= y + vY;
   655     y:= y + vY;
   654     rx:= trunc(x);
   656     rx:= trunc(x);
   655     ry:= trunc(y);
   657     ry:= trunc(y);
   656     if ((Me = CurrentHedgehog^.Gear) and TestColl(rx, ry, 2)) or 
   658     if ((Me = CurrentHedgehog^.Gear) and TestColl(rx, ry, 2)) or
   657         ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, rx, ry, 2)) then
   659         ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, rx, ry, 2)) then
   658     begin
   660     begin
   659         x:= x + vX * 8;
   661         x:= x + vX * 8;
   660         y:= y + vY * 8;
   662         y:= y + vY * 8;
   661         valueResult:= RateShotgun(Me, vX, vY, rx, ry);
   663         valueResult:= RateShotgun(Me, vX, vY, rx, ry);
   662      
   664 
   663         if valueResult = 0 then 
   665         if valueResult = 0 then
   664             valueResult:= 1024 - Metric(Targ.X, Targ.Y, rx, ry) div 64
   666             valueResult:= 1024 - Metric(Targ.X, Targ.Y, rx, ry) div 64
   665         else 
   667         else
   666             dec(valueResult, Level * 4000);
   668             dec(valueResult, Level * 4000);
   667         // 27/20 is reuse bonus
   669         // 27/20 is reuse bonus
   668         exit(valueResult * 27 div 20)
   670         exit(valueResult * 27 div 20)
   669     end
   671     end
   670 until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 4)
   672 until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 4)
   766 if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 4 then
   768 if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 4 then
   767     begin
   769     begin
   768     fallDmg:= TraceShoveFall(Targ.X, Targ.Y, vX * 0.00166 * dmg, vY * 0.00166 * dmg);
   770     fallDmg:= TraceShoveFall(Targ.X, Targ.Y, vX * 0.00166 * dmg, vY * 0.00166 * dmg);
   769     if fallDmg < 0 then
   771     if fallDmg < 0 then
   770         TestSniperRifle:= BadTurn
   772         TestSniperRifle:= BadTurn
   771     else 
   773     else
   772         TestSniperRifle:= Max(0, trunc((dmg + fallDmg) * dmgMod) * 1024)
   774         TestSniperRifle:= Max(0, trunc((dmg + fallDmg) * dmgMod) * 1024)
   773     end
   775     end
   774 else
   776 else
   775     TestSniperRifle:= BadTurn
   777     TestSniperRifle:= BadTurn
   776 end;
   778 end;
   805                 , -dx, -dy, trackFall);
   807                 , -dx, -dy, trackFall);
   806         v2:= RateShove(x + 10, y + 2
   808         v2:= RateShove(x + 10, y + 2
   807                 , 32, 30, 115
   809                 , 32, 30, 115
   808                 , dx, -dy, trackFall);
   810                 , dx, -dy, trackFall);
   809         if (v1 > valueResult) or (v2 > valueResult) then
   811         if (v1 > valueResult) or (v2 > valueResult) then
   810             if (v2 > v1) 
   812             if (v2 > v1)
   811                 or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
   813                 or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
   812                 begin
   814                 begin
   813                 ap.Angle:= a;
   815                 ap.Angle:= a;
   814                 valueResult:= v2
   816                 valueResult:= v2
   815                 end
   817                 end
   816             else 
   818             else
   817                 begin
   819                 begin
   818                 ap.Angle:= -a;
   820                 ap.Angle:= -a;
   819                 valueResult:= v1
   821                 valueResult:= v1
   820                 end;
   822                 end;
   821 
   823 
   822         a:= a - 15 - random(cMaxAngle div 16)
   824         a:= a - 15 - random(cMaxAngle div 16)
   823         end;
   825         end;
   824    
   826 
   825     if valueResult <= 0 then
   827     if valueResult <= 0 then
   826         valueResult:= BadTurn;
   828         valueResult:= BadTurn;
   827 
   829 
   828     TestBaseballBat:= valueResult;
   830     TestBaseballBat:= valueResult;
   829 end;
   831 end;
   865         end;
   867         end;
   866     v2:= v2 + RateShove(x + 5, y - 90
   868     v2:= v2 + RateShove(x + 5, y - 90
   867             , 19, 30, 40
   869             , 19, 30, 40
   868             , 0.45, -0.9, trackFall);
   870             , 0.45, -0.9, trackFall);
   869 
   871 
   870     if (v2 > v1) 
   872     if (v2 > v1)
   871         or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
   873         or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
   872         begin
   874         begin
   873         ap.Angle:= 1;
   875         ap.Angle:= 1;
   874         valueResult:= v2
   876         valueResult:= v2
   875         end
   877         end
   876     else 
   878     else
   877         begin
   879         begin
   878         ap.Angle:= -1;
   880         ap.Angle:= -1;
   879         valueResult:= v1
   881         valueResult:= v1
   880         end;
   882         end;
   881     
   883 
   882     if valueResult <= 0 then
   884     if valueResult <= 0 then
   883         valueResult:= BadTurn;
   885         valueResult:= BadTurn;
   884 
   886 
   885     TestFirePunch:= valueResult;
   887     TestFirePunch:= valueResult;
   886 end;
   888 end;
   900     ap.Power:= 1;
   902     ap.Power:= 1;
   901     x:= hwRound(Me^.X);
   903     x:= hwRound(Me^.X);
   902     y:= hwRound(Me^.Y);
   904     y:= hwRound(Me^.Y);
   903 
   905 
   904     // check left direction
   906     // check left direction
   905     {first RateShove checks farthermost of two whip's AmmoShove attacks 
   907     {first RateShove checks farthermost of two whip's AmmoShove attacks
   906     to encourage distant attacks (damaged hog is excluded from view of second 
   908     to encourage distant attacks (damaged hog is excluded from view of second
   907     RateShove call)}
   909     RateShove call)}
   908     v1:= RateShove(x - 13, y
   910     v1:= RateShove(x - 13, y
   909             , 30, 30, 25
   911             , 30, 30, 25
   910             , -1, -0.8, trackFall or afSetSkip);
   912             , -1, -0.8, trackFall or afSetSkip);
   911     v1:= v1 +
   913     v1:= v1 +
   919     v2:= v2 +
   921     v2:= v2 +
   920         RateShove(x + 2, y
   922         RateShove(x + 2, y
   921             , 30, 30, 25
   923             , 30, 30, 25
   922             , 1, -0.8, trackFall);
   924             , 1, -0.8, trackFall);
   923 
   925 
   924     if (v2 > v1) 
   926     if (v2 > v1)
   925         or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
   927         or {don't encourage turning for no gain}((v2 = v1) and (not Me^.dX.isNegative)) then
   926         begin
   928         begin
   927         ap.Angle:= 1;
   929         ap.Angle:= 1;
   928         valueResult:= v2
   930         valueResult:= v2
   929         end
   931         end
   930     else 
   932     else
   931         begin
   933         begin
   932         ap.Angle:= -1;
   934         ap.Angle:= -1;
   933         valueResult:= v1
   935         valueResult:= v1
   934         end;
   936         end;
   935     
   937 
   936     if valueResult <= 0 then
   938     if valueResult <= 0 then
   937         valueResult:= BadTurn
   939         valueResult:= BadTurn
   938     else
   940     else
   939         inc(valueResult);
   941         inc(valueResult);
   940 
   942 
   949 begin
   951 begin
   950     ap.ExplR:= 0;
   952     ap.ExplR:= 0;
   951     ap.Time:= 0;
   953     ap.Time:= 0;
   952     ap.Power:= 1;
   954     ap.Power:= 1;
   953 
   955 
   954     if Level = 1 then 
   956     if Level = 1 then
   955         trackFall:= afTrackFall
   957         trackFall:= afTrackFall
   956     else if Level = 2 then
   958     else if Level = 2 then
   957         trackFall:= 0
   959         trackFall:= 0
   958     else
   960     else
   959         exit(BadTurn);
   961         exit(BadTurn);
   960         
   962 
   961     valueResult:= 0;
   963     valueResult:= 0;
   962     v:= 0;
   964     v:= 0;
   963 
   965 
   964     x:= hwFloat2Float(Me^.X);
   966     x:= hwFloat2Float(Me^.X);
   965     y:= hwFloat2Float(Me^.Y);
   967     y:= hwFloat2Float(Me^.Y);
   976         dx:= (Targ.X - x) * t;
   978         dx:= (Targ.X - x) * t;
   977         dy:= (Targ.Y - y) * t;
   979         dy:= (Targ.Y - y) * t;
   978 
   980 
   979         ap.Angle:= DxDy2AttackAnglef(dx, -dy)
   981         ap.Angle:= DxDy2AttackAnglef(dx, -dy)
   980         end;
   982         end;
   981     
   983 
   982     if dx >= 0 then cx:= 0.45 else cx:= -0.45;
   984     if dx >= 0 then cx:= 0.45 else cx:= -0.45;
   983 
   985 
   984     for i:= 0 to 512 div step - 2 do
   986     for i:= 0 to 512 div step - 2 do
   985         begin
   987         begin
   986         valueResult:= valueResult + 
   988         valueResult:= valueResult +
   987             RateShove(trunc(x), trunc(y)
   989             RateShove(trunc(x), trunc(y)
   988                 , 30, 30, 25
   990                 , 30, 30, 25
   989                 , cx, -0.9, trackFall or afSetSkip);
   991                 , cx, -0.9, trackFall or afSetSkip);
   990                 
   992 
   991         x:= x + dx;
   993         x:= x + dx;
   992         y:= y + dy;
   994         y:= y + dy;
   993         end;
   995         end;
   994     if dx = 0 then
   996     if dx = 0 then
   995         begin
   997         begin
  1000                 , 30, 30, 25
  1002                 , 30, 30, 25
  1001                 , -cx, -0.9, trackFall);
  1003                 , -cx, -0.9, trackFall);
  1002         for i:= 1 to 512 div step - 2 do
  1004         for i:= 1 to 512 div step - 2 do
  1003             begin
  1005             begin
  1004             y:= y + dy;
  1006             y:= y + dy;
  1005             v:= v + 
  1007             v:= v +
  1006                 RateShove(tx, trunc(y)
  1008                 RateShove(tx, trunc(y)
  1007                     , 30, 30, 25
  1009                     , 30, 30, 25
  1008                     , -cx, -0.9, trackFall or afSetSkip);
  1010                     , -cx, -0.9, trackFall or afSetSkip);
  1009             end
  1011             end
  1010         end;
  1012         end;
  1033 
  1035 
  1034 ap.ExplR:= 0;
  1036 ap.ExplR:= 0;
  1035 ap.Time:= 0;
  1037 ap.Time:= 0;
  1036 ap.Power:= 1;
  1038 ap.Power:= 1;
  1037 ap.Angle:= 0;
  1039 ap.Angle:= 0;
  1038          
  1040 
  1039 rate:= RateHammer(Me);
  1041 rate:= RateHammer(Me);
  1040 if rate = 0 then
  1042 if rate = 0 then
  1041     rate:= BadTurn;
  1043     rate:= BadTurn;
  1042 TestHammer:= rate;
  1044 TestHammer:= rate;
  1043 end;
  1045 end;
  1124     if bonuses.Count = 0 then
  1126     if bonuses.Count = 0 then
  1125         begin
  1127         begin
  1126         if Me^.Health <= 100  then
  1128         if Me^.Health <= 100  then
  1127             begin
  1129             begin
  1128             maxTop := Targ.Y - cHHRadius * 2;
  1130             maxTop := Targ.Y - cHHRadius * 2;
  1129             
  1131 
  1130             while not TestColl(Targ.X, maxTop, cHHRadius) and (maxTop > topY + cHHRadius * 2 + 1) do
  1132             while not TestColl(Targ.X, maxTop, cHHRadius) and (maxTop > topY + cHHRadius * 2 + 1) do
  1131                 dec(maxTop, cHHRadius*2);
  1133                 dec(maxTop, cHHRadius*2);
  1132             if not TestColl(Targ.X, maxTop + cHHRadius, cHHRadius) then
  1134             if not TestColl(Targ.X, maxTop + cHHRadius, cHHRadius) then
  1133                 begin
  1135                 begin
  1134                 ap.AttackPutX := Targ.X;
  1136                 ap.AttackPutX := Targ.X;
  1143         repeat
  1145         repeat
  1144             i := random(bonuses.Count);
  1146             i := random(bonuses.Count);
  1145             inc(failNum);
  1147             inc(failNum);
  1146         until not TestColl(bonuses.ar[i].X, bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius, cHHRadius)
  1148         until not TestColl(bonuses.ar[i].X, bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius, cHHRadius)
  1147         or (failNum = bonuses.Count*2);
  1149         or (failNum = bonuses.Count*2);
  1148         
  1150 
  1149         if failNum < bonuses.Count*2 then
  1151         if failNum < bonuses.Count*2 then
  1150             begin
  1152             begin
  1151             ap.AttackPutX := bonuses.ar[i].X;
  1153             ap.AttackPutX := bonuses.ar[i].X;
  1152             ap.AttackPutY := bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius;
  1154             ap.AttackPutY := bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius;
  1153             TestTeleport := 0;
  1155             TestTeleport := 0;
  1165 
  1167 
  1166 for i:= 0 to 2040 do
  1168 for i:= 0 to 2040 do
  1167     begin
  1169     begin
  1168     cakeStep(Gear);
  1170     cakeStep(Gear);
  1169     v:= RateExplosion(Me, hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg * 2, afTrackFall);
  1171     v:= RateExplosion(Me, hwRound(Gear^.X), hwRound(Gear^.Y), cakeDmg * 2, afTrackFall);
  1170     if v > ap.Power then 
  1172     if v > ap.Power then
  1171         begin
  1173         begin
  1172         ap.ExplX:= hwRound(Gear^.X);
  1174         ap.ExplX:= hwRound(Gear^.X);
  1173         ap.ExplY:= hwRound(Gear^.Y);
  1175         ap.ExplY:= hwRound(Gear^.Y);
  1174         ap.Power:= v
  1176         ap.Power:= v
  1175         end
  1177         end