hedgewars/uAIAmmoTests.pas
changeset 6580 6155187bf599
parent 6474 42e9773eedfd
child 6700 e04da46ee43c
equal deleted inserted replaced
6579:fc52f7c22c9b 6580:6155187bf599
    22 interface
    22 interface
    23 uses SDLh, uConsts, uFloat, uTypes;
    23 uses SDLh, uConsts, uFloat, uTypes;
    24 const amtest_OnTurn = $00000001;
    24 const amtest_OnTurn = $00000001;
    25 
    25 
    26 type TAttackParams = record
    26 type TAttackParams = record
    27             Time: Longword;
    27         Time: Longword;
    28             Angle, Power: LongInt;
    28         Angle, Power: LongInt;
    29             ExplX, ExplY, ExplR: LongInt;
    29         ExplX, ExplY, ExplR: LongInt;
    30             AttackPutX, AttackPutY: LongInt;
    30         AttackPutX, AttackPutY: LongInt;
    31             end;
    31         end;
    32 
    32 
    33 function TestBazooka(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
    33 function TestBazooka(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
    34 function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
    34 function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
    35 function TestGrenade(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
    35 function TestGrenade(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
    36 function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
    36 function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   135 ap.Time:= 0;
   135 ap.Time:= 0;
   136 rTime:= 350;
   136 rTime:= 350;
   137 ap.ExplR:= 0;
   137 ap.ExplR:= 0;
   138 valueResult:= BadTurn;
   138 valueResult:= BadTurn;
   139 repeat
   139 repeat
   140   rTime:= rTime + 300 + Level * 50 + random(300);
   140     rTime:= rTime + 300 + Level * 50 + random(300);
   141   Vx:= - cWindSpeedf * rTime * 0.5 + (Targ.X + AIrndSign(2) - mX) / rTime;
   141     Vx:= - cWindSpeedf * rTime * 0.5 + (Targ.X + AIrndSign(2) - mX) / rTime;
   142   Vy:= cGravityf * rTime * 0.5 - (Targ.Y - mY) / rTime;
   142     Vy:= cGravityf * rTime * 0.5 - (Targ.Y - mY) / rTime;
   143   r:= sqrt(sqr(Vx) + sqr(Vy));
   143     r:= sqrt(sqr(Vx) + sqr(Vy));
   144   if not (r > 1) then
   144     if not (r > 1) then
   145      begin
   145         begin
   146         x:= mX;
   146         x:= mX;
   147         y:= mY;
   147         y:= mY;
   148         dX:= Vx;
   148         dX:= Vx;
   149         dY:= -Vy;
   149         dY:= -Vy;
   150         t:= rTime;
   150         t:= rTime;
   151         repeat
   151         repeat
   152               x:= x + dX;
   152             x:= x + dX;
   153               y:= y + dY;
   153             y:= y + dY;
   154               dX:= dX + cWindSpeedf;
   154             dX:= dX + cWindSpeedf;
   155               dY:= dY + cGravityf;
   155             dY:= dY + cGravityf;
   156               dec(t)
   156             dec(t)
   157         until TestCollExcludingMe(Me, trunc(x), trunc(y), 5) or (t <= 0);
   157         until TestCollExcludingMe(Me, trunc(x), trunc(y), 5) or (t <= 0);
       
   158         
   158         EX:= trunc(x);
   159         EX:= trunc(x);
   159         EY:= trunc(y);
   160         EY:= trunc(y);
   160         value:= RateExplosion(Me, EX, EY, 101);
   161         value:= RateExplosion(Me, EX, EY, 101);
   161         if value = 0 then value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
   162         if value = 0 then
   162      if valueResult <= value then
   163             value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
       
   164     if valueResult <= value then
   163         begin
   165         begin
   164         ap.Angle:= DxDy2AttackAngle(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
   166         ap.Angle:= DxDy2AttackAngle(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
   165         ap.Power:= trunc(r * cMaxPower) - random((Level - 1) * 17 + 1);
   167         ap.Power:= trunc(r * cMaxPower) - random((Level - 1) * 17 + 1);
   166         ap.ExplR:= 100;
   168         ap.ExplR:= 100;
   167         ap.ExplX:= EX;
   169         ap.ExplX:= EX;
   168         ap.ExplY:= EY;
   170         ap.ExplY:= EY;
   169         valueResult:= value
   171         valueResult:= value
   170         end;
   172         end;
   171      end
   173     end
   172 until (rTime > 4250);
   174 until (rTime > 4250);
   173 TestBazooka:= valueResult
   175 TestBazooka:= valueResult
   174 end;
   176 end;
   175 
   177 
   176 function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   178 function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   186 ap.Time:= 0;
   188 ap.Time:= 0;
   187 rTime:= 350;
   189 rTime:= 350;
   188 ap.ExplR:= 0;
   190 ap.ExplR:= 0;
   189 valueResult:= BadTurn;
   191 valueResult:= BadTurn;
   190 repeat
   192 repeat
   191   rTime:= rTime + 300 + Level * 50 + random(300);
   193     rTime:= rTime + 300 + Level * 50 + random(300);
   192   Vx:= - cWindSpeed * rTime * _0_5 + (int2hwFloat(Targ.X + AIrndSign(2)) - Me^.X) / int2hwFloat(rTime);
   194     Vx:= - cWindSpeed * rTime * _0_5 + (int2hwFloat(Targ.X + AIrndSign(2)) - Me^.X) / int2hwFloat(rTime);
   193   Vy:= cGravity * rTime * _0_5 - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(rTime);
   195     Vy:= cGravity * rTime * _0_5 - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(rTime);
   194   r:= Distance(Vx, Vy);
   196     r:= Distance(Vx, Vy);
   195   if not (r > _1) then
   197     if not (r > _1) then
   196      begin
   198         begin
   197         x:= Me^.X;
   199         x:= Me^.X;
   198         y:= Me^.Y;
   200         y:= Me^.Y;
   199         dX:= Vx;
   201         dX:= Vx;
   200         dY:= -Vy;
   202         dY:= -Vy;
   201         t:= rTime;
   203         t:= rTime;
   202         repeat
   204         repeat
   203           x:= x + dX;
   205             x:= x + dX;
   204           y:= y + dY;
   206             y:= y + dY;
   205           dX:= dX + cWindSpeed;
   207             dX:= dX + cWindSpeed;
   206           dY:= dY + cGravity;
   208             dY:= dY + cGravity;
   207           dec(t)
   209             dec(t)
   208         until TestCollExcludingMe(Me, hwRound(x), hwRound(y), 5) or (t <= 0);
   210         until TestCollExcludingMe(Me, hwRound(x), hwRound(y), 5) or (t <= 0);
   209         EX:= hwRound(x);
   211         EX:= hwRound(x);
   210         EY:= hwRound(y);
   212         EY:= hwRound(y);
   211         value:= RateExplosion(Me, EX, EY, 5);
   213         value:= RateExplosion(Me, EX, EY, 5);
   212         if value = 0 then value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
   214         if value = 0 then
       
   215             value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
   213 
   216 
   214         if valueResult <= value then
   217         if valueResult <= value then
   215             begin
   218             begin
   216             ap.Angle:= DxDy2AttackAngle(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
   219             ap.Angle:= DxDy2AttackAngle(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
   217             ap.Power:= hwRound(r * cMaxPower) - random((Level - 1) * 17 + 1);
   220             ap.Power:= hwRound(r * cMaxPower) - random((Level - 1) * 17 + 1);
   234 begin
   237 begin
   235 valueResult:= BadTurn;
   238 valueResult:= BadTurn;
   236 TestTime:= 0;
   239 TestTime:= 0;
   237 ap.ExplR:= 0;
   240 ap.ExplR:= 0;
   238 repeat
   241 repeat
   239   inc(TestTime, 300);
   242     inc(TestTime, 300);
   240   Vx:= (int2hwFloat(Targ.X) - Me^.X) / int2hwFloat(TestTime);
   243     Vx:= (int2hwFloat(Targ.X) - Me^.X) / int2hwFloat(TestTime);
   241   Vy:= cGravity * (TestTime div 2) - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(TestTime);
   244     Vy:= cGravity * (TestTime div 2) - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(TestTime);
   242   r:= Distance(Vx, Vy);
   245     r:= Distance(Vx, Vy);
   243   if not (r > _1) then
   246     if not (r > _1) then
   244      begin
   247         begin
   245         x:= Me^.X;
   248         x:= Me^.X;
   246         y:= Me^.Y;
   249         y:= Me^.Y;
   247         dY:= -Vy;
   250         dY:= -Vy;
   248         t:= TestTime;
   251         t:= TestTime;
   249         repeat
   252         repeat
   250           x:= x + Vx;
   253             x:= x + Vx;
   251           y:= y + dY;
   254             y:= y + dY;
   252           dY:= dY + cGravity;
   255             dY:= dY + cGravity;
   253           dec(t)
   256             dec(t)
   254         until TestCollExcludingMe(Me, hwRound(x), hwRound(y), 7) or (t = 0);
   257         until TestCollExcludingMe(Me, hwRound(x), hwRound(y), 7) or (t = 0);
   255         EX:= hwRound(x);
   258         EX:= hwRound(x);
   256         EY:= hwRound(y);
   259         EY:= hwRound(y);
   257         if t < 50 then Score:= RateExplosion(Me, EX, EY, 97)  // average of 17 attempts, most good, but some failing spectacularly
   260         if t < 50 then
   258                   else Score:= BadTurn;
   261             Score:= RateExplosion(Me, EX, EY, 97)  // average of 17 attempts, most good, but some failing spectacularly
       
   262         else
       
   263             Score:= BadTurn;
   259                   
   264                   
   260         if valueResult < Score then
   265         if valueResult < Score then
   261             begin
   266             begin
   262             ap.Angle:= DxDy2AttackAngle(Vx, Vy) + AIrndSign(random(Level));
   267             ap.Angle:= DxDy2AttackAngle(Vx, Vy) + AIrndSign(random(Level));
   263             ap.Power:= hwRound(r * cMaxPower) + AIrndSign(random(Level) * 15);
   268             ap.Power:= hwRound(r * cMaxPower) + AIrndSign(random(Level) * 15);
   265             ap.ExplR:= 100;
   270             ap.ExplR:= 100;
   266             ap.ExplX:= EX;
   271             ap.ExplX:= EX;
   267             ap.ExplY:= EY;
   272             ap.ExplY:= EY;
   268             valueResult:= Score
   273             valueResult:= Score
   269             end;
   274             end;
   270      end
   275         end
   271 until (TestTime > 4250);
   276 until (TestTime > 4250);
   272 TestMolotov:= valueResult
   277 TestMolotov:= valueResult
   273 end;
   278 end;
   274 
   279 
   275 function TestGrenade(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   280 function TestGrenade(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   282 begin
   287 begin
   283 valueResult:= BadTurn;
   288 valueResult:= BadTurn;
   284 TestTime:= 0;
   289 TestTime:= 0;
   285 ap.ExplR:= 0;
   290 ap.ExplR:= 0;
   286 repeat
   291 repeat
   287   inc(TestTime, 1000);
   292     inc(TestTime, 1000);
   288   Vx:= (int2hwFloat(Targ.X) - Me^.X) / int2hwFloat(TestTime + tDelta);
   293     Vx:= (int2hwFloat(Targ.X) - Me^.X) / int2hwFloat(TestTime + tDelta);
   289   Vy:= cGravity * ((TestTime + tDelta) div 2) - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(TestTime + tDelta);
   294     Vy:= cGravity * ((TestTime + tDelta) div 2) - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(TestTime + tDelta);
   290   r:= Distance(Vx, Vy);
   295     r:= Distance(Vx, Vy);
   291   if not (r > _1) then
   296     if not (r > _1) then
   292     begin
   297         begin
   293     x:= Me^.X;
   298         x:= Me^.X;
   294     y:= Me^.Y;
   299         y:= Me^.Y;
   295     dY:= -Vy;
   300         dY:= -Vy;
   296     t:= TestTime;
   301         t:= TestTime;
   297     repeat
   302         repeat
   298         x:= x + Vx;
   303             x:= x + Vx;
   299         y:= y + dY;
   304             y:= y + dY;
   300         dY:= dY + cGravity;
   305             dY:= dY + cGravity;
   301         dec(t)
   306             dec(t)
   302     until TestCollExcludingMe(Me, hwRound(x), hwRound(y), 5) or (t = 0);
   307         until TestCollExcludingMe(Me, hwRound(x), hwRound(y), 5) or (t = 0);
   303     EX:= hwRound(x);
   308     EX:= hwRound(x);
   304     EY:= hwRound(y);
   309     EY:= hwRound(y);
   305     if t < 50 then 
   310     if t < 50 then 
   306         Score:= RateExplosion(Me, EX, EY, 101)
   311         Score:= RateExplosion(Me, EX, EY, 101)
   307     else 
   312     else 
   332 begin
   337 begin
   333 valueResult:= BadTurn;
   338 valueResult:= BadTurn;
   334 TestTime:= 0;
   339 TestTime:= 0;
   335 ap.ExplR:= 0;
   340 ap.ExplR:= 0;
   336 repeat
   341 repeat
   337   inc(TestTime, 1000);
   342     inc(TestTime, 1000);
   338   // Try to overshoot slightly, seems to pay slightly better dividends in terms of hitting cluster
   343     // Try to overshoot slightly, seems to pay slightly better dividends in terms of hitting cluster
   339   if Me^.X<int2hwFloat(Targ.X) then
   344     if Me^.X<int2hwFloat(Targ.X) then
   340       Vx:= (int2hwFloat(Targ.X+10) - Me^.X) / int2hwFloat(TestTime + tDelta)
   345         Vx:= (int2hwFloat(Targ.X+10) - Me^.X) / int2hwFloat(TestTime + tDelta)
   341   else
   346     else
   342       Vx:= (int2hwFloat(Targ.X-10) - Me^.X) / int2hwFloat(TestTime + tDelta);
   347         Vx:= (int2hwFloat(Targ.X-10) - Me^.X) / int2hwFloat(TestTime + tDelta);
   343   Vy:= cGravity * ((TestTime + tDelta) div 2) - (int2hwFloat(Targ.Y-150) - Me^.Y) / int2hwFloat(TestTime + tDelta);
   348     Vy:= cGravity * ((TestTime + tDelta) div 2) - (int2hwFloat(Targ.Y-150) - Me^.Y) / int2hwFloat(TestTime + tDelta);
   344   r:= Distance(Vx, Vy);
   349     r:= Distance(Vx, Vy);
   345   if not (r > _1) then
   350     if not (r > _1) then
   346      begin
   351         begin
   347     x:= Me^.X;
   352         x:= Me^.X;
   348     y:= Me^.Y;
   353         y:= Me^.Y;
   349     dY:= -Vy;
   354         dY:= -Vy;
   350     t:= TestTime;
   355         t:= TestTime;
   351     repeat
   356     repeat
   352         x:= x + Vx;
   357         x:= x + Vx;
   353         y:= y + dY;
   358         y:= y + dY;
   354         dY:= dY + cGravity;
   359         dY:= dY + cGravity;
   355         dec(t)
   360         dec(t)
   386 begin
   391 begin
   387 valueResult:= BadTurn;
   392 valueResult:= BadTurn;
   388 TestTime:= 0;
   393 TestTime:= 0;
   389 ap.ExplR:= 0;
   394 ap.ExplR:= 0;
   390 repeat
   395 repeat
   391   inc(TestTime, 1000);
   396     inc(TestTime, 1000);
   392   Vx:= (int2hwFloat(Targ.X) - Me^.X) / int2hwFloat(TestTime + tDelta);
   397     Vx:= (int2hwFloat(Targ.X) - Me^.X) / int2hwFloat(TestTime + tDelta);
   393   Vy:= cGravity * ((TestTime + tDelta) div 2) - (int2hwFloat(Targ.Y-200) - Me^.Y) / int2hwFloat(TestTime + tDelta);
   398     Vy:= cGravity * ((TestTime + tDelta) div 2) - (int2hwFloat(Targ.Y-200) - Me^.Y) / int2hwFloat(TestTime + tDelta);
   394   r:= Distance(Vx, Vy);
   399     r:= Distance(Vx, Vy);
   395   if not (r > _1) then
   400     if not (r > _1) then
   396     begin
   401         begin
   397     x:= Me^.X;
   402         x:= Me^.X;
   398     y:= Me^.Y;
   403         y:= Me^.Y;
   399     dY:= -Vy;
   404         dY:= -Vy;
   400     t:= TestTime;
   405         t:= TestTime;
   401     repeat
   406     repeat
   402         x:= x + Vx;
   407         x:= x + Vx;
   403         y:= y + dY;
   408         y:= y + dY;
   404         dY:= dY + cGravity;
   409         dY:= dY + cGravity;
   405         dec(t)
   410         dec(t)
   441             if D.isNegative = false then
   446             if D.isNegative = false then
   442                 T:= hwSqrt(D)
   447                 T:= hwSqrt(D)
   443             else
   448             else
   444                 T:= _0;
   449                 T:= _0;
   445             Solve:= hwRound(T)
   450             Solve:= hwRound(T)
   446             end else Solve:= 0
   451             end
       
   452             else
       
   453                 Solve:= 0
   447     end;
   454     end;
   448     
   455     
   449 function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   456 function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   450 //const tDelta = 24;
   457 //const tDelta = 24;
   451 var Vx, Vy: hwFloat;
   458 var Vx, Vy: hwFloat;
   454     x, y, dY: hwFloat;
   461     x, y, dY: hwFloat;
   455 begin
   462 begin
   456 valueResult:= BadTurn;
   463 valueResult:= BadTurn;
   457 ap.ExplR:= 0;
   464 ap.ExplR:= 0;
   458 
   465 
   459 if (Level > 2) then exit(BadTurn);
   466 if (Level > 2) then
       
   467     exit(BadTurn);
   460 
   468 
   461 TestTime:= Solve(Targ.X, Targ.Y, hwRound(Me^.X), hwRound(Me^.Y));
   469 TestTime:= Solve(Targ.X, Targ.Y, hwRound(Me^.X), hwRound(Me^.Y));
   462 
   470 
   463 if TestTime = 0 then exit(BadTurn);
   471 if TestTime = 0 then
       
   472     exit(BadTurn);
   464 
   473 
   465     Vx:= (int2hwFloat(Targ.X) - Me^.X) / int2hwFloat(TestTime);
   474     Vx:= (int2hwFloat(Targ.X) - Me^.X) / int2hwFloat(TestTime);
   466     Vy:= cGravity * (TestTime div 2) - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(TestTime);
   475     Vy:= cGravity * (TestTime div 2) - (int2hwFloat(Targ.Y) - Me^.Y) / int2hwFloat(TestTime);
   467 
   476 
   468     x:= Me^.X;
   477     x:= Me^.X;
   483         if (Score = 0) then
   492         if (Score = 0) then
   484             if (dY > _0_15) then
   493             if (dY > _0_15) then
   485                 Score:= - abs(Targ.Y - EY) div 32
   494                 Score:= - abs(Targ.Y - EY) div 32
   486             else
   495             else
   487                 Score:= BadTurn
   496                 Score:= BadTurn
   488         else if (Score < 0) then Score:= BadTurn
   497         else if (Score < 0) then
       
   498             Score:= BadTurn
   489         end
   499         end
   490     else
   500     else
   491         Score:= BadTurn;
   501         Score:= BadTurn;
   492 
   502 
   493     if valueResult < Score then
   503     if valueResult < Score then
   503 TestMortar:= valueResult;
   513 TestMortar:= valueResult;
   504 end;
   514 end;
   505 
   515 
   506 function TestShotgun(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   516 function TestShotgun(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   507 const
   517 const
   508   MIN_RANGE =  80;
   518     MIN_RANGE =  80;
   509   MAX_RANGE = 400;
   519     MAX_RANGE = 400;
   510 var Vx, Vy, x, y: hwFloat;
   520 var Vx, Vy, x, y: hwFloat;
   511     rx, ry, valueResult: LongInt;
   521     rx, ry, valueResult: LongInt;
   512     range: integer;
   522     range: integer;
   513 begin
   523 begin
   514 ap.ExplR:= 0;
   524 ap.ExplR:= 0;
   515 ap.Time:= 0;
   525 ap.Time:= 0;
   516 ap.Power:= 1;
   526 ap.Power:= 1;
   517 x:= Me^.X;
   527 x:= Me^.X;
   518 y:= Me^.Y;
   528 y:= Me^.Y;
   519 range:= Metric(hwRound(x), hwRound(y), Targ.X, Targ.Y);
   529 range:= Metric(hwRound(x), hwRound(y), Targ.X, Targ.Y);
   520 if ( range < MIN_RANGE ) or ( range > MAX_RANGE ) then exit(BadTurn);
   530 if ( range < MIN_RANGE ) or ( range > MAX_RANGE ) then
       
   531     exit(BadTurn);
   521 Vx:= (int2hwFloat(Targ.X) - x) * _1div1024;
   532 Vx:= (int2hwFloat(Targ.X) - x) * _1div1024;
   522 Vy:= (int2hwFloat(Targ.Y) - y) * _1div1024;
   533 Vy:= (int2hwFloat(Targ.Y) - y) * _1div1024;
   523 ap.Angle:= DxDy2AttackAngle(Vx, -Vy);
   534 ap.Angle:= DxDy2AttackAngle(Vx, -Vy);
   524 repeat
   535 repeat
   525   x:= x + vX;
   536     x:= x + vX;
   526   y:= y + vY;
   537     y:= y + vY;
   527   rx:= hwRound(x);
   538     rx:= hwRound(x);
   528   ry:= hwRound(y);
   539     ry:= hwRound(y);
   529   if TestCollExcludingMe(Me, rx, ry, 2) then
   540     if TestCollExcludingMe(Me, rx, ry, 2) then
   530      begin
   541         begin
   531      x:= x + vX * 8;
   542         x:= x + vX * 8;
   532      y:= y + vY * 8;
   543         y:= y + vY * 8;
   533      valueResult:= RateShotgun(Me, rx, ry);
   544         valueResult:= RateShotgun(Me, rx, ry);
   534      
   545      
   535      if valueResult = 0 then 
   546     if valueResult = 0 then 
   536         valueResult:= - Metric(Targ.X, Targ.Y, rx, ry) div 64
   547         valueResult:= - Metric(Targ.X, Targ.Y, rx, ry) div 64
   537         else 
   548     else 
   538         dec(valueResult, Level * 4000);
   549         dec(valueResult, Level * 4000);
   539      exit(valueResult * 27 div 20) // 27/20 is reuse bonus
   550     exit(valueResult * 27 div 20) // 27/20 is reuse bonus
   540      end
   551     end
   541 until (Abs(Targ.X - hwRound(x)) + Abs(Targ.Y - hwRound(y)) < 4)
   552 until (Abs(Targ.X - hwRound(x)) + Abs(Targ.Y - hwRound(y)) < 4)
   542     or (x.isNegative)
   553     or (x.isNegative)
   543     or (y.isNegative)
   554     or (y.isNegative)
   544     or (x.Round > LongWord(LAND_WIDTH))
   555     or (x.Round > LongWord(LAND_WIDTH))
   545     or (y.Round > LongWord(LAND_HEIGHT));
   556     or (y.Round > LongWord(LAND_HEIGHT));
   565 Vy:= (int2hwFloat(Targ.Y) - y) * t;
   576 Vy:= (int2hwFloat(Targ.Y) - y) * t;
   566 ap.Angle:= DxDy2AttackAngle(Vx, -Vy);
   577 ap.Angle:= DxDy2AttackAngle(Vx, -Vy);
   567 d:= 0;
   578 d:= 0;
   568 
   579 
   569 repeat
   580 repeat
   570   x:= x + vX;
   581     x:= x + vX;
   571   y:= y + vY;
   582     y:= y + vY;
   572   if ((hwRound(x) and LAND_WIDTH_MASK) = 0)and((hwRound(y) and LAND_HEIGHT_MASK) = 0)
   583     if ((hwRound(x) and LAND_WIDTH_MASK) = 0)and((hwRound(y) and LAND_HEIGHT_MASK) = 0)
   573      and (Land[hwRound(y), hwRound(x)] <> 0) then inc(d);
   584     and (Land[hwRound(y), hwRound(x)] <> 0) then
       
   585         inc(d);
   574 until (Abs(Targ.X - hwRound(x)) + Abs(Targ.Y - hwRound(y)) < 4)
   586 until (Abs(Targ.X - hwRound(x)) + Abs(Targ.Y - hwRound(y)) < 4)
   575     or (x.isNegative)
   587     or (x.isNegative)
   576     or (y.isNegative)
   588     or (y.isNegative)
   577     or (x.Round > LongWord(LAND_WIDTH))
   589     or (x.Round > LongWord(LAND_WIDTH))
   578     or (y.Round > LongWord(LAND_HEIGHT))
   590     or (y.Round > LongWord(LAND_HEIGHT))
   579     or (d > 200);
   591     or (d > 200);
   580 
   592 
   581 if Abs(Targ.X - hwRound(x)) + Abs(Targ.Y - hwRound(y)) < 3 then valueResult:= Max(0, (4 - d div 50) * 7 * 1024)
   593 if Abs(Targ.X - hwRound(x)) + Abs(Targ.Y - hwRound(y)) < 3 then
   582                                                            else valueResult:= BadTurn;
   594     valueResult:= Max(0, (4 - d div 50) * 7 * 1024)
       
   595 else
       
   596     valueResult:= BadTurn;
   583 TestDesertEagle:= valueResult
   597 TestDesertEagle:= valueResult
   584 end;
   598 end;
   585 
   599 
   586 function TestBaseballBat(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   600 function TestBaseballBat(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   587 var valueResult: LongInt;
   601 var valueResult: LongInt;
   588     x, y: hwFloat;
   602     x, y: hwFloat;
   589 begin
   603 begin
   590 Level:= Level; // avoid compiler hint
   604 Level:= Level; // avoid compiler hint
   591 ap.ExplR:= 0;
   605 ap.ExplR:= 0;
   592 if (Level > 2) or (Abs(hwRound(Me^.X) - Targ.X) + Abs(hwRound(Me^.Y) - Targ.Y) > 25) then
   606 if (Level > 2) or (Abs(hwRound(Me^.X) - Targ.X) + Abs(hwRound(Me^.Y) - Targ.Y) > 25) then
   593    exit(BadTurn);
   607     exit(BadTurn);
   594 
   608 
   595 ap.Time:= 0;
   609 ap.Time:= 0;
   596 ap.Power:= 1;
   610 ap.Power:= 1;
   597 x:= Me^.X;
   611 x:= Me^.X;
   598 y:= Me^.Y;
   612 y:= Me^.Y;
   599 if (Targ.X) - hwRound(x) >= 0 then ap.Angle:=   cMaxAngle div 4
   613 if (Targ.X) - hwRound(x) >= 0 then
   600                               else ap.Angle:= - cMaxAngle div 4;
   614     ap.Angle:=   cMaxAngle div 4
       
   615 else
       
   616     ap.Angle:= - cMaxAngle div 4;
   601 valueResult:= RateShove(Me, hwRound(x) + 10 * hwSign(int2hwFloat(Targ.X) - x), hwRound(y), 15, 30);
   617 valueResult:= RateShove(Me, hwRound(x) + 10 * hwSign(int2hwFloat(Targ.X) - x), hwRound(y), 15, 30);
   602 if valueResult <= 0 then valueResult:= BadTurn else inc(valueResult);
   618 if valueResult <= 0 then
       
   619     valueResult:= BadTurn
       
   620 else
       
   621     inc(valueResult);
   603 TestBaseballBat:= valueResult;
   622 TestBaseballBat:= valueResult;
   604 end;
   623 end;
   605 
   624 
   606 function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   625 function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   607 var i, valueResult: LongInt;
   626 var i, valueResult: LongInt;
   646 ap.Power:= 1;
   665 ap.Power:= 1;
   647 ap.Angle:= 0;
   666 ap.Angle:= 0;
   648          
   667          
   649 if (Abs(hwRound(Me^.X) + hwSign(Me^.dX) * 10 - Targ.X) + Abs(hwRound(Me^.Y) - Targ.Y) > 20) then
   668 if (Abs(hwRound(Me^.X) + hwSign(Me^.dX) * 10 - Targ.X) + Abs(hwRound(Me^.Y) - Targ.Y) > 20) then
   650     rate:= 0
   669     rate:= 0
   651     else
   670 else
   652     rate:= RateHammer(Me);
   671     rate:= RateHammer(Me);
   653 if rate = 0 then rate:= BadTurn;
   672 if rate = 0 then
       
   673     rate:= BadTurn;
   654 TestHammer:= rate;
   674 TestHammer:= rate;
   655 end;
   675 end;
   656 
   676 
   657 function TestAirAttack(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   677 function TestAirAttack(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   658 const cShift = 4;
   678 const cShift = 4;
   662     fexit: boolean;
   682     fexit: boolean;
   663     i, t, valueResult: LongInt;
   683     i, t, valueResult: LongInt;
   664 begin
   684 begin
   665 ap.ExplR:= 0;
   685 ap.ExplR:= 0;
   666 ap.Time:= 0;
   686 ap.Time:= 0;
   667 if (Level > 3) then exit(BadTurn);
   687 if (Level > 3) then
       
   688     exit(BadTurn);
   668 
   689 
   669 ap.AttackPutX:= Targ.X;
   690 ap.AttackPutX:= Targ.X;
   670 ap.AttackPutY:= Targ.Y;
   691 ap.AttackPutY:= Targ.Y;
   671 
   692 
   672 X:= int2hwFloat(Targ.X - 135 - cShift); // hh center - cShift
   693 X:= int2hwFloat(Targ.X - 135 - cShift); // hh center - cShift
   680     dmg[i]:= 0
   701     dmg[i]:= 0
   681     end;
   702     end;
   682 valueResult:= 0;
   703 valueResult:= 0;
   683 
   704 
   684 repeat
   705 repeat
   685   X:= X + cBombsSpeed;
   706     X:= X + cBombsSpeed;
   686   Y:= Y + dY;
   707     Y:= Y + dY;
   687   dY:= dY + cGravity;
   708     dY:= dY + cGravity;
   688   fexit:= true;
   709     fexit:= true;
   689 
   710 
   690   for i:= 0 to 9 do
   711     for i:= 0 to 9 do
   691     if b[i] then
   712         if b[i] then
   692        begin
   713             begin
   693        fexit:= false;
   714             fexit:= false;
   694        if TestColl(hwRound(X) + i * 30, hwRound(Y), 4) then
   715             if TestColl(hwRound(X) + i * 30, hwRound(Y), 4) then
   695           begin
   716                 begin
   696           b[i]:= false;
   717                 b[i]:= false;
   697           dmg[i]:= RateExplosion(Me, hwRound(X) + i * 30, hwRound(Y), 58)
   718                 dmg[i]:= RateExplosion(Me, hwRound(X) + i * 30, hwRound(Y), 58)
   698           // 58 (instead of 60) for better prediction (hh moves after explosion of one of the rockets)
   719                 // 58 (instead of 60) for better prediction (hh moves after explosion of one of the rockets)
   699           end
   720                 end
   700        end;
   721             end;
   701 until fexit or (Y.Round > cWaterLine);
   722 until fexit or (Y.Round > cWaterLine);
   702 
   723 
   703 for i:= 0 to 5 do inc(valueResult, dmg[i]);
   724 for i:= 0 to 5 do inc(valueResult, dmg[i]);
   704 t:= valueResult;
   725 t:= valueResult;
   705 ap.AttackPutX:= Targ.X - 60;
   726 ap.AttackPutX:= Targ.X - 60;
   707 for i:= 0 to 3 do
   728 for i:= 0 to 3 do
   708     begin
   729     begin
   709     dec(t, dmg[i]);
   730     dec(t, dmg[i]);
   710     inc(t, dmg[i + 6]);
   731     inc(t, dmg[i + 6]);
   711     if t > valueResult then
   732     if t > valueResult then
   712        begin
   733         begin
   713        valueResult:= t;
   734         valueResult:= t;
   714        ap.AttackPutX:= Targ.X - 30 - cShift + i * 30
   735         ap.AttackPutX:= Targ.X - 30 - cShift + i * 30
   715        end
   736         end
   716     end;
   737     end;
   717 
   738 
   718 if valueResult <= 0 then valueResult:= BadTurn;
   739 if valueResult <= 0 then
       
   740     valueResult:= BadTurn;
   719 TestAirAttack:= valueResult;
   741 TestAirAttack:= valueResult;
   720 end;
   742 end;
   721 
   743 
   722 
   744 
   723 function TestTeleport(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   745 function TestTeleport(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
   726     maxTop: longword;
   748     maxTop: longword;
   727 begin
   749 begin
   728     TestTeleport := BadTurn;
   750     TestTeleport := BadTurn;
   729     Level:= Level; // avoid compiler hint
   751     Level:= Level; // avoid compiler hint
   730     FillBonuses(true, [gtCase]);
   752     FillBonuses(true, [gtCase]);
   731     if bonuses.Count = 0 then begin
   753     if bonuses.Count = 0 then
   732         if Me^.Health <= 100  then begin
   754         begin
       
   755         if Me^.Health <= 100  then
       
   756             begin
   733             maxTop := Targ.Y - cHHRadius * 2;
   757             maxTop := Targ.Y - cHHRadius * 2;
       
   758             
   734             while not TestColl(Targ.X, maxTop, cHHRadius) and (maxTop > topY + cHHRadius * 2 + 1) do
   759             while not TestColl(Targ.X, maxTop, cHHRadius) and (maxTop > topY + cHHRadius * 2 + 1) do
   735             dec(maxTop, cHHRadius*2);
   760                 dec(maxTop, cHHRadius*2);
   736             if not TestColl(Targ.X, maxTop + cHHRadius, cHHRadius) then begin
   761             if not TestColl(Targ.X, maxTop + cHHRadius, cHHRadius) then
       
   762                 begin
   737                 ap.AttackPutX := Targ.X;
   763                 ap.AttackPutX := Targ.X;
   738                 ap.AttackPutY := maxTop + cHHRadius;
   764                 ap.AttackPutY := maxTop + cHHRadius;
   739                 TestTeleport := Targ.Y - maxTop;
   765                 TestTeleport := Targ.Y - maxTop;
       
   766                 end;
   740             end;
   767             end;
   741         end;
   768         end
   742     end
   769     else
   743     else begin
   770         begin
   744         failNum := 0;
   771         failNum := 0;
   745         repeat
   772         repeat
   746             i := random(bonuses.Count);
   773             i := random(bonuses.Count);
   747             inc(failNum);
   774             inc(failNum);
   748         until not TestColl(bonuses.ar[i].X, bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius, cHHRadius) or (failNum = bonuses.Count*2);
   775         until not TestColl(bonuses.ar[i].X, bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius, cHHRadius)
   749         if failNum < bonuses.Count*2 then begin
   776         or (failNum = bonuses.Count*2);
       
   777         
       
   778         if failNum < bonuses.Count*2 then
       
   779             begin
   750             ap.AttackPutX := bonuses.ar[i].X;
   780             ap.AttackPutX := bonuses.ar[i].X;
   751             ap.AttackPutY := bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius;
   781             ap.AttackPutY := bonuses.ar[i].Y - cHHRadius - bonuses.ar[i].Radius;
   752             TestTeleport := 0;
   782             TestTeleport := 0;
       
   783             end;
   753         end;
   784         end;
   754     end;
       
   755 end;
   785 end;
   756 
   786 
   757 end.
   787 end.