--- a/hedgewars/uAIMisc.pas Thu Apr 04 14:37:19 2013 +0200
+++ b/hedgewars/uAIMisc.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
@@ -30,14 +30,18 @@
BadTurn = Low(LongInt) div 4;
-type TTarget = record
+type TTarget = record // starting to look more and more like a gear
Point: TPoint;
- Score: LongInt;
- skip, matters: boolean;
+ Score, Radius: LongInt;
+ State: LongWord;
+ Density: real;
+ skip, matters, dead: boolean;
+ Kind: TGearType;
end;
TTargets = record
Count: Longword;
- ar: array[0..Pred(cMaxHHs)] of TTarget;
+ ar: array[0..Pred(256)] of TTarget;
+ reset: boolean;
end;
TJumpType = (jmpNone, jmpHJump, jmpLJump);
TGoInfo = record
@@ -65,6 +69,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;
@@ -73,12 +78,11 @@
function TestColl(x, y, r: LongInt): boolean; inline;
function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline;
-function TraceShoveFall(x, y, dX, dY: Real): LongInt;
-function TestCollWithLand(x, y, r: LongInt): boolean; inline;
function RateExplosion(Me: PGear; x, y, r: LongInt): LongInt; inline;
-function RateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
-function RateShove(x, y, r, power, kick: LongInt; gdX, gdY: real; 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(Me: PGear; x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
function RateHammer(Me: PGear): LongInt;
@@ -94,52 +98,82 @@
const KillScore = 200;
var friendlyfactor: LongInt = 300;
+var dmgMod: real = 1.0;
implementation
uses uCollisions, uVariables, uUtils, uLandTexture, uGearsUtils;
-var
+var
KnownExplosion: record
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;
+ Gear: PGear;
begin
Targets.Count:= 0;
+Targets.reset:= false;
f:= 0;
e:= 0;
-for t:= 0 to Pred(TeamsCount) do
- with TeamsArray[t]^ do
- if not hasGone then
+Gear:= GearsList;
+while Gear <> nil do
+ begin
+ if (((Gear^.Kind = gtHedgehog) and
+ (Gear <> ThinkingHH) and
+ (Gear^.Health > Gear^.Damage) and
+ not(Gear^.Hedgehog^.Team^.hasgone)) or
+ ((Gear^.Kind = gtExplosives) and
+ (Gear^.Health > Gear^.Damage)) or
+ ((Gear^.Kind = gtMine) and
+ (Gear^.Health = 0) and
+ (Gear^.Damage < 35))
+ ) and
+ (Targets.Count < 256) then
+ begin
+ with Targets.ar[Targets.Count] do
begin
- for i:= 0 to cMaxHHIndex do
- if (Hedgehogs[i].Gear <> nil)
- and (Hedgehogs[i].Gear <> ThinkingHH)
- and (Hedgehogs[i].Gear^.Health > Hedgehogs[i].Gear^.Damage)
- then
+ skip:= false;
+ dead:= false;
+ Kind:= Gear^.Kind;
+ Radius:= Gear^.Radius;
+ Density:= hwFloat2Float(Gear^.Density)/3;
+ State:= Gear^.State;
+ matters:= (Gear^.AIHints and aihDoesntMatter) = 0;
+
+ Point.X:= hwRound(Gear^.X);
+ Point.Y:= hwRound(Gear^.Y);
+ if (Gear^.Kind = gtHedgehog) then
+ begin
+ if (Gear^.Hedgehog^.Team^.Clan = CurrentTeam^.Clan) then
begin
- with Targets.ar[Targets.Count], Hedgehogs[i] do
- begin
- skip:= false;
- matters:= (Hedgehogs[i].Gear^.AIHints and aihDoesntMatter) = 0;
-
- Point.X:= hwRound(Gear^.X);
- Point.Y:= hwRound(Gear^.Y);
- if Clan <> CurrentTeam^.Clan then
- begin
- Score:= Gear^.Health - Gear^.Damage;
- inc(e)
- end else
- begin
- Score:= Gear^.Damage - Gear^.Health;
- inc(f)
- end
- end;
- inc(Targets.Count)
+ Score:= Gear^.Damage - Gear^.Health;
+ inc(f)
+ end
+ else
+ begin
+ Score:= Gear^.Health - Gear^.Damage;
+ inc(e)
end;
+ end
+ else if Gear^.Kind = gtExplosives then
+ Score:= Gear^.Health - Gear^.Damage
+ else if Gear^.Kind = gtMine then
+ Score:= max(0,35-Gear^.Damage);
end;
+ inc(Targets.Count)
+ end;
+ Gear:= Gear^.NextGear
+ end;
if e > f then friendlyfactor:= 300 + (e - f) * 30
else friendlyfactor:= max(30, 300 - f * 80 div max(1,e))
@@ -185,24 +219,24 @@
gtFlame:
if (Gear^.State and gsttmpFlag) <> 0 then
AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 20, -50);
-// avoid mines unless they are very likely to be duds, or are duds. also avoid if they are about to blow
+// avoid mines unless they are very likely to be duds, or are duds. also avoid if they are about to blow
gtMine:
if ((Gear^.State and gstAttacking) = 0) and (((cMineDudPercent < 90) and (Gear^.Health <> 0))
or (isAfterAttack and (Gear^.Health = 0) and (Gear^.Damage > 30))) then
AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 50, -50)
else if (Gear^.State and gstAttacking) <> 0 then
AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 100, -50); // mine is on
-
+
gtExplosives:
if isAfterAttack then
AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 75, -60 + Gear^.Health);
-
+
gtSMine:
AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 50, -30);
-
+
gtDynamite:
AddBonus(hwRound(Gear^.X), hwRound(Gear^.Y), 150, -75);
-
+
gtHedgehog:
begin
if Gear^.Damage >= Gear^.Health then
@@ -260,6 +294,58 @@
RatePlace:= rate;
end;
+function CheckBounds(x, y, r: Longint): boolean; inline;
+begin
+ CheckBounds := (((x-r) and LAND_WIDTH_MASK) = 0) and
+ (((x+r) and LAND_WIDTH_MASK) = 0) and
+ (((y-r) and LAND_HEIGHT_MASK) = 0) and
+ (((y+r) and LAND_HEIGHT_MASK) = 0);
+end;
+
+
+function TestCollWithEverything(x, y, r: LongInt): boolean; inline;
+begin
+ if not CheckBounds(x, y, r) then
+ exit(false);
+
+ if (Land[y-r, x-r] <> 0) or
+ (Land[y+r, x-r] <> 0) or
+ (Land[y-r, x+r] <> 0) or
+ (Land[y+r, x+r] <> 0) then
+ exit(true);
+
+ TestCollWithEverything := false;
+end;
+
+function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
+begin
+ if not CheckBounds(x, y, r) then
+ exit(false);
+
+ if (Land[y-r, x-r] > lfAllObjMask) or
+ (Land[y+r, x-r] > lfAllObjMask) or
+ (Land[y-r, x-r] > lfAllObjMask) or
+ (Land[y+r, x+r] > lfAllObjMask) then
+ exit(true);
+
+ TestCollExcludingObjects:= false;
+end;
+
+function TestColl(x, y, r: LongInt): boolean; inline;
+begin
+ if not CheckBounds(x, y, r) then
+ exit(false);
+
+ if (Land[y-r, x-r] and lfNotCurrentMask <> 0) or
+ (Land[y+r, x-r] and lfNotCurrentMask <> 0) or
+ (Land[y+r, x-r] and lfNotCurrentMask <> 0) or
+ (Land[y+r, x+r] and lfNotCurrentMask <> 0) then
+ exit(true);
+
+ TestColl:= false;
+end;
+
+
// Wrapper to test various approaches. If it works reasonably, will just replace.
// Right now, converting to hwFloat is a tad inefficient since the x/y were hwFloat to begin with...
function TestCollExcludingMe(Me: PGear; x, y, r: LongInt): boolean; inline;
@@ -270,155 +356,134 @@
MeX:= hwRound(Me^.X);
MeY:= hwRound(Me^.Y);
// We are still inside the hog. Skip radius test
- if ((((x-MeX)*(x-MeX)) + ((y-MeY)*(y-MeY))) < 256) and (Land[y, x] <= lfAllObjMask) and ((Land[y, x] and lfObjMask) < 2) then
+ if ((sqr(x-MeX) + sqr(y-MeY)) < 256) and (Land[y, x] and lfObjMask = 0) then
exit(false);
end;
- TestCollExcludingMe:= TestColl(x, y, r)
-end;
-
-function TestCollExcludingObjects(x, y, r: LongInt): boolean; inline;
-var b: boolean;
-begin
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] > lfAllObjMask);
- if b then
- exit(true);
-
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] > lfAllObjMask);
- if b then
- exit(true);
-
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] > lfAllObjMask);
- if b then
- exit(true);
-
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] > lfAllObjMask);
- if b then
- exit(true);
-
- TestCollExcludingObjects:= false;
+ TestCollExcludingMe:= TestCollWithEverything(x, y, r)
end;
-function TestColl(x, y, r: LongInt): boolean; inline;
-var b: boolean;
-begin
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] and lfNotCurrentMask <> 0);
- if b then
- exit(true);
-
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] and lfNotCurrentMask <> 0);
- if b then
- exit(true);
-
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] and lfNotCurrentMask <> 0);
- if b then
- exit(true);
-
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] and lfNotCurrentMask <> 0);
- if b then
- exit(true);
-
- TestColl:= false;
-end;
+
-function TestCollWithLand(x, y, r: LongInt): boolean; inline;
-var b: boolean;
-begin
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x-r] > lfAllObjMask);
- if b then
- exit(true);
-
- b:= (((x-r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x-r] > lfAllObjMask);
- if b then
- exit(true);
-
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y-r) and LAND_HEIGHT_MASK) = 0) and (Land[y-r, x+r] > lfAllObjMask);
- if b then
- exit(true);
-
- b:= (((x+r) and LAND_WIDTH_MASK) = 0) and (((y+r) and LAND_HEIGHT_MASK) = 0) and (Land[y+r, x+r] > lfAllObjMask);
- if b then
- exit(true);
-
- TestCollWithLand:= false;
-end;
-
-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; Target: TTarget): LongInt;
var skipLandCheck: boolean;
- rCorner: real;
+ rCorner, dxdy, odX, odY: real;
dmg: LongInt;
begin
+ odX:= dX;
+ odY:= dY;
skipLandCheck:= true;
- if x - eX < 0 then dX:= -dX;
- if y - eY < 0 then dY:= -dY;
// ok. attempt approximate search for an unbroken trajectory into water. if it continues far enough, assume out of map
rCorner:= r * 0.75;
while true do
- begin
+ begin
x:= x + dX;
y:= y + dY;
dY:= dY + cGravityf;
skipLandCheck:= skipLandCheck and (r <> 0) and (abs(eX-x) + abs(eY-y) < r) and ((abs(eX-x) < rCorner) or (abs(eY-y) < rCorner));
- if (not skipLandCheck) and TestCollWithLand(trunc(x), trunc(y), cHHRadius) then
- begin
- if 0.4 < dY then
- begin
- dmg := 1 + trunc((abs(dY) - 0.4) * 70);
- if dmg >= 1 then
- exit(dmg);
+ if not skipLandCheck and TestCollExcludingObjects(trunc(x), trunc(y), Target.Radius) then
+ with Target do
+ begin
+ if (Kind = gtHedgehog) and (0.4 < dY) then
+ begin
+ dmg := 1 + trunc((dY - 0.4) * 70);
+ exit(dmg)
+ end
+ else
+ begin
+ dxdy:= abs(dX)+abs(dY);
+ if ((Kind = gtMine) and (dxdy > 0.35)) or
+ ((Kind = gtExplosives) and
+ (((State and gstTmpFlag <> 0) and (dxdy > 0.35)) or
+ ((State and gstTmpFlag = 0) and
+ ((abs(odX) > 0.15) or ((abs(odY) > 0.15) and
+ (abs(odX) > 0.02))) and (dxdy > 0.35)))) then
+ begin
+ dmg := trunc(dxdy * 25);
+ exit(dmg)
+ end
+ else if (Kind = gtExplosives) and not((abs(odX) > 0.15) or ((abs(odY) > 0.15) and (abs(odX) > 0.02))) and (dY > 0.2) then
+ begin
+ dmg := trunc(dy * 70);
+ exit(dmg)
+ end
+ end;
+ exit(0)
end;
- exit(0)
- end;
- if (y > cWaterLine) or (x > 4096) or (x < 0) then
- exit(-1);
- end;
+ if (y > cWaterLine) or (x > rightX) or (x < leftX) then exit(-1)
+ end
end;
-function TraceShoveFall(x, y, dX, dY: Real): LongInt;
+function TraceShoveFall(var x, y: Real; dX, dY: Real; Target: TTarget): LongInt;
var dmg: LongInt;
+ dxdy, odX, odY: real;
begin
+ odX:= dX;
+ odY:= dY;
//v:= random($FFFFFFFF);
while true do
- begin
+ begin
x:= x + dX;
y:= y + dY;
dY:= dY + cGravityf;
-{ if ((trunc(y) and LAND_HEIGHT_MASK) = 0) and ((trunc(x) and LAND_WIDTH_MASK) = 0) then
+{ if ((trunc(y) and LAND_HEIGHT_MASK) = 0) and ((trunc(x) and LAND_WIDTH_MASK) = 0) then
begin
LandPixels[trunc(y), trunc(x)]:= v;
UpdateLandTexture(trunc(X), 1, trunc(Y), 1, true);
end;}
-
- // consider adding dX/dY calc here for fall damage
- if TestCollExcludingObjects(trunc(x), trunc(y), cHHRadius) then
- begin
- if 0.4 < dY then
- begin
- dmg := 1 + trunc((abs(dY) - 0.4) * 70);
- if dmg >= 1 then
+ if TestCollExcludingObjects(trunc(x), trunc(y), Target.Radius) then
+ with Target do
+ begin
+ if (Kind = gtHedgehog) and (0.4 < dY) then
+ begin
+ dmg := trunc((dY - 0.4) * 70);
exit(dmg);
- end;
+ end
+ else
+ begin
+ dxdy:= abs(dX)+abs(dY);
+ if ((Kind = gtMine) and (dxdy > 0.4)) or
+ ((Kind = gtExplosives) and
+ (((State and gstTmpFlag <> 0) and (dxdy > 0.4)) or
+ ((State and gstTmpFlag = 0) and
+ ((abs(odX) > 0.15) or ((abs(odY) > 0.15) and
+ (abs(odX) > 0.02))) and (dxdy > 0.35)))) then
+ begin
+ dmg := trunc(dxdy * 50);
+ exit(dmg)
+ end
+ else if (Kind = gtExplosives) and not((abs(odX) > 0.15) or ((abs(odY) > 0.15) and (abs(odX) > 0.02))) and (dY > 0.2) then
+ begin
+ dmg := trunc(dy * 70);
+ exit(dmg)
+ end
+ end;
exit(0)
end;
- if (y > cWaterLine) or (x > 4096) or (x < 0) then
+ if (y > cWaterLine) or (x > rightX) or (x < leftX) then
// returning -1 for drowning so it can be considered in the Rate routine
exit(-1)
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;
-var i, fallDmg, dmg, dmgBase, rate, erasure: LongInt;
- dX, dY, dmgMod: real;
+function RealRateExplosion(Me: PGear; x, y, r: LongInt; Flags: LongWord): LongInt;
+var i, fallDmg, dmg, dmgBase, rate, subrate, erasure: LongInt;
+ pX, pY, dX, dY: real;
hadSkips: boolean;
begin
fallDmg:= 0;
-dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
rate:= 0;
// add our virtual position
with Targets.ar[Targets.Count] do
@@ -427,10 +492,12 @@
Point.y:= hwRound(Me^.Y);
skip:= false;
matters:= true;
+ Kind:= gtHedgehog;
+ Density:= 1;
+ Radius:= cHHRadius;
Score:= - ThinkingHH^.Health
end;
// rate explosion
-dmgBase:= r + cHHRadius div 2;
if (Flags and afErasesLand <> 0) and (GameFlags and gfSolidLand = 0) then erasure:= r
else erasure:= 0;
@@ -438,98 +505,169 @@
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;
+ dmgBase:= r + Radius div 2;
+ 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
- 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)
+ pX:= Point.x;
+ pY:= Point.y;
+ fallDmg:= 0;
+ if (Flags and afTrackFall <> 0) and (Score > 0) and (dmg < Score) then
+ begin
+ dX:= (0.005 * dmg + 0.01) / Density;
+ dY:= dX;
+ if (Kind = gtExplosives) and (State and gstTmpFlag = 0) and
+ (((abs(dY) > 0.15) and (abs(dX) < 0.02)) or
+ ((abs(dY) < 0.15) and (abs(dX) < 0.15))) then
+ dX:= 0;
+
+ if pX - x < 0 then dX:= -dX;
+ if pY - y < 0 then dY:= -dY;
+
+ 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, Targets.ar[i]) * dmgMod)
+ else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod)
+ end;
+ if Kind = gtHedgehog then
+ begin
+ if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
+ begin
+ 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
+ end
+ else if (dmg+fallDmg) >= abs(Score) then
+ begin
+ dead:= true;
+ Targets.reset:= true;
+ if dX < 0.035 then
+ begin
+ subrate:= RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or (Flags and afTrackFall));
+ if abs(subrate) > 2000 then inc(Rate,subrate)
+ end;
+ 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
+ begin
+ if Score > 0 then
+ inc(rate, (dmg + fallDmg) * 1024)
+ else dec(rate, (dmg + fallDmg) * friendlyfactor div 100 * 1024)
+ end
+ end
+ else if (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then
+ begin
+ dead:= true;
+ Targets.reset:= true;
+ if Kind = gtExplosives then
+ subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or (Flags and afTrackFall))
+ else subrate:= RealRateExplosion(Me, round(pX), round(pY), 101, afErasesLand or (Flags and afTrackFall));
+ if abs(subrate) > 2000 then inc(Rate,subrate);
+ end
+ 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;
-var i, fallDmg, dmg, rate: LongInt;
- dX, dY, dmgMod: real;
+function RateShove(Me: PGear; x, y, r, power, kick: LongInt; gdX, gdY: real; Flags: LongWord): LongInt;
+var i, fallDmg, dmg, rate, subrate: LongInt;
+ dX, dY, pX, pY: real;
begin
fallDmg:= 0;
dX:= gdX * 0.01 * kick;
dY:= gdY * 0.01 * kick;
-dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
rate:= 0;
for i:= 0 to Pred(Targets.Count) do
with Targets.ar[i] do
- if skip then
- if (Flags and afSetSkip = 0) then skip:= false else {still skip}
- else if matters then
- begin
- dmg:= 0;
- if abs(Point.x - x) + abs(Point.y - y) < r then
- dmg:= r - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)));
-
- if dmg > 0 then
+ if skip then
+ begin
+ if Flags and afSetSkip = 0 then skip:= false
+ end
+ else if matters then
begin
- if (Flags and afSetSkip <> 0) then skip:= true;
- if (Flags and afTrackFall <> 0) and (Score > 0) then
- fallDmg:= trunc(TraceShoveFall(Point.x, Point.y - 2, dX, dY) * 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 power+fallDmg >= abs(Score) then
- if Score > 0 then
- inc(rate, KillScore)
- else
- dec(rate, KillScore * friendlyfactor div 100)
- else
- if Score > 0 then
- inc(rate, power+fallDmg)
- else
- dec(rate, (power+fallDmg) * friendlyfactor div 100)
+ dmg:= 0;
+ if abs(Point.x - x) + abs(Point.y - y) < r then
+ dmg:= r - trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)));
+
+ if dmg > 0 then
+ begin
+ pX:= Point.x;
+ pY:= Point.y-2;
+ fallDmg:= 0;
+ if (Flags and afSetSkip <> 0) then skip:= true;
+ if not(dead) and (Flags and afTrackFall <> 0) and (Score > 0) and (power < Score) then
+ if (Kind = gtExplosives) and (State and gstTmpFlag = 0) and
+ (((abs(dY) > 0.15) and (abs(dX) < 0.02)) or
+ ((abs(dY) < 0.15) and (abs(dX) < 0.15))) then
+ fallDmg:= trunc(TraceShoveFall(pX, pY, 0, dY, Targets.ar[i]) * dmgMod)
+ else
+ fallDmg:= trunc(TraceShoveFall(pX, pY, dX, dY, Targets.ar[i]) * dmgMod);
+ if Kind = gtHedgehog then
+ begin
+ if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
+ begin
+ 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
+ end
+ else if power+fallDmg >= abs(Score) then
+ begin
+ dead:= true;
+ Targets.reset:= true;
+ if dX < 0.035 then
+ begin
+ subrate:= RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or afTrackFall);
+ if abs(subrate) > 2000 then inc(Rate,subrate div 1024)
+ end;
+ if Score > 0 then
+ inc(rate, KillScore)
+ else
+ dec(rate, KillScore * friendlyfactor div 100)
+ end
+ else
+ begin
+ if Score > 0 then
+ inc(rate, power+fallDmg)
+ else
+ dec(rate, (power+fallDmg) * friendlyfactor div 100)
+ end
+ end
+ else if (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then
+ begin
+ dead:= true;
+ Targets.reset:= true;
+ if Kind = gtExplosives then
+ subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or (Flags and afTrackFall))
+ else subrate:= RealRateExplosion(Me, round(pX), round(pY), 101, afErasesLand or (Flags and afTrackFall));
+ if abs(subrate) > 2000 then inc(Rate,subrate div 1024);
+ end
+ end
end;
- end;
-RateShove:= rate * 1024
+RateShove:= rate * 1024;
+ResetTargets
end;
function RateShotgun(Me: PGear; gdX, gdY: real; x, y: LongInt): LongInt;
-var i, dmg, fallDmg, baseDmg, rate, erasure: LongInt;
- dX, dY, dmgMod: real;
+var i, dmg, fallDmg, baseDmg, rate, subrate, erasure: LongInt;
+ pX, pY, dX, dY: real;
hadSkips: boolean;
begin
-dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent;
rate:= 0;
gdX:= gdX * 0.01;
gdY:= gdX * 0.01;
@@ -540,6 +678,9 @@
Point.y:= hwRound(Me^.Y);
skip:= false;
matters:= true;
+ Kind:= gtHedgehog;
+ Density:= 1;
+ Radius:= cHHRadius;
Score:= - ThinkingHH^.Health
end;
// rate shot
@@ -551,48 +692,80 @@
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
- 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)
- else
- dec(rate, KillScore * friendlyfactor div 100)
- else
- if Score > 0 then
- inc(rate, dmg+fallDmg)
- else
- dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
+ 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
+ if not(dead) and (Score > 0) and (dmg < Score) then
+ begin
+ pX:= Point.x;
+ pY:= Point.y;
+ dX:= gdX * dmg / Density;
+ dY:= gdY * dmg / Density;
+ if dX < 0 then dX:= dX - 0.01
+ else dX:= dX + 0.01;
+ if (Kind = gtExplosives) and (State and gstTmpFlag = 0) and
+ (((abs(dY) > 0.15) and (abs(dX) < 0.02)) or
+ ((abs(dY) < 0.15) and (abs(dX) < 0.15))) then
+ dX:= 0;
+ 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, Targets.ar[i]) * dmgMod)
+ else fallDmg:= trunc(TraceFall(x, y, pX, pY, dX, dY, erasure, Targets.ar[i]) * dmgMod)
+ end;
+ if Kind = gtHedgehog then
+ begin
+ if fallDmg < 0 then // drowning. score healthier hogs higher, since their death is more likely to benefit the AI
+ begin
+ 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
+ end
+ else if (dmg+fallDmg) >= abs(Score) then
+ begin
+ dead:= true;
+ Targets.reset:= true;
+ if dX < 0.035 then
+ begin
+ subrate:= RealRateExplosion(Me, round(pX), round(pY), 61, afErasesLand or afTrackFall);
+ if abs(subrate) > 2000 then inc(Rate,subrate div 1024)
+ end;
+ if Score > 0 then
+ inc(rate, KillScore)
+ else
+ dec(rate, KillScore * friendlyfactor div 100)
+ end
+ else if Score > 0 then
+ inc(rate, dmg+fallDmg)
+ else dec(rate, (dmg+fallDmg) * friendlyfactor div 100)
+ end
+ else if (fallDmg >= 0) and ((dmg+fallDmg) >= Score) then
+ begin
+ dead:= true;
+ Targets.reset:= true;
+ if Kind = gtExplosives then
+ subrate:= RealRateExplosion(Me, round(pX), round(pY), 151, afErasesLand or afTrackFall)
+ else subrate:= RealRateExplosion(Me, round(pX), round(pY), 101, afErasesLand or afTrackFall);
+ if abs(subrate) > 2000 then inc(Rate,subrate div 1024);
+ end
+ end
end;
- end;
if hadSkips and (rate = 0) then
RateShotgun:= BadTurn
else
RateShotgun:= rate * 1024;
+ ResetTargets;
end;
function RateHammer(Me: PGear): LongInt;
@@ -605,14 +778,13 @@
for i:= 0 to Pred(Targets.Count) do
with Targets.ar[i] do
- if matters then
// hammer hit radius is 8, shift is 10
- if abs(Point.x - x) + abs(Point.y - y) < 18 then
+ if matters and (Kind = gtHedgehog) and (abs(Point.x - x) + abs(Point.y - y) < 18) then
begin
r:= trunc(sqrt(sqr(Point.x - x)+sqr(Point.y - y)));
if r <= 18 then
- if Score > 0 then
+ if Score > 0 then
inc(rate, Score div 3)
else
inc(rate, Score div 3 * friendlyfactor div 100)
@@ -630,7 +802,7 @@
bY:= hwRound(Gear^.Y);
case JumpType of
jmpNone: exit(false);
-
+
jmpHJump:
if TestCollisionYwithGear(Gear, -1) = 0 then
begin
@@ -640,7 +812,7 @@
end
else
exit(false);
-
+
jmpLJump:
begin
if TestCollisionYwithGear(Gear, -1) <> 0 then
@@ -662,12 +834,12 @@
end;
repeat
- {if ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) then
+ {if ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) then
begin
LandPixels[hwRound(Gear^.Y), hwRound(Gear^.X)]:= Gear^.Hedgehog^.Team^.Clan^.Color;
UpdateLandTexture(hwRound(Gear^.X), 1, hwRound(Gear^.Y), 1, true);
end;}
-
+
if not (hwRound(Gear^.Y) + cHHRadius < cWaterLine) then
exit(false);
if (Gear^.State and gstMoving) <> 0 then
@@ -725,7 +897,7 @@
GoInfo.JumpType:= jmpNone;
tY:= hwRound(Gear^.Y);
repeat
- {if ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) then
+ {if ((hwRound(Gear^.Y) and LAND_HEIGHT_MASK) = 0) and ((hwRound(Gear^.X) and LAND_WIDTH_MASK) = 0) then
begin
LandPixels[hwRound(Gear^.Y), hwRound(Gear^.X)]:= random($FFFFFFFF);//Gear^.Hedgehog^.Team^.Clan^.Color;
UpdateLandTexture(hwRound(Gear^.X), 1, hwRound(Gear^.Y), 1, true);
@@ -739,8 +911,8 @@
AddWalkBonus(pX, tY, 250, -40);
exit(false)
end;
-
- // hog is falling
+
+ // hog is falling
if (Gear^.State and gstMoving) <> 0 then
begin
inc(GoInfo.Ticks);
@@ -749,7 +921,7 @@
begin
GoInfo.FallPix:= 0;
// try ljump instead of fall with damage
- HHJump(AltGear, jmpLJump, GoInfo);
+ HHJump(AltGear, jmpLJump, GoInfo);
if AltGear^.Hedgehog^.BotLevel < 4 then
AddWalkBonus(pX, tY, 175, -20);
exit(false)