diff --git a/CREDITS.md b/CREDITS.md index 8a2c955b1e..52e95c2eab 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -662,7 +662,9 @@ This page lists all the individual contributions to the project by their author. - Return warhead - `ElectricAssault` weapons can now auto acquire allies' overpowerable defenses - **NaotoYuuki** - Vertical & meteor trajectory projectile prototypes -- **handama** - AI script action to `16005 Jump Back To Previous Script` +- **handama**: + - AI script action to `16005 Jump Back To Previous Script` + - Fix AI team recruitment inconsistency causing underfilled teams - **TaranDahl (航味麻酱)**: - Skirmish AI "sell all buildings and set all technos to hunt" behavior dehardcode - Skirmish AI "gather when MCV deploy" behavior dehardcode diff --git a/YRpp b/YRpp index 97f03d8bdc..4faf00803d 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit 97f03d8bdc7ebeda1a6e0848a7bd81a4662c52fc +Subproject commit 4faf00803dbcab04eca19078d8657c3fd0038c26 diff --git a/docs/AI-Scripting-and-Mapping.md b/docs/AI-Scripting-and-Mapping.md index e5d82cfd1a..ef4402c666 100644 --- a/docs/AI-Scripting-and-Mapping.md +++ b/docs/AI-Scripting-and-Mapping.md @@ -13,6 +13,7 @@ This page describes all AI scripting and mapping related additions and changes i - Teams spawned by trigger action 7,80,107 can use IFV and opentopped logic normally. - If a pre-placed building has a `NaturalParticleSystem`, it used to always be created when the game starts. This has been removed. - Superweapons used by AI for script actions `56 Chronoshift to Building`, `57 Chronoshift to a Target Type` and `10104 Chronoshift to Enemy Base` can now be explicitly set via `[General] -> AIChronoSphereSW` & `AIChronoWarpSW` respectively. If `AIChronoSphereSW` is set but `AIChronoWarpSW` is not, game will check former's `SW.PostDependent` for a second superweapon to use. Otherwise if not set, last superweapon listed in `[SuperWeaponTypes]` with `Type=ChronoSphere` or `Type=ChronoWarp` will be used, respectively. +- Fixed AI team recruitment inconsistency causing underfilled teams. ### Increased Overlay Limit diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 2e4916855f..52c809cf6f 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -652,6 +652,7 @@ Vanilla fixes: - Enabled playing ingame movie in non-campaign modes (i.e. trigger action `100 Play Sidebar Movie...` and `117 Play Sidebar Movie and pause...`) (by TaranDahl) - `ElectricAssault` weapons can now auto acquire allies' overpowerable defenses (by Ollerus) - Fixed the issue that the time for units in the area guard mission to reacquire targets after eliminating the target is significantly longer than that in other missions (by TaranDahl) +- Fixed AI team recruitment inconsistency causing underfilled teams (by handama) Phobos fixes: - Fixed the bug that `AllowAirstrike=no` cannot completely prevent air strikes from being launched against it (by NetsuNegi) diff --git a/src/Ext/Techno/Body.cpp b/src/Ext/Techno/Body.cpp index 2646b31b12..6c5a99f768 100644 --- a/src/Ext/Techno/Body.cpp +++ b/src/Ext/Techno/Body.cpp @@ -1,4 +1,4 @@ -#include "Body.h" +#include "Body.h" #include @@ -884,6 +884,33 @@ void TechnoExt::ClickedApproachObject(FootClass* pThis, ObjectClass* pObject) event.AddEvent(); } +bool TechnoExt::CanBeRecruitedFix(FootClass* pThis, HouseClass* pHouse) +{ + const bool inTeam = pThis->Team != nullptr; + const bool available = pThis->IsAlive && pThis->Health > 0 && !pThis->InLimbo; + const bool wrongOwner = pThis->Owner != pHouse; + + if (inTeam || !available || wrongOwner) + return false; + + const bool canRecruit = pThis->RecruitableA && pThis->RecruitableB; + if (!canRecruit) + return false; + + const Mission mission = pThis->GetCurrentMission(); + + if (!MissionClass::IsRecruitableMission(mission)) + return false; + + const bool validState = + !(pThis->ShouldEnterAbsorber || pThis->ShouldEnterOccupiable || pThis->ShouldGarrisonStructure) && + pThis->DrainTarget == nullptr && + !pThis->BunkerLinkedItem && + pThis->LocomotorSource == nullptr; + + return validState; +} + bool TechnoExt::EjectRandomly(FootClass* pEjectee, const CoordStruct& coords, int distance, bool select) { std::vector usableCoords; diff --git a/src/Ext/Techno/Body.h b/src/Ext/Techno/Body.h index 20ec1e7c6a..4f6279d8d4 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -310,6 +310,7 @@ class TechnoExt static bool SimpleDeployerAllowedToDeploy(UnitClass* pThis, bool defaultValue, bool alwaysCheckLandTypes); static void ShowPromoteAnim(TechnoClass* pThis); static void ClickedApproachObject(FootClass* pThis, ObjectClass* pObject); + static bool CanBeRecruitedFix(FootClass* pThis, HouseClass* pHouse); static bool EjectRandomly(FootClass* pEjectee, const CoordStruct& coords, int distance, bool select); static bool EjectSurvivor(FootClass* pSurvivor, CoordStruct coords, bool select); diff --git a/src/Ext/Techno/Hooks.cpp b/src/Ext/Techno/Hooks.cpp index 66e13ba5c0..bb8687c887 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -1972,6 +1972,18 @@ DEFINE_HOOK(0x4D4B43, FootClass_Mission_Capture, 0x6) return LosesDestination; } +DEFINE_HOOK(0x4DA230, FootClass_CanBeRecruited, 0x5) +{ + enum { SkipGameCode = 0x4DA294 }; + + GET(FootClass*, pThis, ECX); + GET_STACK(HouseClass*, pHouse, 0x4); + + R->AL(TechnoExt::CanBeRecruitedFix(pThis, pHouse)); + + return SkipGameCode; +} + #pragma region DynamicSight DEFINE_HOOK(0x41AE00, AircraftClass_See_DynamicSight, 0x6)