Skip to content

Commit

Permalink
Retreat control optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
SMUnlimited committed Nov 26, 2024
1 parent f5e4e6b commit 25c747e
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 31 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,20 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Building additional factory buildings should not be done while actively tiering up as the buildings needed for tier 2/3 may be different.
- Harass will correctly keep harassing if no units can harm its air harass.
- Harass attacks will return harassing units faster to the ai's control when complete.
- Reduced time heros wait to pick up items after creeping in half.

### Fixed
- Fix to avoid rare crashes in job thread.
- Fix to avoid a case where AMAI tries to buy more than one hero in tier 1 and when using the recalculate heros ai command.
- Fix Panda clones to not be canceled early when hero is going home or buying items.
- If no units to attack with windwalk, then will exit windwalk and just attack a building rather than just stand around doing nothing.
- Fixed an issue where harass attacks could failed to track harass units correctly and lose more units in the group when just one is killed, ending the harass early.
- Fixed an issue where harass attacks fail to start.
- Fixed an issue where harass attacks could fail to track harass units correctly.
- Fixed an issue where harass attacks could cause units to permanently stop moving.
- Team game defeated ai's that cannot share to a same race player will share to victim neutral player same as in single matches.
- Ensure focus fire controls are not running during a players retreat.
- Natural retreat will now actually trigger instead of staying stuck in combat.
- Alliance targets are once again flagged to allies with a ping on the minimap.
- (Classic) Include missing hero harass attacks that are applicable from reforged scripts.

## [3.4.0] - 2024-11-19
Expand Down
4 changes: 2 additions & 2 deletions Jobs/FOCUSFIRE_CONTROL.eai
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ function FocusFireJob takes nothing returns nothing
exitwhen u == null
if IsUnitVisible(u, Player(PLAYER_NEUTRAL_AGGRESSIVE)) and not IsUnitInGroup(u, unit_healing) and not IsUnitInGroup(u, unit_rescueing ) and not IsUnitInGroup(u, unit_harassing ) and not IsUnitInGroup(u, unit_zepplin_move ) then
call RecycleGuardPosition(u)
if attack_running and not CaptainIsHome() and not CaptainRetreating() and not isfleeing then
if attack_running and not isfleeing then
call AddAssault(1, GetUnitTypeId(u))
endif
endif
Expand All @@ -339,7 +339,7 @@ function FocusFireJob takes nothing returns nothing
set u = null
call GroupClear(windwalk_group)

if not CaptainRetreating() and not isfleeing and (attack_running or town_threatened) then
if not isfleeing and (attack_running or town_threatened) then
if (major_hero != null) then
call MoveLocation(last_major_hero_loc, GetUnitX(major_hero), GetUnitY(major_hero))
call GroupEnumUnitsInRange(g,GetUnitX(major_hero),GetUnitY(major_hero),battle_radius,null)
Expand Down
2 changes: 1 addition & 1 deletion Jobs/MICRO_HERO.eai
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ function MicroHeroJob takes integer hn returns nothing
return
endif
// Next statement detects when the main army is outmatched and so teleports back to home base
elseif attack_running and main_army >= 0 and army_loc[main_army] != null and IsUnitInRangeXY(hero_unit[hn],GetLocationX(army_loc[main_army]), GetLocationY(army_loc[main_army]), battle_radius) and army_strength[armyOfHero] >= teleport_army_min_strength and CaptainRetreating() and isfleeing and DistanceBetweenPoints(hero_loc[hn], home_location) > teleport_low_threat_distance then
elseif attack_running and main_army >= 0 and army_loc[main_army] != null and IsUnitInRangeXY(hero_unit[hn],GetLocationX(army_loc[main_army]), GetLocationY(army_loc[main_army]), battle_radius) and army_strength[armyOfHero] >= teleport_army_min_strength and isfleeing and DistanceBetweenPoints(hero_loc[hn], home_location) > teleport_low_threat_distance then
call CreateDebugTag("HERO: Army outmatched-teleporting home", 10, hero_unit[hn], 4.00, 2.00)
call TeleportHome(hn)
call TQAddJob(1, MICRO_HERO, hn)
Expand Down
2 changes: 1 addition & 1 deletion Jobs/RESET_GUARD_POSITION_ONLY.eai
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function ResetGuardPositionOnlyJob takes unit u returns nothing
endif
call CreateDebugTag("RECYCLE", 10, u, 3.00, 1.50)
call RecycleGuardPosition(u)
if not IsUnitType(u, UNIT_TYPE_PEON) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not CaptainRetreating() and not isfleeing then
if not IsUnitType(u, UNIT_TYPE_PEON) and not IsUnitType(u, UNIT_TYPE_STRUCTURE) and not isfleeing then
call AddAssault(60, GetUnitTypeId(u)) // Add units back to the assault group to stop them running home from the combat
endif
endfunction
Expand Down
2 changes: 1 addition & 1 deletion Jobs/RESET_WINDWALKER.eai
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ function ResetWindWalkerGuardPosition takes unit u returns nothing
call CreateDebugTag("RECYCLE Windwalk", 10, u, 3.00, 1.50)
if IsUnitVisible(u, Player(PLAYER_NEUTRAL_AGGRESSIVE)) and not IsUnitInGroup(u, unit_healing) and not IsUnitInGroup(u, unit_rescueing ) and not IsUnitInGroup(u, unit_harassing ) and not IsUnitInGroup(u, unit_zepplin_move ) then
call RecycleGuardPosition(u)
if attack_running and not CaptainIsHome() and not CaptainRetreating() and not isfleeing then
if attack_running and not isfleeing then
call AddAssault(1, GetUnitTypeId(u))
endif
endif
Expand Down
21 changes: 15 additions & 6 deletions Jobs/RETREAT_CONTROL.eai
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
location home_location = null
real enemy_strength_sum = 0
real ally_strength_sum = 0
boolean canflee = false
boolean isfleeing = false
integer added_target_aggression = 0 // The current bonus aggression added to current attack specified in the profiles
integer added_racial_aggression = 0 // The current bonus added to current attack based on which race amai is attacking
Expand Down Expand Up @@ -113,11 +114,17 @@ if not retreat_controlled then
return
endif

