hedgewars/uAIAmmoTests.pas
branchwebgl
changeset 9127 e350500c4edb
parent 8839 caa57115d7ea
parent 9080 9b42757d7e71
child 9136 78f087fd3e5b
--- a/hedgewars/uAIAmmoTests.pas	Thu Apr 04 14:37:19 2013 +0200
+++ b/hedgewars/uAIAmmoTests.pas	Tue Jun 04 22:28:12 2013 +0200
@@ -1,6 +1,6 @@
 (*
  * Hedgewars, a free turn based strategy game
- * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
+ * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@
 
 unit uAIAmmoTests;
 interface
-uses SDLh, uConsts, uFloat, uTypes;
+uses SDLh, uConsts, uFloat, uTypes, uAIMisc;
 const
     amtest_Rare     = $00000001; // check only several positions
     amtest_NoTarget = $00000002; // each pos, but no targetting
@@ -34,27 +34,27 @@
         AttackPutX, AttackPutY: LongInt;
         end;
 
-function TestBazooka(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestGrenade(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestClusterBomb(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestWatermelon(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestDrillRocket(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestShotgun(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestDesertEagle(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestSniperRifle(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestBaseballBat(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestWhip(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestKamikaze(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestAirAttack(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestTeleport(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestHammer(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-function TestCake(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestBazooka(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestSnowball(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestGrenade(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestMolotov(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestClusterBomb(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestWatermelon(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestDrillRocket(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestMortar(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestShotgun(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestDesertEagle(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestSniperRifle(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestBaseballBat(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestFirePunch(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestWhip(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestKamikaze(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestAirAttack(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestTeleport(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestHammer(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestCake(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 
-type TAmmoTestProc = function (Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+type TAmmoTestProc = function (Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
     TAmmoTest = record
             proc: TAmmoTestProc;
             flags: Longword;
@@ -123,14 +123,14 @@
             );
 
 implementation
-uses uAIMisc, uVariables, uUtils, uGearsHandlers;
+uses uVariables, uUtils, uGearsHandlers;
 
 function Metric(x1, y1, x2, y2: LongInt): LongInt; inline;
 begin
 Metric:= abs(x1 - x2) + abs(y1 - y2)
 end;
 
-function TestBazooka(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestBazooka(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var Vx, Vy, r, mX, mY: real;
     rTime: LongInt;
     EX, EY: LongInt;
@@ -147,8 +147,8 @@
 valueResult:= BadTurn;
 repeat
     rTime:= rTime + 300 + Level * 50 + random(300);
-    Vx:= - windSpeed * rTime * 0.5 + (Targ.X + AIrndSign(2) - mX) / rTime;
-    Vy:= cGravityf * rTime * 0.5 - (Targ.Y + 1 - mY) / rTime;
+    Vx:= - windSpeed * rTime * 0.5 + (Targ.Point.X + AIrndSign(2) - mX) / rTime;
+    Vy:= cGravityf * rTime * 0.5 - (Targ.Point.Y + 1 - mY) / rTime;
     r:= sqr(Vx) + sqr(Vy);
     if not (r > 1) then
         begin
@@ -164,15 +164,15 @@
             dY:= dY + cGravityf;
             dec(t)
         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
-               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t <= 0);
+               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (t <= 0);
 
         EX:= trunc(x);
         EY:= trunc(y);
         if Level = 1 then
             value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
         else value:= RateExplosion(Me, EX, EY, 101);
-        if value = 0 then
-            value:= 1024 - Metric(Targ.X, Targ.Y, EX, EY) div 64;
+        if (value = 0) and (Targ.Kind = gtHedgehog) and (Targ.Score > 0) then
+            value:= 1024 - Metric(Targ.Point.X, Targ.Point.Y, EX, EY) div 64;
         if valueResult <= value then
             begin
             ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random((Level - 1) * 9));
@@ -184,12 +184,12 @@
             end;
         end
 //until (value > 204800) or (rTime > 4250); not so useful since adding score to the drowning
-until rTime > 4250;
+until rTime > 5050 - Level * 800;
 TestBazooka:= valueResult
 end;
 
 
-function TestDrillRocket(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestDrillRocket(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var Vx, Vy, r, mX, mY: real;
     rTime: LongInt;
     EX, EY: LongInt;
@@ -210,8 +210,8 @@
     valueResult:= BadTurn;
     repeat
         rTime:= rTime + 300 + Level * 50 + random(300);
-        Vx:= - windSpeed * rTime * 0.5 + (Targ.X + AIrndSign(2) - mX) / rTime;
-        Vy:= cGravityf * rTime * 0.5 - (Targ.Y - 35 - mY) / rTime;
+        Vx:= - windSpeed * rTime * 0.5 + (Targ.Point.X + AIrndSign(2) - mX) / rTime;
+        Vy:= cGravityf * rTime * 0.5 - (Targ.Point.Y - 35 - mY) / rTime;
         r:= sqr(Vx) + sqr(Vy);
         if not (r > 1) then
             begin
@@ -227,9 +227,9 @@
                 dY:= dY + cGravityf;
                 dec(t)
             until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
-                   ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (y > cWaterLine);
+                   ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (y > cWaterLine);
 
-            if TestCollWithLand(trunc(x), trunc(y), 5) and (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) > 21) then
+            if TestCollExcludingObjects(trunc(x), trunc(y), 5) and (Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) > 21) then
                 begin
                 timer := 500;
                 t2 := 0.5 / sqrt(sqr(dX) + sqr(dY));
@@ -239,16 +239,18 @@
                     x:= x + dX;
                     y:= y + dY;
                     dec(timer);
-                until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 22)
+                until (Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) < 22)
                     or (x < 0)
                     or (y < 0)
                     or (trunc(x) > LAND_WIDTH)
                     or (trunc(y) > LAND_HEIGHT)
-                    or (not TestCollWithLand(trunc(x), trunc(y), 5))
+                    or not TestCollExcludingObjects(trunc(x), trunc(y), 5)
                     or (timer = 0)
                 end;
             EX:= trunc(x);
             EY:= trunc(y);
+            // Try to prevent AI from thinking firing into water will cause a drowning
+            if (EY < cWaterLine-5) and (Timer > 0) and (Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) > 21) then exit(BadTurn);
             if Level = 1 then
                 value:= RateExplosion(Me, EX, EY, 101, afTrackFall or afErasesLand)
             else value:= RateExplosion(Me, EX, EY, 101);
@@ -262,12 +264,12 @@
                 valueResult:= value-2500 // trying to make it slightly less attractive than a bazooka, to prevent waste.  AI could use awareness of weapon count
                 end;
             end
-    until rTime > 4250;
+    until rTime > 5050 - Level * 800;
     TestDrillRocket:= valueResult
 end;
 
 
-function TestSnowball(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestSnowball(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var Vx, Vy, r: real;
     rTime: LongInt;
     EX, EY: LongInt;
@@ -285,8 +287,8 @@
 valueResult:= BadTurn;
 repeat
     rTime:= rTime + 300 + Level * 50 + random(1000);
-    Vx:= - windSpeed * rTime * 0.5 + ((Targ.X + AIrndSign(2)) - meX) / rTime;
-    Vy:= cGravityf * rTime * 0.5 - (Targ.Y - meY) / rTime;
+    Vx:= - windSpeed * rTime * 0.5 + ((Targ.Point.X + AIrndSign(2)) - meX) / rTime;
+    Vy:= cGravityf * rTime * 0.5 - (Targ.Point.Y - meY) / rTime;
     r:= sqr(Vx) + sqr(Vy);
     if not (r > 1) then
         begin
@@ -302,14 +304,14 @@
             dY:= dY + cGravityf;
             dec(t)
         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
-               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t <= 0);
+               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (t <= 0);
         EX:= trunc(x);
         EY:= trunc(y);
 
-        value:= RateShove(trunc(x), trunc(y), 5, 1, trunc((abs(dX)+abs(dY))*20), -dX, -dY, afTrackFall);
+        value:= RateShove(Me, trunc(x), trunc(y), 5, 1, trunc((abs(dX)+abs(dY))*20), -dX, -dY, afTrackFall);
         // LOL copypasta: this is score for digging with... snowball
         //if value = 0 then
-        //    value:= - Metric(Targ.X, Targ.Y, EX, EY) div 64;
+        //    value:= - Metric(Targ.Point.X, Targ.Point.Y, EX, EY) div 64;
 
         if valueResult <= value then
             begin
@@ -321,11 +323,11 @@
             valueResult:= value
             end;
      end
-until (rTime > 4250);
+until (rTime > 5050 - Level * 800);
 TestSnowball:= valueResult
 end;
 
-function TestMolotov(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestMolotov(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var Vx, Vy, r: real;
     Score, EX, EY, valueResult: LongInt;
     TestTime: Longword;
@@ -339,8 +341,8 @@
 ap.ExplR:= 0;
 repeat
     inc(TestTime, 300);
-    Vx:= (Targ.X - meX) / TestTime;
-    Vy:= cGravityf * (TestTime div 2) - Targ.Y - meY / TestTime;
+    Vx:= (Targ.Point.X - meX) / TestTime;
+    Vy:= cGravityf * (TestTime div 2) - Targ.Point.Y - meY / TestTime;
     r:= sqr(Vx) + sqr(Vy);
     if not (r > 1) then
         begin
@@ -354,7 +356,7 @@
             dY:= dY + cGravityf;
             dec(t)
         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or
-               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 6))) or (t = 0);
+               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 6))) or (t = 0);
         EX:= trunc(x);
         EY:= trunc(y);
         if t < 50 then
@@ -372,11 +374,11 @@
             valueResult:= Score
             end;
         end
-until (TestTime > 4250);
+until (TestTime > 5050 - Level * 800);
 TestMolotov:= valueResult
 end;
 
-function TestGrenade(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestGrenade(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 const tDelta = 24;
 var Vx, Vy, r: real;
     Score, EX, EY, valueResult: LongInt;
@@ -391,8 +393,8 @@
 meY:= hwFloat2Float(Me^.Y);
 repeat
     inc(TestTime, 1000);
-    Vx:= (Targ.X - meX) / (TestTime + tDelta);
-    Vy:= cGravityf * ((TestTime + tDelta) div 2) - (Targ.Y - meY) / (TestTime + tDelta);
+    Vx:= (Targ.Point.X - meX) / (TestTime + tDelta);
+    Vy:= cGravityf * ((TestTime + tDelta) div 2) - (Targ.Point.Y - meY) / (TestTime + tDelta);
     r:= sqr(Vx) + sqr(Vy);
     if not (r > 1) then
         begin
@@ -406,7 +408,7 @@
             dY:= dY + cGravityf;
             dec(t)
         until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
-               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t = 0);
+               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (t = 0);
     EX:= trunc(x);
     EY:= trunc(y);
     if t < 50 then
@@ -418,8 +420,8 @@
 
     if (valueResult < Score) and (Score > 0) then
         begin
-        ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
-        ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
+        ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level * 3));
+        ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 20);
         ap.Time:= TestTime;
         ap.ExplR:= 100;
         ap.ExplX:= EX;
@@ -428,11 +430,11 @@
         end;
     end
 //until (Score > 204800) or (TestTime > 4000);
-until TestTime > 4000;
+until TestTime > 4500 - Level * 512;
 TestGrenade:= valueResult
 end;
 
-function TestClusterBomb(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestClusterBomb(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 const tDelta = 24;
 var Vx, Vy, r: real;
     Score, EX, EY, valueResult: LongInt;
@@ -448,11 +450,11 @@
 repeat
     inc(TestTime, 900);
     // Try to overshoot slightly, seems to pay slightly better dividends in terms of hitting cluster
-    if meX<Targ.X then
-        Vx:= ((Targ.X+10) - meX) / (TestTime + tDelta)
+    if meX<Targ.Point.X then
+        Vx:= ((Targ.Point.X+10) - meX) / (TestTime + tDelta)
     else
-        Vx:= ((Targ.X-10) - meX) / (TestTime + tDelta);
-    Vy:= cGravityf * ((TestTime + tDelta) div 2) - ((Targ.Y-50) - meY) / (TestTime + tDelta);
+        Vx:= ((Targ.Point.X-10) - meX) / (TestTime + tDelta);
+    Vy:= cGravityf * ((TestTime + tDelta) div 2) - ((Targ.Point.Y-50) - meY) / (TestTime + tDelta);
     r:= sqr(Vx)+sqr(Vy);
     if not (r > 1) then
         begin
@@ -466,7 +468,7 @@
         dY:= dY + cGravityf;
         dec(t)
     until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 5)) or
-           ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 5))) or (t = 0);
+           ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 5))) or (t = 0);
     EX:= trunc(x);
     EY:= trunc(y);
     if t < 50 then
@@ -474,9 +476,9 @@
     else
         Score:= BadTurn;
 
-     if valueResult < Score then
+     if Score > 0 then
         begin
-        ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
+        ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level * 2));
         ap.Power:= trunc(sqrt(r) * cMaxPower) + AIrndSign(random(Level) * 15);
         ap.Time:= TestTime div 1000 * 1000;
         ap.ExplR:= 90;
@@ -489,7 +491,7 @@
 TestClusterBomb:= valueResult
 end;
 
-function TestWatermelon(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestWatermelon(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 const tDelta = 24;
 var Vx, Vy, r: real;
     Score, EX, EY, valueResult: LongInt;
@@ -504,8 +506,8 @@
 meY:= hwFloat2Float(Me^.Y);
 repeat
     inc(TestTime, 900);
-    Vx:= (Targ.X - meX) / (TestTime + tDelta);
-    Vy:= cGravityf * ((TestTime + tDelta) div 2) - ((Targ.Y-50) - meY) / (TestTime + tDelta);
+    Vx:= (Targ.Point.X - meX) / (TestTime + tDelta);
+    Vy:= cGravityf * ((TestTime + tDelta) div 2) - ((Targ.Point.Y-50) - meY) / (TestTime + tDelta);
     r:= sqr(Vx)+sqr(Vy);
     if not (r > 1) then
         begin
@@ -519,7 +521,7 @@
             dY:= dY + cGravityf;
             dec(t)
        until (((Me = CurrentHedgehog^.Gear) and TestColl(trunc(x), trunc(y), 6)) or
-               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, trunc(x), trunc(y), 6))) or (t = 0);
+               ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, trunc(x), trunc(y), 6))) or (t = 0);
 
         EX:= trunc(x);
         EY:= trunc(y);
@@ -565,7 +567,7 @@
                 Solve:= 0
     end;
 
-function TestMortar(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestMortar(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 //const tDelta = 24;
 var Vx, Vy: real;
     Score, EX, EY: LongInt;
@@ -581,13 +583,13 @@
     if (Level > 2) then
         exit(BadTurn);
 
-    TestTime:= Solve(Targ.X, Targ.Y, trunc(meX), trunc(meY));
+    TestTime:= Solve(Targ.Point.X, Targ.Point.Y, trunc(meX), trunc(meY));
 
     if TestTime = 0 then
         exit(BadTurn);
 
-    Vx:= (Targ.X - meX) / TestTime;
-    Vy:= cGravityf * (TestTime div 2) - (Targ.Y - meY) / TestTime;
+    Vx:= (Targ.Point.X - meX) / TestTime;
+    Vy:= cGravityf * (TestTime div 2) - (Targ.Point.Y - meY) / TestTime;
 
     x:= meX;
     y:= meY;
@@ -600,14 +602,14 @@
         EX:= trunc(x);
         EY:= trunc(y);
     until (((Me = CurrentHedgehog^.Gear) and TestColl(EX, EY, 4)) or
-           ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, EX, EY, 4))) or (EY > cWaterLine);
+           ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, EX, EY, 4))) or (EY > cWaterLine);
 
     if (EY < cWaterLine) and (dY >= 0) then
         begin
         Score:= RateExplosion(Me, EX, EY, 91);
         if (Score = 0) then
-            if (dY > 0.15) then
-                Score:= - abs(Targ.Y - EY) div 32
+            if (dY > 0.15) and (Targ.Kind = gtHedgehog) and (Targ.Score > 0) then
+                Score:= - abs(Targ.Point.Y - EY) div 32
             else
                 Score:= BadTurn
         else if (Score < 0) then
@@ -616,7 +618,7 @@
     else
         Score:= BadTurn;
 
-    if BadTurn < Score then
+    if Score > 0 then
         begin
         ap.Angle:= DxDy2AttackAnglef(Vx, Vy) + AIrndSign(random(Level));
         ap.Power:= 1;
@@ -627,7 +629,7 @@
         end;
 end;
 
-function TestShotgun(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestShotgun(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 const
     MIN_RANGE =  80;
     MAX_RANGE = 400;
@@ -641,12 +643,12 @@
 ap.Power:= 1;
 x:= hwFloat2Float(Me^.X);
 y:= hwFloat2Float(Me^.Y);
-range:= Metric(trunc(x), trunc(y), Targ.X, Targ.Y);
+range:= Metric(trunc(x), trunc(y), Targ.Point.X, Targ.Point.Y);
 if ( range < MIN_RANGE ) or ( range > MAX_RANGE ) then
     exit(BadTurn);
 
-Vx:= (Targ.X - x) * 1 / 1024;
-Vy:= (Targ.Y - y) * 1 / 1024;
+Vx:= (Targ.Point.X - x) * 1 / 1024;
+Vy:= (Targ.Point.Y - y) * 1 / 1024;
 ap.Angle:= DxDy2AttackAnglef(Vx, -Vy);
 repeat
     x:= x + vX;
@@ -654,20 +656,20 @@
     rx:= trunc(x);
     ry:= trunc(y);
     if ((Me = CurrentHedgehog^.Gear) and TestColl(rx, ry, 2)) or
-        ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me, rx, ry, 2)) then
+        ((Me <> CurrentHedgehog^.Gear) and TestCollExcludingMe(Me^.Hedgehog^.Gear, rx, ry, 2)) then
     begin
         x:= x + vX * 8;
         y:= y + vY * 8;
         valueResult:= RateShotgun(Me, vX, vY, rx, ry);
 
-        if valueResult = 0 then
-            valueResult:= 1024 - Metric(Targ.X, Targ.Y, rx, ry) div 64
+        if (valueResult = 0) and (Targ.Kind = gtHedgehog) and (Targ.Score > 0) then
+            valueResult:= 1024 - Metric(Targ.Point.X, Targ.Point.Y, rx, ry) div 64
         else
             dec(valueResult, Level * 4000);
         // 27/20 is reuse bonus
         exit(valueResult * 27 div 20)
     end
-until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 4)
+until (Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) < 4)
     or (x < 0)
     or (y < 0)
     or (trunc(x) > LAND_WIDTH)
@@ -676,27 +678,26 @@
 TestShotgun:= BadTurn
 end;
 
-function TestDesertEagle(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-var Vx, Vy, x, y, t, dmgMod: real;
+function TestDesertEagle(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+var Vx, Vy, x, y, t: real;
     d: Longword;
     fallDmg, valueResult: LongInt;
 begin
-if Level > 4 then exit(BadTurn);
-dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
+if (Level > 4) or (Targ.Score < 0) or (Targ.Kind <> gtHedgehog) then exit(BadTurn);
 Level:= Level; // avoid compiler hint
-ap.ExplR:= 0;
+ap.ExplR:= 1;
 ap.Time:= 0;
 ap.Power:= 1;
 
 x:= hwFloat2Float(Me^.X);
 y:= hwFloat2Float(Me^.Y);
 
-if Abs(trunc(x) - Targ.X) + Abs(trunc(y) - Targ.Y) < 20 then
+if Abs(trunc(x) - Targ.Point.X) + Abs(trunc(y) - Targ.Point.Y) < 20 then
     exit(BadTurn);
 
-t:= 2 / sqrt(sqr(Targ.X - x)+sqr(Targ.Y-y));
-Vx:= (Targ.X - x) * t;
-Vy:= (Targ.Y - y) * t;
+t:= 2 / sqrt(sqr(Targ.Point.X - x)+sqr(Targ.Point.Y-y));
+Vx:= (Targ.Point.X - x) * t;
+Vy:= (Targ.Point.Y - y) * t;
 ap.Angle:= DxDy2AttackAnglef(Vx, -Vy);
 d:= 0;
 
@@ -706,47 +707,40 @@
     if ((trunc(x) and LAND_WIDTH_MASK) = 0)and((trunc(y) and LAND_HEIGHT_MASK) = 0)
     and (Land[trunc(y), trunc(x)] <> 0) then
         inc(d);
-until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 5)
+until (Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) < 5)
     or (x < 0)
     or (y < 0)
     or (trunc(x) > LAND_WIDTH)
     or (trunc(y) > LAND_HEIGHT)
     or (d > 48);
 
-if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 5 then
-    begin
-    fallDmg:= TraceShoveFall(Targ.X, Targ.Y, vX * 0.00125 * 20, vY * 0.00125 * 20);
-    if fallDmg < 0 then
-        valueResult:= 204800
-    else valueResult:= Max(0, (4 - d div 12) * trunc((7 + fallDmg) * dmgMod) * 1024)
-    end
-else
-    valueResult:= BadTurn;
+if Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) < 5 then
+     valueResult:= RateShove(Me, Targ.Point.X, Targ.Point.Y, 1, 7, 20, vX*0.125, vY*0.125, afTrackFall)
+else valueResult:= BadTurn;
 TestDesertEagle:= valueResult
 end;
 
 
-function TestSniperRifle(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
-var Vx, Vy, x, y, t, dmg, dmgMod: real;
+function TestSniperRifle(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
+var Vx, Vy, x, y, t, dmg: real;
     d: Longword;
     fallDmg: LongInt;
 begin
-if Level > 3 then exit(BadTurn);
-dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
+if (Level > 3) or (Targ.Score < 0) or (Targ.Kind <> gtHedgehog) then exit(BadTurn);
 Level:= Level; // avoid compiler hint
 ap.ExplR:= 0;
 ap.Time:= 0;
 ap.Power:= 1;
 x:= hwFloat2Float(Me^.X);
 y:= hwFloat2Float(Me^.Y);
-if Abs(trunc(x) - Targ.X) + Abs(trunc(y) - Targ.Y) < 40 then
+if Abs(trunc(x) - Targ.Point.X) + Abs(trunc(y) - Targ.Point.Y) < 40 then
     exit(BadTurn);
 
-dmg:= sqrt(sqr(Targ.X - x)+sqr(Targ.Y-y));
+dmg:= sqrt(sqr(Targ.Point.X - x)+sqr(Targ.Point.Y-y));
 t:= 1.5 / dmg;
 dmg:= dmg * 0.025; // div 40
-Vx:= (Targ.X - x) * t;
-Vy:= (Targ.Y - y) * t;
+Vx:= (Targ.Point.X - x) * t;
+Vy:= (Targ.Point.Y - y) * t;
 ap.Angle:= DxDy2AttackAnglef(Vx, -Vy);
 d:= 0;
 
@@ -756,27 +750,20 @@
     if ((trunc(x) and LAND_WIDTH_MASK) = 0)and((trunc(y) and LAND_HEIGHT_MASK) = 0)
     and (Land[trunc(y), trunc(x)] <> 0) then
         inc(d);
-until (Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 4)
+until (Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) < 4)
     or (x < 0)
     or (y < 0)
     or (trunc(x) > LAND_WIDTH)
     or (trunc(y) > LAND_HEIGHT)
     or (d > 22);
 
-if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 4 then
-    begin
-    fallDmg:= TraceShoveFall(Targ.X, Targ.Y, vX * 0.00166 * dmg, vY * 0.00166 * dmg);
-    if fallDmg < 0 then
-        TestSniperRifle:= BadTurn
-    else
-        TestSniperRifle:= Max(0, trunc((dmg + fallDmg) * dmgMod) * 1024)
-    end
-else
-    TestSniperRifle:= BadTurn
+if Abs(Targ.Point.X - trunc(x)) + Abs(Targ.Point.Y - trunc(y)) < 4 then
+     TestSniperRifle:= RateShove(Me, Targ.Point.X, Targ.Point.Y, 1, trunc(dmg), 20, vX*0.166, vY*0.166, afTrackFall)
+else TestSniperRifle:= BadTurn;
 end;
 
 
-function TestBaseballBat(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestBaseballBat(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var valueResult, a, v1, v2: LongInt;
     x, y, trackFall: LongInt;
     dx, dy: real;
@@ -800,10 +787,10 @@
         dx:= sin(a / cMaxAngle * pi) * 0.5;
         dy:= cos(a / cMaxAngle * pi) * 0.5;
 
-        v1:= RateShove(x - 10, y + 2
+        v1:= RateShove(Me, x - 10, y + 2
                 , 32, 30, 115
                 , -dx, -dy, trackFall);
-        v2:= RateShove(x + 10, y + 2
+        v2:= RateShove(Me, x + 10, y + 2
                 , 32, 30, 115
                 , dx, -dy, trackFall);
         if (v1 > valueResult) or (v2 > valueResult) then
@@ -828,7 +815,7 @@
     TestBaseballBat:= valueResult;
 end;
 
-function TestFirePunch(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestFirePunch(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var valueResult, v1, v2, i: LongInt;
     x, y, trackFall: LongInt;
 begin
@@ -846,11 +833,11 @@
     v1:= 0;
     for i:= 0 to 8 do
         begin
-        v1:= v1 + RateShove(x - 5, y - 10 * i
+        v1:= v1 + RateShove(Me, x - 5, y - 10 * i
                 , 19, 30, 40
                 , -0.45, -0.9, trackFall or afSetSkip);
         end;
-    v1:= v1 + RateShove(x - 5, y - 90
+    v1:= v1 + RateShove(Me, x - 5, y - 90
             , 19, 30, 40
             , -0.45, -0.9, trackFall);
 
@@ -859,11 +846,11 @@
     v2:= 0;
     for i:= 0 to 8 do
         begin
-        v2:= v2 + RateShove(x + 5, y - 10 * i
+        v2:= v2 + RateShove(Me, x + 5, y - 10 * i
                 , 19, 30, 40
                 , 0.45, -0.9, trackFall or afSetSkip);
         end;
-    v2:= v2 + RateShove(x + 5, y - 90
+    v2:= v2 + RateShove(Me, x + 5, y - 90
             , 19, 30, 40
             , 0.45, -0.9, trackFall);
 
@@ -886,7 +873,7 @@
 end;
 
 
-function TestWhip(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestWhip(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var valueResult, v1, v2: LongInt;
     x, y, trackFall: LongInt;
 begin
@@ -905,19 +892,19 @@
     {first RateShove checks farthermost of two whip's AmmoShove attacks
     to encourage distant attacks (damaged hog is excluded from view of second
     RateShove call)}
-    v1:= RateShove(x - 13, y
+    v1:= RateShove(Me, x - 13, y
             , 30, 30, 25
             , -1, -0.8, trackFall or afSetSkip);
     v1:= v1 +
-        RateShove(x - 2, y
+        RateShove(Me, x - 2, y
             , 30, 30, 25
             , -1, -0.8, trackFall);
     // now try opposite direction
-    v2:= RateShove(x + 13, y
+    v2:= RateShove(Me, x + 13, y
             , 30, 30, 25
             , 1, -0.8, trackFall or afSetSkip);
     v2:= v2 +
-        RateShove(x + 2, y
+        RateShove(Me, x + 2, y
             , 30, 30, 25
             , 1, -0.8, trackFall);
 
@@ -941,7 +928,7 @@
     TestWhip:= valueResult;
 end;
 
-function TestKamikaze(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestKamikaze(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 const step = 8;
 var valueResult, i, v, tx: LongInt;
     trackFall: LongInt;
@@ -963,7 +950,7 @@
 
     x:= hwFloat2Float(Me^.X);
     y:= hwFloat2Float(Me^.Y);
-    d:= sqrt(sqr(Targ.X - x) + sqr(Targ.Y - y));
+    d:= sqrt(sqr(Targ.Point.X - x) + sqr(Targ.Point.Y - y));
     if d < 10 then
         begin
         dx:= 0;
@@ -973,8 +960,8 @@
     else
         begin
         t:= step / d;
-        dx:= (Targ.X - x) * t;
-        dy:= (Targ.Y - y) * t;
+        dx:= (Targ.Point.X - x) * t;
+        dy:= (Targ.Point.Y - y) * t;
 
         ap.Angle:= DxDy2AttackAnglef(dx, -dy)
         end;
@@ -984,7 +971,7 @@
     for i:= 0 to 512 div step - 2 do
         begin
         valueResult:= valueResult +
-            RateShove(trunc(x), trunc(y)
+            RateShove(Me, trunc(x), trunc(y)
                 , 30, 30, 25
                 , cx, -0.9, trackFall or afSetSkip);
 
@@ -996,14 +983,14 @@
         x:= hwFloat2Float(Me^.X);
         y:= hwFloat2Float(Me^.Y);
         tx:= trunc(x);
-        v:= RateShove(tx, trunc(y)
+        v:= RateShove(Me, tx, trunc(y)
                 , 30, 30, 25
                 , -cx, -0.9, trackFall);
         for i:= 1 to 512 div step - 2 do
             begin
             y:= y + dy;
             v:= v +
-                RateShove(tx, trunc(y)
+                RateShove(Me, tx, trunc(y)
                     , 30, 30, 25
                     , -cx, -0.9, trackFall or afSetSkip);
             end
@@ -1014,7 +1001,7 @@
         valueResult:= v
         end;
 
-    v:= RateShove(trunc(x), trunc(y)
+    v:= RateShove(Me, trunc(x), trunc(y)
             , 30, 30, 25
             , cx, -0.9, trackFall);
     valueResult:= valueResult + v - KillScore * friendlyfactor div 100 * 1024;
@@ -1025,7 +1012,7 @@
     TestKamikaze:= valueResult;
 end;
 
-function TestHammer(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestHammer(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var rate: LongInt;
 begin
 Level:= Level; // avoid compiler hint
@@ -1042,7 +1029,7 @@
 TestHammer:= rate;
 end;
 
-function TestAirAttack(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestAirAttack(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 const cShift = 4;
 var bombsSpeed, X, Y, dY: real;
     b: array[0..9] of boolean;
@@ -1056,12 +1043,12 @@
     exit(BadTurn);
 
 ap.Angle:= 0;
-ap.AttackPutX:= Targ.X;
-ap.AttackPutY:= Targ.Y;
+ap.AttackPutX:= Targ.Point.X;
+ap.AttackPutY:= Targ.Point.Y;
 
 bombsSpeed:= hwFloat2Float(cBombsSpeed);
-X:= Targ.X - 135 - cShift; // hh center - cShift
-X:= X - bombsSpeed * sqrt(((Targ.Y + 128) * 2) / cGravityf);
+X:= Targ.Point.X - 135 - cShift; // hh center - cShift
+X:= X - bombsSpeed * sqrt(((Targ.Point.Y + 128) * 2) / cGravityf);
 Y:= -128;
 dY:= 0;
 
@@ -1093,7 +1080,7 @@
 
 for i:= 0 to 5 do inc(valueResult, dmg[i]);
 t:= valueResult;
-ap.AttackPutX:= Targ.X - 60;
+ap.AttackPutX:= Targ.Point.X - 60;
 
 for i:= 0 to 3 do
     begin
@@ -1102,7 +1089,7 @@
     if t > valueResult then
         begin
         valueResult:= t;
-        ap.AttackPutX:= Targ.X - 30 - cShift + i * 30
+        ap.AttackPutX:= Targ.Point.X - 30 - cShift + i * 30
         end
     end;
 
@@ -1112,7 +1099,7 @@
 end;
 
 
-function TestTeleport(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestTeleport(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var
     i, failNum: longword;
     maxTop: longword;
@@ -1125,15 +1112,15 @@
         begin
         if Me^.Health <= 100  then
             begin
-            maxTop := Targ.Y - cHHRadius * 2;
+            maxTop := Targ.Point.Y - cHHRadius * 2;
 
-            while (not TestColl(Targ.X, maxTop, cHHRadius)) and (maxTop > topY + cHHRadius * 2 + 1) do
+            while not TestColl(Targ.Point.X, maxTop, cHHRadius) and (maxTop > topY + cHHRadius * 2 + 1) do
                 dec(maxTop, cHHRadius*2);
-            if not TestColl(Targ.X, maxTop + cHHRadius, cHHRadius) then
+            if not TestColl(Targ.Point.X, maxTop + cHHRadius, cHHRadius) then
                 begin
-                ap.AttackPutX := Targ.X;
+                ap.AttackPutX := Targ.Point.X;
                 ap.AttackPutY := maxTop + cHHRadius;
-                TestTeleport := Targ.Y - maxTop;
+                TestTeleport := Targ.Point.Y - maxTop;
                 end;
             end;
         end
@@ -1176,7 +1163,7 @@
     end;
 end;
 
-function TestCake(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt;
+function TestCake(Me: PGear; Targ: TTarget; Level: LongInt; var ap: TAttackParams): LongInt;
 var valueResult, v1, v2: LongInt;
     cake: TGear;
 begin