From bbb3284187aaae6b4483d761b2db800cb17687f5 Mon Sep 17 00:00:00 2001 From: handama <55939089+handama@users.noreply.github.com> Date: Wed, 15 Apr 2026 14:58:30 +0800 Subject: [PATCH 1/7] Fix AI team recruitment inconsistency causing underfilled teams --- YRpp | 2 +- src/Ext/Techno/Body.cpp | 31 ++++++++++++++++++++++++++++++- src/Ext/Techno/Body.h | 3 ++- src/Ext/Techno/Hooks.cpp | 12 ++++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/YRpp b/YRpp index d512ac7ff5..85ecc24065 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit d512ac7ff5a65cfb72e2bca775f13c797304afb1 +Subproject commit 85ecc240657a918fd3e54b4cf7548fb44c7e8b35 diff --git a/src/Ext/Techno/Body.cpp b/src/Ext/Techno/Body.cpp index a1a5987a1a..3d202a1da5 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,35 @@ void TechnoExt::ClickedApproachObject(FootClass* pThis, ObjectClass* pObject) event.AddEvent(); } +bool TechnoExt::CanBeRecruitedFix(FootClass* pThis, HouseClass* pHouse) +{ + if (!pThis || !pHouse) return false; + + 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 bfc21c09d1..38a0527ca8 100644 --- a/src/Ext/Techno/Body.h +++ b/src/Ext/Techno/Body.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -309,6 +309,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 96c7d24059..6429d9316c 100644 --- a/src/Ext/Techno/Hooks.cpp +++ b/src/Ext/Techno/Hooks.cpp @@ -1971,3 +1971,15 @@ 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; +} From 500adfd31a4becf2e05b410dc072018f51f43c5c Mon Sep 17 00:00:00 2001 From: handama <55939089+handama@users.noreply.github.com> Date: Wed, 15 Apr 2026 15:04:10 +0800 Subject: [PATCH 2/7] update document --- CREDITS.md | 4 +++- docs/Whats-New.md | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CREDITS.md b/CREDITS.md index a9fdc39683..14bfef5c2a 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -660,7 +660,9 @@ This page lists all the individual contributions to the project by their author. - Maximum amount for power plant enhancer - Return warhead - **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/docs/Whats-New.md b/docs/Whats-New.md index 0b109974ed..e30b02a792 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -638,6 +638,7 @@ Vanilla fixes: - Fixed the bug where non-Teleporter miners would not return to work after minerals are depleted and then regenerated (by TaranDahl) - Miners back to work when ore regenerated (by TaranDahl) - Fixed the incorrect mission switching in infantry EnterIdleMode (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) From 76a529eaa39653a2716447ffafec53140cf721f2 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Wed, 15 Apr 2026 17:58:16 +0800 Subject: [PATCH 3/7] Supplement the document to pass the check --- docs/AI-Scripting-and-Mapping.md | 1 + 1 file changed, 1 insertion(+) 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 From 65a396f9d0febbd00185f7347751c207631f613c Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Wed, 15 Apr 2026 17:58:42 +0800 Subject: [PATCH 4/7] Remove extra spaces --- docs/Whats-New.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Whats-New.md b/docs/Whats-New.md index e30b02a792..2addd81127 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -638,7 +638,7 @@ Vanilla fixes: - Fixed the bug where non-Teleporter miners would not return to work after minerals are depleted and then regenerated (by TaranDahl) - Miners back to work when ore regenerated (by TaranDahl) - Fixed the incorrect mission switching in infantry EnterIdleMode (by TaranDahl) -- Fixed AI team recruitment inconsistency causing underfilled teams (by handama) +- 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) From 85c264c4c06c73334759ccb8b258f8f67b95eb1f Mon Sep 17 00:00:00 2001 From: handama <55939089+handama@users.noreply.github.com> Date: Sat, 18 Apr 2026 20:11:57 +0800 Subject: [PATCH 5/7] remove unnecessary check --- src/Ext/Techno/Body.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Ext/Techno/Body.cpp b/src/Ext/Techno/Body.cpp index 3d202a1da5..4f41545154 100644 --- a/src/Ext/Techno/Body.cpp +++ b/src/Ext/Techno/Body.cpp @@ -886,8 +886,6 @@ void TechnoExt::ClickedApproachObject(FootClass* pThis, ObjectClass* pObject) bool TechnoExt::CanBeRecruitedFix(FootClass* pThis, HouseClass* pHouse) { - if (!pThis || !pHouse) return false; - const bool inTeam = pThis->Team != nullptr; const bool available = pThis->IsAlive && pThis->Health > 0 && !pThis->InLimbo; const bool wrongOwner = pThis->Owner != pHouse; From f34ef4d67a28871700953430825da81202132a19 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Tue, 5 May 2026 22:29:52 +0800 Subject: [PATCH 6/7] update --- YRpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/YRpp b/YRpp index 4faf00803d..97f03d8bdc 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit 4faf00803dbcab04eca19078d8657c3fd0038c26 +Subproject commit 97f03d8bdc7ebeda1a6e0848a7bd81a4662c52fc From 58ae161d37649d8b3adf94781843b0f6b11ac953 Mon Sep 17 00:00:00 2001 From: handama <55939089+handama@users.noreply.github.com> Date: Wed, 6 May 2026 03:20:20 +0800 Subject: [PATCH 7/7] Refactor CanBeRecruitedFix for improved performance --- src/Ext/Techno/Body.cpp | 54 +++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/src/Ext/Techno/Body.cpp b/src/Ext/Techno/Body.cpp index 6c5a99f768..1ce68ee1f2 100644 --- a/src/Ext/Techno/Body.cpp +++ b/src/Ext/Techno/Body.cpp @@ -886,29 +886,37 @@ void TechnoExt::ClickedApproachObject(FootClass* pThis, ObjectClass* pObject) 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; + if (pThis->Team != nullptr || + !pThis->IsAlive || + pThis->Health <= 0 || + pThis->InLimbo || + pThis->Owner != pHouse) + { + return false; + } + + if (!(pThis->RecruitableA && pThis->RecruitableB)) + { + return false; + } + + const Mission mission = pThis->GetCurrentMission(); + if (!MissionClass::IsRecruitableMission(mission)) + { + return false; + } + + if (pThis->ShouldEnterAbsorber || + pThis->ShouldEnterOccupiable || + pThis->ShouldGarrisonStructure || + pThis->DrainTarget != nullptr || + pThis->BunkerLinkedItem || + pThis->LocomotorSource != nullptr) + { + return false; + } + + return true; } bool TechnoExt::EjectRandomly(FootClass* pEjectee, const CoordStruct& coords, int distance, bool select)