if ((not attack_running and not isfleeing) or (isfleeing and (CaptainRetreating() or CaptainIsHome())) or town_threatened) then
if not isfleeing and canflee and (CaptainRetreating() or CaptainIsHome()) then
call TraceAll("RETREAT_CONTROL: Natural Flee !!!")
set isfleeing = true
endif

if ((not attack_running and not isfleeing) or isfleeing or (town_threatened and town_threat_break)) then
set break_attack = attack_running
if CaptainIsHome() or (not attack_running and not isfleeing) then
call Trace("===Retreat control ended===")
set retreat_controlled = false
set canflee = false
set isfleeing = false // home so no need to be retreating. Also prevents bug in the captainretreating condition
call SetGroupsFlee(false)
return
Expand All @@ -126,7 +133,8 @@ if ((not attack_running and not isfleeing) or (isfleeing and (CaptainRetreating(
endif
endif

if isfleeing or town_threatened then
if isfleeing or (town_threatened and town_threat_break) then
call ClearCaptainTargets()
call CaptainGoHome()
endif

Expand Down Expand Up @@ -203,19 +211,20 @@ if attack_running then
set ally_strength_sum = ally_sum
call Trace("RETREAT_CONTROL: Our strength: " + Real2Str(ally_strength_sum) + " Enemy strength: " + Real2Str(enemy_strength_sum))

if not desperation_assault and (enemy_strength_sum > LinearInterpolation(ver_low_aggression,ver_high_aggression,ver_flee_multiple2,ver_flee_multiple3,attacking_aggression + added_aggression + added_target_aggression + added_racial_aggression)*ally_strength_sum or (town_threatened and attack_running) or ally_strength_sum == 0) then
call Trace("RETREAT_CONTROL: Flee!!!!")
if not desperation_assault and (enemy_strength_sum > LinearInterpolation(ver_low_aggression,ver_high_aggression,ver_flee_multiple2,ver_flee_multiple3,attacking_aggression + added_aggression + added_target_aggression + added_racial_aggression)*ally_strength_sum or (town_threatened and town_threat_break and attack_running) or ally_strength_sum == 0) then
call TraceAll("RETREAT_CONTROL: Flee!!!!")
set break_attack = attack_running
call ClearCaptainTargets()
call CaptainGoHome()
set isfleeing = true
elseif not desperation_assault and (enemy_strength_sum > LinearInterpolation(ver_low_aggression,ver_high_aggression,ver_flee_multiple1,ver_flee_multiple2,attacking_aggression + added_aggression + added_target_aggression + added_racial_aggression)*ally_strength_sum or (battle_radius == creep_battle_radius and enemy_strength_sum > ally_strength_sum )) then
call Trace("RETREAT_CONTROL: Allowed to Flee")
call TraceAll("RETREAT_CONTROL: Allowed to Flee")
call SetGroupsFlee(true)
set isfleeing = true
set canflee = true
else
call SetGroupsFlee(false) // Prevent natural fleeing
set isfleeing = false
set canflee = false
endif

endif
Expand Down
41 changes: 22 additions & 19 deletions common.eai
Original file line number Diff line number Diff line change
Expand Up @@ -11937,6 +11937,7 @@ function SleepInCombatAM takes boolean ally_override returns nothing
exitwhen break_attack // forced attack to end
exitwhen CaptainIsEmpty()// no troops so stop attack
exitwhen R2I(count) >= 900 // Took longer than 15 mins to stop lingering something is wrong
exitwhen isfleeing // Retreat control says to retreat
if (lastcaptainx != 0 and lastcaptainy != 0) then
call CreateDebugTagLoc("Sleep at captainloc", 10, lastcaptainx, lastcaptainy, 1.00, 0.80)
call GroupEnumUnitsInRange(g, lastcaptainx, lastcaptainy, battle_radius,null)
Expand All @@ -11947,7 +11948,7 @@ function SleepInCombatAM takes boolean ally_override returns nothing
call GroupRemoveUnit(g, u)
endloop
call GroupClear(g)
if u == null and noenemycount < 8 then
if u == null and noenemycount < 4 then
set noenemycount = noenemycount + 1 // 8 seconds to pick up items on ground
call TeleportCaptain(lastcaptainx, lastcaptainy)
elseif u == null then
Expand All @@ -11962,9 +11963,10 @@ function SleepInCombatAM takes boolean ally_override returns nothing
set attack_length_counter = 0
call FormGroupAM(0)
endif
call AttackMoveKill(u) // Use existing troops
if (c_ally_total > 0 and not ally_override) then
call TeleportCaptain(GetUnitX(u), GetUnitY(u)) // Override hardcoded logic with attackmovekill which will help allies
if true or CaptainAtGoal() or (attack_length_counter == 0 and not CaptainInCombat(true)) or CaptainInCombat(true) or ally_override or c_ally_total == 0 then
call AttackMoveKill(u) // Use existing troops
elseif (c_ally_total > 0 and not ally_override) then
call CaptainAttack(GetUnitX(u), GetUnitY(u)) // Override hardcoded logic with attackmovekill as ally targets will change the attackmovekill we wanted. Teleport ignores the ally control.
endif
call CreateDebugTag("Combat sleep attack", 10, u, 1.00, 0.80)
endif
Expand Down Expand Up @@ -12065,7 +12067,7 @@ function CommonSleepUntilTargetDeadAM takes unit target, boolean iscreeping, boo
exitwhen break_attack and not desperation_assault
//exitwhen captain_flee and CaptainRetreating()
//call Trace("SleepExitFlee:" + B2S(isfleeing and (CaptainRetreating() or CaptainIsHome()) and not desperation_assault))
exitwhen isfleeing and (CaptainRetreating() or CaptainIsHome()) and not desperation_assault
exitwhen isfleeing and not desperation_assault
//call Trace("SleepExitEmpty:" + B2S(CaptainIsEmpty() and not desperation_assault))
exitwhen CaptainIsEmpty() and not desperation_assault
//if (c_ally_total > 0 and GetAllianceTarget() != null) then // If alliance target exists this overrides hardcoded attack controls regardless of unit you pass, so reconfigure attack to be aware of this
Expand Down Expand Up @@ -12103,8 +12105,11 @@ function CommonSleepUntilTargetDeadAM takes unit target, boolean iscreeping, boo
set lastcaptainx = GetLocationX(ally_loc)
set lastcaptainy = GetLocationY(ally_loc)
//call SetCaptainHome(, lastcaptainx, lastcaptainy)
call AttackMoveXY(R2I(GetLocationX(ally_loc)), R2I(GetLocationY(ally_loc)))
call TeleportCaptain(GetLocationX(ally_loc), GetLocationY(ally_loc)) // Override and help nearby ally
if true or CaptainAtGoal() or attack_length_counter == 0 or CaptainInCombat(true) or ally_override or c_ally_total == 0 then
call AttackMoveXY(R2I(GetLocationX(ally_loc)), R2I(GetLocationY(ally_loc)))
elseif (c_ally_total > 0 and not ally_override) then
call CaptainAttack(GetLocationX(ally_loc), GetLocationY(ally_loc)) // Override and help nearby ally
endif
call CreateDebugTagLoc("Reform near ally", 10, GetLocationX(ally_loc), GetLocationY(ally_loc), 1.00, 0.80)
else
set lastcaptainx = GetUnitX(target)
Expand All @@ -12114,9 +12119,10 @@ function CommonSleepUntilTargetDeadAM takes unit target, boolean iscreeping, boo
if (ally_override and c_ally_total > 0 and ally_target != null and ally_target != target) then
set target = ally_target
endif
call AttackMoveKill(target)
if (c_ally_total > 0 and not ally_override) then
call TeleportCaptain(GetUnitX(target), GetUnitY(target)) // Override hardcoded logic from attackmovekill which will help allies
if true or CaptainAtGoal() or (attack_length_counter == 0 and not CaptainInCombat(true)) or CaptainInCombat(true) or ally_override or c_ally_total == 0 then
call AttackMoveKill(target) // use attack length counter to do an ocassional attack move incase enemies nearby
elseif (c_ally_total > 0 and not ally_override) then // CURRENTLY DISABLED AS FIGHTS WITH ABOVE, NEED NEW COMBAT ATTACK MOVE FUNCTION
call CaptainAttack(GetUnitX(target), GetUnitY(target)) // Override hardcoded logic from attackmovekill which will help allies, but this is not an attack move operation
endif
// Below is old style alliance but this overrides all hardcoded attacks whether you want it to or not
//if (GetAllianceTarget() == target) then
Expand Down Expand Up @@ -12157,7 +12163,7 @@ function CommonSleepUntilTargetDeadAM takes unit target, boolean iscreeping, boo
set attack_length_counter = attack_length_counter + 1
set combat_length_counter = 0
endif
if CaptainInCombat(true) and combat_length_counter > attack_reform_length * 3 then
if CaptainInCombat(true) and combat_length_counter > attack_reform_length then
set combat_length_counter = 0
call FormGroupAM(0)
elseif not CaptainInCombat(true) and attack_length_counter > attack_reform_length then
Expand Down Expand Up @@ -12187,9 +12193,8 @@ function SleepUntilAtGoalAM takes nothing returns nothing
loop
exitwhen town_threat_break and town_threatened
set lcount = lcount + 1
call StaggerSleep(0.8, 1*sleep_multiplier)
exitwhen break_attack
exitwhen CaptainRetreating() and isfleeing
exitwhen break_attack
exitwhen isfleeing
if lcount >= 6 then
exitwhen CaptainAtGoal() // reached goal
exitwhen CaptainIsHome() // failed to path and returned home
Expand Down Expand Up @@ -12222,11 +12227,11 @@ endfunction
function SetAllianceTargetIfLeadAndChat takes unit u, integer chat returns nothing
if (not HaveStoredInteger(amaiCache, Int2Str(ALLIANCE_TARGET), "0") and u != null) then // if leadally
call StoreInteger(amaiCache, Int2Str(ALLIANCE_TARGET), "0", GetHandleId(u))
//call SetAllianceTarget(u)
call SetAllianceTarget(u) // Just sends alliance attack signal, doesn't actually control ally attack target as originally thought, thats hardcoded into attackmovekill
call SetChatVarsAttack(u)
call Chat(chat)
elseif (HaveStoredInteger(amaiCache, Int2Str(ALLIANCE_TARGET), "0") and u == null) then
//call SetAllianceTarget(u)
call SetAllianceTarget(u)
call FlushStoredInteger(amaiCache, Int2Str(ALLIANCE_TARGET), "0")
endif
endfunction
Expand Down Expand Up @@ -12757,7 +12762,7 @@ function ChooseEnemyBaseTarget takes unit u returns unit
call StartGetEnemyBase()
loop
exitwhen not WaitGetEnemyBase()
if c > 4 or town_threatened or isfleeing or CaptainRetreating() or CaptainIsEmpty() then
if c > 4 or town_threatened or isfleeing or CaptainIsEmpty() then
return null
endif
call Sleep(1)
Expand Down Expand Up @@ -13025,7 +13030,6 @@ function SingleMeleeAttackAM takes boolean needs_exp, boolean has_siege, integer

if town_threatened then
set break_attack = false
set isfleeing = false
call SleepUntilTownDefended(ai_strength)
return
endif
Expand Down Expand Up @@ -13680,7 +13684,6 @@ function universal_attack_sequence takes nothing returns nothing

if town_threatened or TownThreatened() then // Attack has finished so any AMAI detections or hardcoded threat detections should be dealt with
set break_attack = false
set isfleeing = false
//call FormGroupAM(1)
call SleepUntilTownDefended(ai_strength)
//elseif not towerrush and not ancient_expanding and not militia_expanding and not item_expanding then
Expand Down

0 comments on commit 25c747e

Please sign in to comment.