# HG changeset patch # User unc0rr # Date 1339164224 -14400 # Node ID 5a9775b97c7e2bdefbafa07d62e283b8f5920221 # Parent 9e6e8e5a4c2ef105b1ce421a903bc6b9fc090e17 - TestSniperRifle ftw (still needs some consts adjustments, because AI seems to love sniper rifle too much) - Also optimize TestDesertEagle a bit - Also some formatting changes diff -r 9e6e8e5a4c2e -r 5a9775b97c7e hedgewars/uAI.pas --- a/hedgewars/uAI.pas Fri Jun 08 14:30:46 2012 +0400 +++ b/hedgewars/uAI.pas Fri Jun 08 18:03:44 2012 +0400 @@ -111,7 +111,7 @@ procedure TestAmmos(var Actions: TActions; Me: PGear; isMoved: boolean); var BotLevel: Byte; ap: TAttackParams; - Score, i: LongInt; + Score, i, dAngle: LongInt; a, aa: TAmmoType; begin BotLevel:= Me^.Hedgehog^.BotLevel; @@ -153,29 +153,41 @@ if (ap.Time <> 0) then AddAction(BestActions, aia_Timer, ap.Time div 1000, 400, 0, 0); + if (Ammoz[a].Ammo.Propz and ammoprop_NoCrosshair) = 0 then begin - ap.Angle:= LongInt(Me^.Angle) - Abs(ap.Angle); - if ap.Angle > 0 then + dAngle:= LongInt(Me^.Angle) - Abs(ap.Angle); + if dAngle > 0 then begin AddAction(BestActions, aia_Up, aim_push, 300 + random(250), 0, 0); - AddAction(BestActions, aia_Up, aim_release, ap.Angle, 0, 0) + AddAction(BestActions, aia_Up, aim_release, dAngle, 0, 0) end - else if ap.Angle < 0 then + else if dAngle < 0 then begin AddAction(BestActions, aia_Down, aim_push, 300 + random(250), 0, 0); - AddAction(BestActions, aia_Down, aim_release, -ap.Angle, 0, 0) + AddAction(BestActions, aia_Down, aim_release, -dAngle, 0, 0) end end; + if (Ammoz[a].Ammo.Propz and ammoprop_NeedTarget) <> 0 then begin AddAction(BestActions, aia_Put, 0, 1, ap.AttackPutX, ap.AttackPutY) end; - if (Ammoz[a].Ammo.Propz and ammoprop_AttackingPut) = 0 then + + if (Ammoz[a].Ammo.Propz and ammoprop_OscAim) <> 0 then begin - AddAction(BestActions, aia_attack, aim_push, 650 + random(300), 0, 0); - AddAction(BestActions, aia_attack, aim_release, ap.Power, 0, 0); - end; + AddAction(BestActions, aia_attack, aim_push, 350 + random(200), 0, 0); + AddAction(BestActions, aia_attack, aim_release, 1, 0, 0); + AddAction(BestActions, aia_waitAngle, ap.Angle, 250, 0, 0); + AddAction(BestActions, aia_attack, aim_push, 1, 0, 0); + AddAction(BestActions, aia_attack, aim_release, 1, 0, 0); + end else + if (Ammoz[a].Ammo.Propz and ammoprop_AttackingPut) = 0 then + begin + AddAction(BestActions, aia_attack, aim_push, 650 + random(300), 0, 0); + AddAction(BestActions, aia_attack, aim_release, ap.Power, 0, 0); + end; + if ap.ExplR > 0 then AddAction(BestActions, aia_AwareExpl, ap.ExplR, 10, ap.ExplX, ap.ExplY); end @@ -218,81 +230,86 @@ BestRate:= RatePlace(Me); BaseRate:= Max(BestRate, 0); +// switch to 'skip' if we can't move because of mouse cursor being shown if (Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NeedTarget) <> 0 then AddAction(Actions, aia_Weapon, Longword(amSkip), 100 + random(200), 0, 0); - -tmp:= random(2) + 1; -Push(0, Actions, Me^, tmp); -Push(0, Actions, Me^, tmp xor 3); -while (Stack.Count > 0) and (not StopThinking) and (GameFlags and gfArtillery = 0) do +if ((CurrentHedgehog^.MultiShootAttacks = 0) or ((Ammoz[Me^.Hedgehog^.CurAmmoType].Ammo.Propz and ammoprop_NoMoveAfter) = 0)) + and (GameFlags and gfArtillery = 0) then begin - Pop(ticks, Actions, Me^); + tmp:= random(2) + 1; + Push(0, Actions, Me^, tmp); + Push(0, Actions, Me^, tmp xor 3); + + while (Stack.Count > 0) and (not StopThinking) do + begin + Pop(ticks, Actions, Me^); - AddAction(Actions, Me^.Message, aim_push, 250, 0, 0); - if (Me^.Message and gmLeft) <> 0 then - AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0) - else - AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0); - - steps:= 0; + AddAction(Actions, Me^.Message, aim_push, 250, 0, 0); + if (Me^.Message and gmLeft) <> 0 then + AddAction(Actions, aia_WaitXL, hwRound(Me^.X), 0, 0, 0) + else + AddAction(Actions, aia_WaitXR, hwRound(Me^.X), 0, 0, 0); + + steps:= 0; - while (not StopThinking) do - begin -{$HINTS OFF} - CanGo:= HHGo(Me, @AltMe, GoInfo); -{$HINTS ON} - inc(ticks, GoInfo.Ticks); - if ticks > maxticks then - break; + while (not StopThinking) do + begin + {$HINTS OFF} + CanGo:= HHGo(Me, @AltMe, GoInfo); + {$HINTS ON} + inc(ticks, GoInfo.Ticks); + if ticks > maxticks then + break; - if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support - if Push(ticks, Actions, AltMe, Me^.Message) then - with Stack.States[Pred(Stack.Count)] do - begin - if Me^.dX.isNegative then - AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0) - else - AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0); + if (BotLevel < 5) and (GoInfo.JumpType = jmpHJump) then // hjump support + if Push(ticks, Actions, AltMe, Me^.Message) then + with Stack.States[Pred(Stack.Count)] do + begin + if Me^.dX.isNegative then + AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0) + else + AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0); + + AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0); + AddAction(MadeActions, aia_HJump, 0, 350, 0, 0); - AddAction(MadeActions, aia_HJump, 0, 305 + random(50), 0, 0); - AddAction(MadeActions, aia_HJump, 0, 350, 0, 0); - - if Me^.dX.isNegative then - AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0) - else - AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0); - end; - if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support - if Push(ticks, Actions, AltMe, Me^.Message) then - with Stack.States[Pred(Stack.Count)] do - AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0); + if Me^.dX.isNegative then + AddAction(MadeActions, aia_LookLeft, 0, 200, 0, 0) + else + AddAction(MadeActions, aia_LookRight, 0, 200, 0, 0); + end; + if (BotLevel < 3) and (GoInfo.JumpType = jmpLJump) then // ljump support + if Push(ticks, Actions, AltMe, Me^.Message) then + with Stack.States[Pred(Stack.Count)] do + AddAction(MadeActions, aia_LJump, 0, 305 + random(50), 0, 0); - // 'not CanGO' means we can't go straight, possible jumps are checked above - if not CanGo then - break; - - inc(steps); - Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X); - Rate:= RatePlace(Me); - if Rate > BestRate then - begin - BestActions:= Actions; - BestActions.isWalkingToABetterPlace:= true; - BestRate:= Rate; - Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo - end - else if Rate < BestRate then - break; - if ((Me^.State and gstAttacked) = 0) and ((steps mod 4) = 0) then - TestAmmos(Actions, Me, true); - if GoInfo.FallPix >= FallPixForBranching then - Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right - end {while}; + // 'not CanGO' means we can't go straight, possible jumps are checked above + if not CanGo then + break; + + inc(steps); + Actions.actions[Pred(Actions.Count)].Param:= hwRound(Me^.X); + Rate:= RatePlace(Me); + if Rate > BestRate then + begin + BestActions:= Actions; + BestActions.isWalkingToABetterPlace:= true; + BestRate:= Rate; + Me^.State:= Me^.State or gstAttacked // we have better place, go there and do not use ammo + end + else if Rate < BestRate then + break; + if ((Me^.State and gstAttacked) = 0) and ((steps mod 4) = 0) then + TestAmmos(Actions, Me, true); + if GoInfo.FallPix >= FallPixForBranching then + Push(ticks, Actions, Me^, Me^.Message xor 3); // aia_Left xor 3 = aia_Right + end {while}; - if BestRate > BaseRate then - exit + if BestRate > BaseRate then + exit end {while} + end {if} end; function Think(Me: Pointer): ptrint; @@ -438,8 +455,8 @@ end else ProcessAction(BestActions, Gear) else if ((GameTicks - StartTicks) > cMaxAIThinkTime) - or (TurnTimeLeft <= cStopThinkTime) then - StopThinking:= true + or (TurnTimeLeft <= cStopThinkTime) then + StopThinking:= true end; procedure initModule; diff -r 9e6e8e5a4c2e -r 5a9775b97c7e hedgewars/uAIActions.pas --- a/hedgewars/uAIActions.pas Fri Jun 08 14:30:46 2012 +0400 +++ b/hedgewars/uAIActions.pas Fri Jun 08 18:03:44 2012 +0400 @@ -43,6 +43,7 @@ aia_Skip = $8008; aia_Wait = $8009; aia_Put = $800A; + aia_waitAngle = $800B; aim_push = $8000; aim_release = $8001; @@ -70,7 +71,7 @@ var PrevX: LongInt = 0; timedelta: Longword = 0; -const ActionIdToStr: array[0..7] of string[16] = ( +const ActionIdToStr: array[0..8] of string[16] = ( {aia_none} '', {aia_Left} 'left', {aia_Right} 'right', @@ -78,7 +79,8 @@ {aia_attack} 'attack', {aia_Up} 'up', {aia_Down} 'down', -{aia_Switch} 'switch' +{aia_Switch} 'switch', +{aia_waitAngle} 'waitAngle' ); {$IFDEF TRACEAIACTIONS} @@ -150,6 +152,7 @@ begin repeat if Actions.Pos >= Actions.Count then exit; + with Actions.actions[Actions.Pos] do begin if Time > GameTicks then @@ -160,74 +163,77 @@ if (Action and ai_specmask) <> 0 then case Action of aia_Weapon: - SetWeapon(TAmmoType(Param)); + SetWeapon(TAmmoType(Param)); aia_WaitXL: - if hwRound(Me^.X) = Param then - begin - Action:= aia_LookLeft; - Time:= GameTicks; - exit - end - else if hwRound(Me^.X) < Param then + if hwRound(Me^.X) = Param then begin - //OutError('AI: WaitXL assert (' + IntToStr(hwRound(Me^.X)) + ' < ' + IntToStr(Param) + ')', false); - FreeActionsList; + Action:= aia_LookLeft; + Time:= GameTicks; + exit + end + else if hwRound(Me^.X) < Param then + begin + //OutError('AI: WaitXL assert (' + IntToStr(hwRound(Me^.X)) + ' < ' + IntToStr(Param) + ')', false); + FreeActionsList; + exit + end + else + begin + CheckHang(Me); + exit + end; + + aia_WaitXR: + if hwRound(Me^.X) = Param then + begin + Action:= aia_LookRight; + Time:= GameTicks; + exit + end + else if hwRound(Me^.X) > Param then + begin + //OutError('AI: WaitXR assert (' + IntToStr(hwRound(Me^.X)) + ' > ' + IntToStr(Param) + ')', false); + FreeActionsList; + exit + end + else + begin + CheckHang(Me); + exit + end; + aia_LookLeft: + if not Me^.dX.isNegative then + begin + ParseCommand('+left', true); exit end else - begin - CheckHang(Me); - exit - end; - - aia_WaitXR: - if hwRound(Me^.X) = Param then - begin - Action:= aia_LookRight; - Time:= GameTicks; - exit - end - else if hwRound(Me^.X) > Param then + ParseCommand('-left', true); + aia_LookRight: + if Me^.dX.isNegative then begin - //OutError('AI: WaitXR assert (' + IntToStr(hwRound(Me^.X)) + ' > ' + IntToStr(Param) + ')', false); - FreeActionsList; + ParseCommand('+right', true); exit end - else - begin - CheckHang(Me); - exit - end; - aia_LookLeft: - if not Me^.dX.isNegative then - begin - ParseCommand('+left', true); - exit - end - else - ParseCommand('-left', true); - aia_LookRight: - if Me^.dX.isNegative then - begin - ParseCommand('+right', true); - exit - end - else ParseCommand('-right', true); + else ParseCommand('-right', true); aia_AwareExpl: - AwareOfExplosion(X, Y, Param); + AwareOfExplosion(X, Y, Param); aia_HJump: - ParseCommand('hjump', true); + ParseCommand('hjump', true); aia_LJump: - ParseCommand('ljump', true); + ParseCommand('ljump', true); aia_Skip: - ParseCommand('skip', true); + ParseCommand('skip', true); aia_Put: - doPut(X, Y, true); + doPut(X, Y, true); + + aia_waitAngle: + if Me^.Angle <> Abs(Param) then exit; end else begin diff -r 9e6e8e5a4c2e -r 5a9775b97c7e hedgewars/uAIAmmoTests.pas --- a/hedgewars/uAIAmmoTests.pas Fri Jun 08 14:30:46 2012 +0400 +++ b/hedgewars/uAIAmmoTests.pas Fri Jun 08 18:03:44 2012 +0400 @@ -43,6 +43,7 @@ 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; @@ -97,7 +98,7 @@ (proc: nil; flags: 0), // amExtraTime (proc: nil; flags: 0), // amLaserSight (proc: nil; flags: 0), // amVampiric - (proc: nil; flags: 0), // amSniperRifle + (proc: @TestSniperRifle; flags: 0), // amSniperRifle (proc: nil; flags: 0), // amJetpack (proc: @TestMolotov; flags: 0), // amMolotov (proc: nil; flags: 0), // amBirdy @@ -602,7 +603,56 @@ TestDesertEagle:= BadTurn; exit(BadTurn); end; -t:= 0.5 / sqrt(sqr(Targ.X - x)+sqr(Targ.Y-y)); +t:= 2 / sqrt(sqr(Targ.X - x)+sqr(Targ.Y-y)); +Vx:= (Targ.X - x) * t; +Vy:= (Targ.Y - y) * t; +ap.Angle:= DxDy2AttackAnglef(Vx, -Vy); +d:= 0; + +repeat + x:= x + vX; + y:= y + vY; + 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) + or (x < 0) + or (y < 0) + or (trunc(x) > LAND_WIDTH) + or (trunc(y) > LAND_HEIGHT) + or (d > 50); + +if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 5 then + begin + fallDmg:= TraceShoveFall(Me, 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 50) * trunc((7+fallDmg)*dmgMod) * 1024) + end +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; + d: Longword; + fallDmg, valueResult: LongInt; +begin +dmgMod:= 0.01 * hwFloat2Float(cDamageModifier) * cDamagePercent; +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 + exit(BadTurn); + +dmg:= sqrt(sqr(Targ.X - x)+sqr(Targ.Y-y)); +t:= 1.5 / dmg; +dmg:= dmg * 0.33333333; Vx:= (Targ.X - x) * t; Vy:= (Targ.Y - y) * t; ap.Angle:= DxDy2AttackAnglef(Vx, -Vy); @@ -619,20 +669,21 @@ or (y < 0) or (trunc(x) > LAND_WIDTH) or (trunc(y) > LAND_HEIGHT) - or (d > 200); + or (d > 23); -if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 3 then +if Abs(Targ.X - trunc(x)) + Abs(Targ.Y - trunc(y)) < 4 then begin - fallDmg:= TraceShoveFall(Me, Targ.X, Targ.Y, vX * 0.005 * 20, vY * 0.005 * 20); + fallDmg:= TraceShoveFall(Me, Targ.X, Targ.Y, vX * 0.00166 * dmg, vY * 0.00166 * dmg); if fallDmg < 0 then - valueResult:= 204800 - else valueResult:= Max(0, (4 - d div 50) * trunc((7+fallDmg)*dmgMod) * 1024) + TestSniperRifle:= BadTurn + else + TestSniperRifle:= Max(0, trunc((dmg + fallDmg) * dmgMod) * 1024) end else - valueResult:= BadTurn; -TestDesertEagle:= valueResult + TestSniperRifle:= BadTurn end; + function TestBaseballBat(Me: PGear; Targ: TPoint; Level: LongInt; var ap: TAttackParams): LongInt; var valueResult: LongInt; x, y: real; diff -r 9e6e8e5a4c2e -r 5a9775b97c7e hedgewars/uConsts.pas --- a/hedgewars/uConsts.pas Fri Jun 08 14:30:46 2012 +0400 +++ b/hedgewars/uConsts.pas Fri Jun 08 18:03:44 2012 +0400 @@ -260,6 +260,8 @@ ammoprop_Effect = $00002000; ammoprop_SetBounce = $00004000; ammoprop_NeedUpDown = $00008000;//Used by TouchInterface to show or hide up/down widgets + ammoprop_OscAim = $00010000; + ammoprop_NoMoveAfter = $00020000; ammoprop_NoRoundEnd = $10000000; AMMO_INFINITE = 100; diff -r 9e6e8e5a4c2e -r 5a9775b97c7e hedgewars/uVariables.pas --- a/hedgewars/uVariables.pas Fri Jun 08 14:30:46 2012 +0400 +++ b/hedgewars/uVariables.pas Fri Jun 08 18:03:44 2012 +0400 @@ -1828,7 +1828,9 @@ NameTex: nil; Probability: 20; NumberInCase: 2; - Ammo: (Propz: ammoprop_NeedUpDown; + Ammo: (Propz: ammoprop_NeedUpDown or + ammoprop_OscAim or + ammoprop_NoMoveAfter; Count: 2; NumPerTurn: 1; Timer: 0;