hedgewars/uAIMisc.pas
changeset 8939 b26aaf28c920
parent 8924 13ac59499066
child 8950 3bf81ed1f984
--- a/hedgewars/uAIMisc.pas	Sat Apr 27 00:09:50 2013 +0400
+++ b/hedgewars/uAIMisc.pas	Sat Apr 27 16:56:50 2013 -0400
@@ -33,11 +33,12 @@
 type TTarget = record
     Point: TPoint;
     Score: LongInt;
-    skip, matters: boolean;
+    skip, matters, dead: boolean;
     end;
 TTargets = record
     Count: Longword;
     ar: array[0..Pred(cMaxHHs)] of TTarget;
+    reset: boolean;
     end;
 TJumpType = (jmpNone, jmpHJump, jmpLJump);
 TGoInfo = record
@@ -55,6 +56,7 @@
 procedure freeModule;
 
 procedure FillTargets;
+procedure ResetTargets; inline;
 procedure AddBonus(x, y: LongInt; r: Longword; s: LongInt); inline;
 procedure FillBonuses(isAfterAttack: boolean);
 procedure AwareOfExplosion(x, y, r: LongInt); inline;
@@ -66,9 +68,11 @@
 function  TraceShoveFall(x, y, dX, dY: Real): LongInt;
 
 function  RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
-function  RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
+function  RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; inline;
+function  RealRateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
 function  RateShove(x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
-function  RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
+function  RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt; inline;
+function  RealRateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
 function  RateHammer(Me: PGear): LongInt;
 
 function  HHGo(Gear, AltGear: PGear; var GoInfo: TGoInfo): boolean;
@@ -99,11 +103,20 @@
         X, Y, Radius: LongInt
         end = (X: 0; Y: 0; Radius: 0);
 
+procedure ResetTargets; inline;
+var i: LongWord;
+begin
+if Targets.reset then
+    for i:= 0 to Targets.Count do
+        Targets.ar[i].dead:= false;
+Targets.reset:= false;
+end;
 procedure FillTargets;
 var i, t: Longword;
     f, e: LongInt;
 begin
 Targets.Count:= 0;
+Targets.reset:= false;
 f:= 0;
 e:= 0;
 for t:= 0 to Pred(TeamsCount) do
@@ -119,6 +132,7 @@
                     with Targets.ar[Targets.Count], Hedgehogs[i] do
                         begin
                         skip:= false;
+                        dead:= false;
                         matters:= (Hedgehogs[i].Gear^.AIHints and aihDoesntMatter) = 0;
 
                         Point.X:= hwRound(Gear^.X);
@@ -326,7 +340,7 @@
 
 
 
-function TraceFall(eX, eY: LongInt; x, y, dX, dY: Real; r: LongWord): LongInt;
+function TraceFall(eX, eY: LongInt; var x, y: Real; dX, dY: Real; r: LongWord): LongInt;
 var skipLandCheck: boolean;
     rCorner: real;
     dmg: LongInt;
@@ -391,14 +405,20 @@
     end;
 end;
 
-function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt;
+function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
 begin
-    RateExplosion:= RateExplosion(Me, x, y, r, 0);
+    RateExplosion:= RealRateExplosion(Me, x, y, r, 0);
+    ResetTargets;
+end;
+function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt; inline;
+begin
+    RateExplosion:= RealRateExplosion(Me, x, y, r, Flags);
+    ResetTargets;
 end;
 
-function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
+function RealRateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
 var i, fallDmg, dmg, dmgBase, rate, erasure: LongInt;
-    dX, dY: real;
+    pX, pY, dX, dY: real;
     hadSkips: boolean;
 begin
 fallDmg:= 0;
@@ -421,46 +441,55 @@
 hadSkips:= false;
 
 for i:= 0 to Targets.Count do
-    with Targets.ar[i] do
-      if not matters then hadSkips:= true
-        else
-        begin
-        dmg:= 0;
-        if abs(Point.x - x) + abs(Point.y - y) < dmgBase then
-            dmg:= trunc(dmgMod * min((dmgBase - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)))) div 2, r));
+    if not Targets.ar[i].dead then
+        with Targets.ar[i] do
+          if not matters then hadSkips:= true
+            else
+            begin
+            dmg:= 0;
+            if abs(Point.x - x) + abs(Point.y - y) < dmgBase then
+                dmg:= trunc(dmgMod * min((dmgBase - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)))) div 2, r));
 
-        if dmg > 0 then
-            begin
-            if (Flags and afTrackFall <> 0) and (dmg < abs(Score)) then
+            if dmg > 0 then
                 begin
-                dX:= 0.005 * dmg + 0.01;
-                dY:= dX;
-                if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
-                   (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
-                     fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, 0) * dmgMod)
-                else fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod)
-                end;
-            if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
-                if Score > 0 then
-                    inc(rate, (KillScore + Score div 10) * 1024)   // Add a bit of a bonus for bigger hog drownings
+                pX:= Point.x;
+                pY:= Point.y;
+                if (Flags and afTrackFall <> 0) and (dmg < abs(Score)) then
+                    begin
+                    dX:= 0.005 * dmg + 0.01;
+                    dY:= dX;
+                    if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
+                       (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
+                         fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0) * dmgMod)
+                    else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure) * dmgMod)
+                    end;
+                if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
+                    if Score > 0 then
+                        inc(rate, (KillScore + Score div 10) * 1024)   // Add a bit of a bonus for bigger hog drownings
+                    else
+                        dec(rate, (KillScore * friendlyfactor div 100 - Score div 10) * 1024) // and more of a punishment for drowning bigger friendly hogs
+                else if (dmg+fallDmg) >= abs(Score) then
+                    begin
+                    dead:= true;
+                    Targets.reset:= true;
+                    if dX < 0.035 then
+                        inc(Rate,RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or (Flags and afTrackFall)));
+                    if Score > 0 then
+                        inc(rate, KillScore * 1024 + (dmg + fallDmg)) // tiny bonus for dealing more damage than needed to kill
+                    else
+                        dec(rate, KillScore * friendlyfactor div 100 * 1024)
+                    end
                 else
