hedgewars/uAIMisc.pas
changeset 8939 b26aaf28c920
parent 8924 13ac59499066
child 8950 3bf81ed1f984
equal deleted inserted replaced
8938:c321264439c6 8939:b26aaf28c920
    31       BadTurn = Low(LongInt) div 4;
    31       BadTurn = Low(LongInt) div 4;
    32 
    32 
    33 type TTarget = record
    33 type TTarget = record
    34     Point: TPoint;
    34     Point: TPoint;
    35     Score: LongInt;
    35     Score: LongInt;
    36     skip, matters: boolean;
    36     skip, matters, dead: boolean;
    37     end;
    37     end;
    38 TTargets = record
    38 TTargets = record
    39     Count: Longword;
    39     Count: Longword;
    40     ar: array[0..Pred(cMaxHHs)] of TTarget;
    40     ar: array[0..Pred(cMaxHHs)] of TTarget;
       
    41     reset: boolean;
    41     end;
    42     end;
    42 TJumpType = (jmpNone, jmpHJump, jmpLJump);
    43 TJumpType = (jmpNone, jmpHJump, jmpLJump);
    43 TGoInfo = record
    44 TGoInfo = record
    44     Ticks: Longword;
    45     Ticks: Longword;
    45     FallPix: Longword;
    46     FallPix: Longword;
    53 
    54 
    54 procedure initModule;
    55 procedure initModule;
    55 procedure freeModule;
    56 procedure freeModule;
    56 
    57 
    57 procedure FillTargets;
    58 procedure FillTargets;
       
    59 procedure ResetTargets; inline;
    58 procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); inline;
    60 procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); inline;
    59 procedure FillBonuses(isAfterAttack: boolean);
    61 procedure FillBonuses(isAfterAttack: boolean);
    60 procedure AwareOfExplosion(x, y, r: LongInt); inline;
    62 procedure AwareOfExplosion(x, y, r: LongInt); inline;
    61 
    63 
    62 function  RatePlace(Gear: PGear): LongInt;
    64 function  RatePlace(Gear: PGear): LongInt;
    64 function  TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
    66 function  TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
    65 function  TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline;
    67 function  TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline;
    66 function  TraceShoveFall(x, y, dX, dY: Real): LongInt;
    68 function  TraceShoveFall(x, y, dX, dY: Real): LongInt;
    67 
    69 
    68 function  RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
    70 function  RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
    69 function  RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
    71 function  RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; inline;
       
    72 function  RealRateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
    70 function  RateShove(x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
    73 function  RateShove(x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
    71 function  RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
    74 function  RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt; inline;
       
    75 function  RealRateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
    72 function  RateHammer(Me: PGear): LongInt;
    76 function  RateHammer(Me: PGear): LongInt;
    73 
    77 
    74 function  HHGo(Gear, AltGear: PGear; var GoInfo: TGoInfo): boolean;
    78 function  HHGo(Gear, AltGear: PGear; var GoInfo: TGoInfo): boolean;
    75 function  AIrndSign(num: LongInt): LongInt;
    79 function  AIrndSign(num: LongInt): LongInt;
    76 
    80 
    97 var
   101 var
    98     KnownExplosion: record
   102     KnownExplosion: record
    99         X, Y, Radius: LongInt
   103         X, Y, Radius: LongInt
   100         end = (X: 0; Y: 0; Radius: 0);
   104         end = (X: 0; Y: 0; Radius: 0);
   101 
   105 
       
   106 procedure ResetTargets; inline;
       
   107 var i: LongWord;
       
   108 begin
       
   109 if Targets.reset then
       
   110     for i:= 0 to Targets.Count do
       
   111         Targets.ar[i].dead:= false;
       
   112 Targets.reset:= false;
       
   113 end;
   102 procedure FillTargets;
   114 procedure FillTargets;
   103 var i, t: Longword;
   115 var i, t: Longword;
   104     f, e: LongInt;
   116     f, e: LongInt;
   105 begin
   117 begin
   106 Targets.Count:= 0;
   118 Targets.Count:= 0;
       
   119 Targets.reset:= false;
   107 f:= 0;
   120 f:= 0;
   108 e:= 0;
   121 e:= 0;
   109 for t:= 0 to Pred(TeamsCount) do
   122 for t:= 0 to Pred(TeamsCount) do
   110     with TeamsArray[t]^ do
   123     with TeamsArray[t]^ do
   111         if not hasGone then
   124         if not hasGone then
   117                     then
   130                     then
   118                     begin
   131                     begin
   119                     with Targets.ar[Targets.Count], Hedgehogs[i] do
   132                     with Targets.ar[Targets.Count], Hedgehogs[i] do
   120                         begin
   133                         begin
   121                         skip:= false;
   134                         skip:= false;
       
   135                         dead:= false;
   122                         matters:= (Hedgehogs[i].Gear^.AIHints and aihDoesntMatter) = 0;
   136                         matters:= (Hedgehogs[i].Gear^.AIHints and aihDoesntMatter) = 0;
   123 
   137 
   124                         Point.X:= hwRound(Gear^.X);
   138                         Point.X:= hwRound(Gear^.X);
   125                         Point.Y:= hwRound(Gear^.Y);
   139                         Point.Y:= hwRound(Gear^.Y);
   126                         if Clan <> CurrentTeam^.Clan then
   140                         if Clan <> CurrentTeam^.Clan then
   324     TestCollExcludingMe:= TestCollWithEverything(x, y, r)
   338     TestCollExcludingMe:= TestCollWithEverything(x, y, r)
   325 end;
   339 end;
   326 
   340 
   327 
   341 
   328 
   342 
   329 function TraceFall(eX, eY: LongInt; x, y, dX, dY: Real; r: LongWord): LongInt;
   343 function TraceFall(eX, eY: LongInt; var x, y: Real; dX, dY: Real; r: LongWord): LongInt;
   330 var skipLandCheck: boolean;
   344 var skipLandCheck: boolean;
   331     rCorner: real;
   345     rCorner: real;
   332     dmg: LongInt;
   346     dmg: LongInt;
   333 begin
   347 begin
   334     skipLandCheck:= true;
   348     skipLandCheck:= true;
   389             // returning -1 for drowning so it can be considered in the Rate routine
   403             // returning -1 for drowning so it can be considered in the Rate routine
   390             exit(-1)
   404             exit(-1)
   391     end;
   405     end;
   392 end;
   406 end;
   393 
   407 
   394 function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt;
   408 function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
   395 begin
   409 begin
   396     RateExplosion:= RateExplosion(Me, x, y, r, 0);
   410     RateExplosion:= RealRateExplosion(Me, x, y, r, 0);
   397 end;
   411     ResetTargets;
   398 
   412 end;
   399 function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
   413 function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; inline;
       
   414 begin
       
   415     RateExplosion:= RealRateExplosion(Me, x, y, r, Flags);
       
   416     ResetTargets;
       
   417 end;
       
   418 
       
   419 function RealRateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
   400 var i, fallDmg, dmg, dmgBase, rate, erasure: LongInt;
   420 var i, fallDmg, dmg, dmgBase, rate, erasure: LongInt;
   401     dX, dY: real;
   421     pX, pY, dX, dY: real;
   402     hadSkips: boolean;
   422     hadSkips: boolean;
   403 begin
   423 begin
   404 fallDmg:= 0;
   424 fallDmg:= 0;
   405 rate:= 0;
   425 rate:= 0;
   406 // add our virtual position
   426 // add our virtual position
   419 else erasure:= 0;
   439 else erasure:= 0;
   420 
   440 
   421 hadSkips:= false;
   441 hadSkips:= false;
   422 
   442 
   423 for i:= 0 to Targets.Count do
   443 for i:= 0 to Targets.Count do
   424     with Targets.ar[i] do
   444     if not Targets.ar[i].dead then
   425       if not matters then hadSkips:= true
   445         with Targets.ar[i] do
   426         else
   446           if not matters then hadSkips:= true
   427         begin
   447             else
   428         dmg:= 0;
   448             begin
   429         if abs(Point.x - x) + abs(Point.y - y) < dmgBase then
   449             dmg:= 0;
   430             dmg:= trunc(dmgMod * min((dmgBase - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)))) div 2, r));
   450             if abs(Point.x - x) + abs(Point.y - y) < dmgBase then
   431 
   451                 dmg:= trunc(dmgMod * min((dmgBase - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)))) div 2, r));
   432         if dmg > 0 then
   452 
   433             begin
   453             if dmg > 0 then
   434             if (Flags and afTrackFall <> 0) and (dmg < abs(Score)) then
       
   435                 begin
   454                 begin
   436                 dX:= 0.005 * dmg + 0.01;
   455                 pX:= Point.x;
   437                 dY:= dX;
   456                 pY:= Point.y;
   438                 if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
   457                 if (Flags and afTrackFall <> 0) and (dmg < abs(Score)) then
   439                    (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
   458                     begin
   440                      fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, 0) * dmgMod)
   459                     dX:= 0.005 * dmg + 0.01;
   441                 else fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod)
   460                     dY:= dX;
       
   461                     if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
       
   462                        (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
       
   463                          fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0) * dmgMod)
       
   464                     else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure) * dmgMod)
       
   465                     end;
       
   466                 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
       
   467                     if Score > 0 then
       
   468                         inc(rate, (KillScore + Score div 10) * 1024)   // Add a bit of a bonus for bigger hog drownings
       
   469                     else
       
   470                         dec(rate, (KillScore * friendlyfactor div 100 - Score div 10) * 1024) // and more of a punishment for drowning bigger friendly hogs
       
   471                 else if (dmg+fallDmg) >= abs(Score) then
       
   472                     begin
       
   473                     dead:= true;
       
   474                     Targets.reset:= true;
       
   475                     if dX < 0.035 then
       
   476                         inc(Rate,RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or (Flags and afTrackFall)));
       
   477                     if Score > 0 then
       
   478                         inc(rate, KillScore * 1024 + (dmg + fallDmg)) // tiny bonus for dealing more damage than needed to kill
       
   479                     else
       
   480                         dec(rate, KillScore * friendlyfactor div 100 * 1024)
       
   481                     end
       
   482                 else
       
   483                     if Score > 0 then
       
   484                         inc(rate, (dmg + fallDmg) * 1024)
       
   485                     else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024)
   442                 end;
   486                 end;
   443             if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
   487             end;
   444                 if Score > 0 then
       
   445                     inc(rate, (KillScore + Score div 10) * 1024)   // Add a bit of a bonus for bigger hog drownings
       
   446                 else
       
   447                     dec(rate, (KillScore * friendlyfactor div 100 - Score div 10) * 1024) // and more of a punishment for drowning bigger friendly hogs
       
   448             else if (dmg+fallDmg) >= abs(Score) then
       
   449                 if Score > 0 then
       
   450                     inc(rate, KillScore * 1024 + (dmg + fallDmg)) // tiny bonus for dealing more damage than needed to kill
       
   451                 else
       
   452                     dec(rate, KillScore * friendlyfactor div 100 * 1024)
       
   453             else
       
   454                 if Score > 0 then
       
   455                     inc(rate, (dmg + fallDmg) * 1024)
       
   456                 else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024)
       
   457             end;
       
   458         end;
       
   459 
   488 
   460 if hadSkips and (rate = 0) then
   489 if hadSkips and (rate = 0) then
   461     RateExplosion:= BadTurn
   490     RealRateExplosion:= BadTurn
   462     else
   491     else
   463     RateExplosion:= rate;
   492     RealRateExplosion:= rate;
   464 end;
   493 end;
   465 
   494 
   466 function RateShove(x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
   495 function RateShove(x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
   467 var i, fallDmg, dmg, rate: LongInt;
   496 var i, fallDmg, dmg, rate: LongInt;
   468     dX, dY: real;
   497     dX, dY: real;
   504             end;
   533             end;
   505         end;
   534         end;
   506 RateShove:= rate * 1024
   535 RateShove:= rate * 1024
   507 end;
   536 end;
   508 
   537 
   509 function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
   538 function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt; inline;
       
   539 begin
       
   540     RateShotgun:= RealRateShotgun(Me, gdX, gdY, x, y);
       
   541     ResetTargets;
       
   542 end;
       
   543 function RealRateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
   510 var i, dmg, fallDmg, baseDmg, rate, erasure: LongInt;
   544 var i, dmg, fallDmg, baseDmg, rate, erasure: LongInt;
   511     dX, dY: real;
   545     pX, pY, dX, dY: real;
   512     hadSkips: boolean;
   546     hadSkips: boolean;
   513 begin
   547 begin
   514 rate:= 0;
   548 rate:= 0;
   515 gdX:= gdX * 0.01;
   549 gdX:= gdX * 0.01;
   516 gdY:= gdX * 0.01;
   550 gdY:= gdX * 0.01;
   530 else erasure:= 0;
   564 else erasure:= 0;
   531 
   565 
   532 hadSkips:= false;
   566 hadSkips:= false;
   533 
   567 
   534 for i:= 0 to Targets.Count do
   568 for i:= 0 to Targets.Count do
   535     with Targets.ar[i] do
   569     if not Targets.ar[i].dead then
   536       if not matters then hadSkips:= true
   570         with Targets.ar[i] do
   537         else
   571           if not matters then hadSkips:= true
   538         begin
   572             else
   539         dmg:= 0;
   573             begin
   540         if abs(Point.x - x) + abs(Point.y - y) < baseDmg then
   574             dmg:= 0;
   541             begin
   575             if abs(Point.x - x) + abs(Point.y - y) < baseDmg then
   542             dmg:= min(baseDmg - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y))), 25);
   576                 begin
   543             dmg:= trunc(dmg * dmgMod);
   577                 dmg:= min(baseDmg - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y))), 25);
   544             end;
   578                 dmg:= trunc(dmg * dmgMod);
   545         if dmg > 0 then
   579                 end;
   546             begin
   580             if dmg > 0 then
   547             dX:= gdX * dmg;
   581                 begin
   548             dY:= gdY * dmg;
   582                 pX:= Point.x;
   549             if dX < 0 then dX:= dX - 0.01
   583                 pY:= Point.y;
   550             else dX:= dX + 0.01;
   584                 dX:= gdX * dmg;
   551             if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
   585                 dY:= gdY * dmg;
   552                (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
   586                 if dX < 0 then dX:= dX - 0.01
   553                  fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, 0) * dmgMod)
   587                 else dX:= dX + 0.01;
   554             else fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod);
   588                 if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
   555             if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
   589                    (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
   556                 if Score > 0 then
   590                      fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0) * dmgMod)
   557                     inc(rate, KillScore + Score div 10)   // Add a bit of a bonus for bigger hog drownings
   591                 else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure) * dmgMod);
       
   592                 if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
       
   593                     if Score > 0 then
       
   594                         inc(rate, KillScore + Score div 10)   // Add a bit of a bonus for bigger hog drownings
       
   595                     else
       
   596                         dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs
       
   597                 else if (dmg+fallDmg) >= abs(Score) then
       
   598                     begin
       
   599                     dead:= true;
       
   600                     Targets.reset:= true;
       
   601                     if dX < 0.035 then
       
   602                         inc(Rate,RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or afTrackFall) div 1024);
       
   603                     if Score > 0 then
       
   604                         inc(rate, KillScore)
       
   605                     else
       
   606                         dec(rate, KillScore * friendlyfactor div 100)
       
   607                     end
   558                 else
   608                 else
   559                     dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs
   609                     if Score > 0 then
   560             else if (dmg+fallDmg) >= abs(Score) then
   610                         inc(rate, dmg+fallDmg)
   561                 if Score > 0 then
       
   562                     inc(rate, KillScore)
       
   563                 else
   611                 else
   564                     dec(rate, KillScore * friendlyfactor div 100)
   612                     dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
   565             else
   613                 end;
   566                 if Score > 0 then
   614             end;
   567                     inc(rate, dmg+fallDmg)
       
   568             else
       
   569                 dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
       
   570             end;
       
   571         end;
       
   572 
   615 
   573 if hadSkips and (rate = 0) then
   616 if hadSkips and (rate = 0) then
   574     RateShotgun:= BadTurn
   617     RealRateShotgun:= BadTurn
   575     else
   618     else
   576     RateShotgun:= rate * 1024;
   619     RealRateShotgun:= rate * 1024;
   577 end;
   620 end;
   578 
   621 
   579 function RateHammer(Me: PGear): LongInt;
   622 function RateHammer(Me: PGear): LongInt;
   580 var x, y, i, r, rate: LongInt;
   623 var x, y, i, r, rate: LongInt;
   581 begin
   624 begin