diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ed6c4710..469b1905f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/Jobs/FOCUSFIRE_CONTROL.eai b/Jobs/FOCUSFIRE_CONTROL.eai index 73ce0285a..c2bf016f1 100644 --- a/Jobs/FOCUSFIRE_CONTROL.eai +++ b/Jobs/FOCUSFIRE_CONTROL.eai @@ -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 @@ -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) diff --git a/Jobs/MICRO_HERO.eai b/Jobs/MICRO_HERO.eai index 9c404ce14..815e946b7 100644 --- a/Jobs/MICRO_HERO.eai +++ b/Jobs/MICRO_HERO.eai @@ -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) diff --git a/Jobs/RESET_GUARD_POSITION_ONLY.eai b/Jobs/RESET_GUARD_POSITION_ONLY.eai index e796d0b36..c1fe9e5d4 100644 --- a/Jobs/RESET_GUARD_POSITION_ONLY.eai +++ b/Jobs/RESET_GUARD_POSITION_ONLY.eai @@ -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 diff --git a/Jobs/RESET_WINDWALKER.eai b/Jobs/RESET_WINDWALKER.eai index 27bcbd647..6370a7d42 100644 --- a/Jobs/RESET_WINDWALKER.eai +++ b/Jobs/RESET_WINDWALKER.eai @@ -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 diff --git a/Jobs/RETREAT_CONTROL.eai b/Jobs/RETREAT_CONTROL.eai index 1c5c228a0..ff150f72b 100644 --- a/Jobs/RETREAT_CONTROL.eai +++ b/Jobs/RETREAT_CONTROL.eai @@ -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 @@ -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 @@ -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 @@ -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 diff --git a/common.eai b/common.eai index 7aea70cc0..af032b7ef 100644 --- a/common.eai +++ b/common.eai @@ -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) @@ -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 @@ -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 @@ -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 @@ -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) @@ -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 @@ -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 @@ -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 @@ -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 @@ -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) @@ -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 @@ -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