-                    dec(rate, (KillScore * friendlyfactor div 100 - Score div 10) * 1024) // and more of a punishment for drowning bigger friendly hogs
-            else if (dmg+fallDmg) >= abs(Score) then
-                if Score > 0 then
-                    inc(rate, KillScore * 1024 + (dmg + fallDmg)) // tiny bonus for dealing more damage than needed to kill
-                else
-                    dec(rate, KillScore * friendlyfactor div 100 * 1024)
-            else
-                if Score > 0 then
-                    inc(rate, (dmg + fallDmg) * 1024)
-                else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024)
+                    if Score > 0 then
+                        inc(rate, (dmg + fallDmg) * 1024)
+                    else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024)
+                end;
             end;
-        end;
 
 if hadSkips and (rate = 0) then
-    RateExplosion:= BadTurn
+    RealRateExplosion:= BadTurn
     else
-    RateExplosion:= rate;
+    RealRateExplosion:= rate;
 end;
 
 function RateShove(x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
@@ -506,9 +535,14 @@
 RateShove:= rate * 1024
 end;
 
-function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
+function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt; inline;
+begin
+    RateShotgun:= RealRateShotgun(Me, gdX, gdY, x, y);
+    ResetTargets;
+end;
+function RealRateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
 var i, dmg, fallDmg, baseDmg, rate, erasure: LongInt;
-    dX, dY: real;
+    pX, pY, dX, dY: real;
     hadSkips: boolean;
 begin
 rate:= 0;
@@ -532,48 +566,57 @@
 hadSkips:= false;
 
 for i:= 0 to Targets.Count do
-    with Targets.ar[i] do
-      if not matters then hadSkips:= true
-        else
-        begin
-        dmg:= 0;
-        if abs(Point.x - x) + abs(Point.y - y) < baseDmg then
-            begin
-            dmg:= min(baseDmg - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y))), 25);
-            dmg:= trunc(dmg * dmgMod);
-            end;
-        if dmg > 0 then
+    if not Targets.ar[i].dead then
+        with Targets.ar[i] do
+          if not matters then hadSkips:= true
+            else
             begin
-            dX:= gdX * dmg;
-            dY:= gdY * dmg;
-            if dX < 0 then dX:= dX - 0.01
-            else dX:= dX + 0.01;
-            if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
-               (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
-                 fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, 0) * dmgMod)
-            else fallDmg:= trunc(TraceFall(x, y, Point.x, Point.y, dX, dY, erasure) * dmgMod);
-            if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
-                if Score > 0 then
-                    inc(rate, KillScore + Score div 10)   // Add a bit of a bonus for bigger hog drownings
+            dmg:= 0;
+            if abs(Point.x - x) + abs(Point.y - y) < baseDmg then
+                begin
+                dmg:= min(baseDmg - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y))), 25);
+                dmg:= trunc(dmg * dmgMod);
+                end;
+            if dmg > 0 then
+                begin
+                pX:= Point.x;
+                pY:= Point.y;
+                dX:= gdX * dmg;
+                dY:= gdY * dmg;
+                if dX < 0 then dX:= dX - 0.01
+                else dX:= dX + 0.01;
+                if (x and LAND_WIDTH_MASK = 0) and ((y+cHHRadius+2) and LAND_HEIGHT_MASK = 0) and
+                   (Land[y+cHHRadius+2, x] and lfIndestructible <> 0) then
+                     fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, 0) * dmgMod)
+                else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure) * dmgMod);
+                if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
+                    if Score > 0 then
+                        inc(rate, KillScore + Score div 10)   // Add a bit of a bonus for bigger hog drownings
+                    else
+                        dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs
+                else if (dmg+fallDmg) >= abs(Score) then
+                    begin
+                    dead:= true;
+                    Targets.reset:= true;
+                    if dX < 0.035 then
+                        inc(Rate,RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or afTrackFall) div 1024);
+                    if Score > 0 then
+                        inc(rate, KillScore)
+                    else
+                        dec(rate, KillScore * friendlyfactor div 100)
+                    end
                 else
-                    dec(rate, KillScore * friendlyfactor div 100 - Score div 10) // and more of a punishment for drowning bigger friendly hogs
-            else if (dmg+fallDmg) >= abs(Score) then
-                if Score > 0 then
-                    inc(rate, KillScore)
+                    if Score > 0 then
+                        inc(rate, dmg+fallDmg)
                 else
-                    dec(rate, KillScore * friendlyfactor div 100)
-            else
-                if Score > 0 then
-                    inc(rate, dmg+fallDmg)
-            else
-                dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
+                    dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
+                end;
             end;
-        end;
 
 if hadSkips and (rate = 0) then
-    RateShotgun:= BadTurn
+    RealRateShotgun:= BadTurn
     else
-    RateShotgun:= rate * 1024;
+    RealRateShotgun:= rate * 1024;
 end;
 
 function RateHammer(Me: PGear): LongInt;