From 775adae5de8f6e58ac0e7349608143902ab8b554 Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:21:18 +0800 Subject: [PATCH 1/6] update --- src/Ext/HouseType/Hooks.cpp | 20 +++++++++----------- src/Misc/Hooks.Ares.cpp | 21 +++++++++++++++++++++ src/Utilities/AresAddressInit.cpp | 16 +++++++++++----- src/Utilities/AresFunctions.h | 6 ++++-- 4 files changed, 45 insertions(+), 18 deletions(-) diff --git a/src/Ext/HouseType/Hooks.cpp b/src/Ext/HouseType/Hooks.cpp index 9776e70bef..0b3cabfd1a 100644 --- a/src/Ext/HouseType/Hooks.cpp +++ b/src/Ext/HouseType/Hooks.cpp @@ -36,22 +36,20 @@ DEFINE_HOOK(0x68AD0C, ScenarioClass_ReadMap_SetEVAIndex, 0x7) return 0; } -DEFINE_HOOK(0x707DCF, TechnoClass_GetCrew_NationalOverride, 0x5) +// It takes effect when `Ares.dll` does not exist. +DEFINE_HOOK(0x707D40, TechnoClass_GetCrew_NationalOverride, 0x6) { - GET(TechnoClass*, pThis, ECX); + enum { SkipGameCode = 0x707D81 }; - if (!pThis) - return 0; + GET(HouseClass* const, pHouse, ECX); - HouseClass* pHouse = pThis->Owner; - - if (!pHouse) - return 0; - - auto const pHouseTypeExt = HouseTypeExt::Fetch(pHouse->Type); + auto const pHouseTypeExt = HouseTypeExt::ExtMap.Find(pHouse->Type); if (pHouseTypeExt->Crew.isset()) - R->EAX(pHouseTypeExt->Crew.Get()); + { + R->ESI(pHouseTypeExt->Crew.Get()); + return SkipGameCode; + } return 0; } diff --git a/src/Misc/Hooks.Ares.cpp b/src/Misc/Hooks.Ares.cpp index 031a5f10ec..f116d7a62f 100644 --- a/src/Misc/Hooks.Ares.cpp +++ b/src/Misc/Hooks.Ares.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -245,6 +246,20 @@ static bool __fastcall AresHouseExt_UpdateKeepAlive(AresHouseExt* pExt_Ares, voi #pragma endregion +#pragma region AresGetCrew + +static InfantryTypeClass* __fastcall AresHouseExt_GetCrew(HouseClass** pExt_Ares, void*) +{ + auto const pTypeExt = HouseTypeExt::Fetch((*pExt_Ares)->Type); + + if (pTypeExt->Crew.isset()) + return pTypeExt->Crew.Get(); + + return AresFunctions::GetSideCrew(pExt_Ares); +} + +#pragma endregion + DEFINE_HOOK(0x440580, BuildingClass_Unlimbo_UnitDeliveryFix, 0x5) { if (UnitDeliveryTemp::Placing) @@ -383,6 +398,9 @@ void Apply_Ares3_0_Patches() // Ares' `KeepAlive` adds global tags. Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x21F70, GET_OFFSET(AresHouseExt_UpdateKeepAlive)); + + // Add a new custom crew for a country. + Patch::Apply_CALL(AresHelper::AresBaseAddress + 0x4C836, GET_OFFSET(AresHouseExt_GetCrew)); } void Apply_Ares3_0p1_Patches() @@ -504,4 +522,7 @@ void Apply_Ares3_0p1_Patches() // Ares' `KeepAlive` adds global tags. Patch::Apply_LJMP(AresHelper::AresBaseAddress + 0x229F0, GET_OFFSET(AresHouseExt_UpdateKeepAlive)); + + // Add a new custom crew for a country. + Patch::Apply_CALL(AresHelper::AresBaseAddress + 0x4D496, GET_OFFSET(AresHouseExt_GetCrew)); } diff --git a/src/Utilities/AresAddressInit.cpp b/src/Utilities/AresAddressInit.cpp index 08576b92b8..f4df3ed3ed 100644 --- a/src/Utilities/AresAddressInit.cpp +++ b/src/Utilities/AresAddressInit.cpp @@ -7,7 +7,6 @@ decltype(AresFunctions::ConvertTypeTo) AresFunctions::ConvertTypeTo = nullptr; decltype(AresFunctions::CreateAresEBolt) AresFunctions::CreateAresEBolt = nullptr; decltype(AresFunctions::SpawnSurvivors) AresFunctions::SpawnSurvivors = nullptr; -decltype(AresFunctions::ReverseEngineer) AresFunctions::ReverseEngineer = nullptr; decltype(AresFunctions::IsTargetConstraintsEligible) AresFunctions::IsTargetConstraintsEligible = nullptr; decltype(AresFunctions::UnitDeliveryStateMachine_Update) AresFunctions::UnitDeliveryStateMachine_Update = nullptr; decltype(AresFunctions::SetSpotlight) AresFunctions::SetSpotlight = nullptr; @@ -21,6 +20,9 @@ PhobosMap* AresFunctions::BombExtMap = nullptr; decltype(AresFunctions::GetTunnel) AresFunctions::GetTunnel = nullptr; decltype(AresFunctions::AddPassengerFromTunnel) AresFunctions::AddPassengerFromTunnel = nullptr; +decltype(AresFunctions::ReverseEngineer) AresFunctions::ReverseEngineer = nullptr; +decltype(AresFunctions::GetSideCrew) AresFunctions::GetSideCrew = nullptr; + decltype(AresFunctions::FindEVAIndex) AresFunctions::FindEVAIndex = nullptr; void* AresFunctions::_SWTypeExtMap = nullptr; @@ -46,8 +48,6 @@ void AresFunctions::InitAres3_0() NOTE_ARES_FUN(SpawnSurvivors, 0x464C0); } - NOTE_ARES_FUN(ReverseEngineer, 0x022360); - NOTE_ARES_FUN(IsTargetConstraintsEligible, 0x032110); NOTE_ARES_FUN(UnitDeliveryStateMachine_Update, 0x075DE0); @@ -71,6 +71,10 @@ void AresFunctions::InitAres3_0() NOTE_ARES_FUN(AresFunctions::GetTunnel, 0x0D740); NOTE_ARES_FUN(AresFunctions::AddPassengerFromTunnel, 0x09000); + // HouseExt + NOTE_ARES_FUN(ReverseEngineer, 0x022360); + NOTE_ARES_FUN(GetSideCrew, 0x021230); + // VoxClass NOTE_ARES_FUN(AresFunctions::FindEVAIndex, 0x063560); @@ -96,8 +100,6 @@ void AresFunctions::InitAres3_0p1() NOTE_ARES_FUN(SpawnSurvivors, 0x47030); } - NOTE_ARES_FUN(ReverseEngineer, 0x022DE0); - NOTE_ARES_FUN(IsTargetConstraintsEligible, 0x032AF0); NOTE_ARES_FUN(UnitDeliveryStateMachine_Update, 0x076E90); @@ -121,6 +123,10 @@ void AresFunctions::InitAres3_0p1() NOTE_ARES_FUN(AresFunctions::GetTunnel, 0x0DA30); NOTE_ARES_FUN(AresFunctions::AddPassengerFromTunnel, 0x09040); + // HouseExt + NOTE_ARES_FUN(ReverseEngineer, 0x022DE0); + NOTE_ARES_FUN(GetSideCrew, 0x021CB0); + // VoxClass NOTE_ARES_FUN(AresFunctions::FindEVAIndex, 0x0642B0); diff --git a/src/Utilities/AresFunctions.h b/src/Utilities/AresFunctions.h index 41b09b148f..7211cf1a3e 100644 --- a/src/Utilities/AresFunctions.h +++ b/src/Utilities/AresFunctions.h @@ -33,8 +33,6 @@ class AresFunctions static void(__stdcall* SpawnSurvivors)(FootClass* pThis, TechnoClass* pKiller, bool Select, bool PreventEscape); - static bool(__thiscall* ReverseEngineer)(void* pAresHouseExt, TechnoTypeClass* pType); - static bool(__thiscall* IsTargetConstraintsEligible)(void*, HouseClass*, bool); static void(__thiscall* UnitDeliveryStateMachine_Update)(void*); @@ -57,6 +55,10 @@ class AresFunctions static void* (__thiscall* GetTunnel)(void*, HouseClass*); static void(__thiscall* AddPassengerFromTunnel)(void*, BuildingClass*, FootClass*); + // HouseExt + static bool(__thiscall* ReverseEngineer)(void*, TechnoTypeClass* pType); + static InfantryTypeClass* (__thiscall* GetSideCrew)(void*); + // VoxClass static int(__stdcall* FindEVAIndex)(const char* buffer); private: From 4368c8c6f9617493921411153a3a98adb187dd36 Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:32:01 +0800 Subject: [PATCH 2/6] fix --- src/Ext/HouseType/Hooks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ext/HouseType/Hooks.cpp b/src/Ext/HouseType/Hooks.cpp index 0b3cabfd1a..43a4f5bc35 100644 --- a/src/Ext/HouseType/Hooks.cpp +++ b/src/Ext/HouseType/Hooks.cpp @@ -43,7 +43,7 @@ DEFINE_HOOK(0x707D40, TechnoClass_GetCrew_NationalOverride, 0x6) GET(HouseClass* const, pHouse, ECX); - auto const pHouseTypeExt = HouseTypeExt::ExtMap.Find(pHouse->Type); + auto const pHouseTypeExt = HouseTypeExt::Fetch(pHouse->Type); if (pHouseTypeExt->Crew.isset()) { From eeb28fb573025ff5101c750e3f6d5f26ff38a535 Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:45:19 +0800 Subject: [PATCH 3/6] ok --- src/Misc/Hooks.Ares.cpp | 2 +- src/Utilities/AresAddressInit.cpp | 6 +++--- src/Utilities/AresFunctions.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Misc/Hooks.Ares.cpp b/src/Misc/Hooks.Ares.cpp index f116d7a62f..90d6e63a4c 100644 --- a/src/Misc/Hooks.Ares.cpp +++ b/src/Misc/Hooks.Ares.cpp @@ -255,7 +255,7 @@ static InfantryTypeClass* __fastcall AresHouseExt_GetCrew(HouseClass** pExt_Ares if (pTypeExt->Crew.isset()) return pTypeExt->Crew.Get(); - return AresFunctions::GetSideCrew(pExt_Ares); + return AresFunctions::GetCrew(pExt_Ares); } #pragma endregion diff --git a/src/Utilities/AresAddressInit.cpp b/src/Utilities/AresAddressInit.cpp index f4df3ed3ed..bbc56e475c 100644 --- a/src/Utilities/AresAddressInit.cpp +++ b/src/Utilities/AresAddressInit.cpp @@ -21,7 +21,7 @@ decltype(AresFunctions::GetTunnel) AresFunctions::GetTunnel = nullptr; decltype(AresFunctions::AddPassengerFromTunnel) AresFunctions::AddPassengerFromTunnel = nullptr; decltype(AresFunctions::ReverseEngineer) AresFunctions::ReverseEngineer = nullptr; -decltype(AresFunctions::GetSideCrew) AresFunctions::GetSideCrew = nullptr; +decltype(AresFunctions::GetCrew) AresFunctions::GetCrew = nullptr; decltype(AresFunctions::FindEVAIndex) AresFunctions::FindEVAIndex = nullptr; @@ -73,7 +73,7 @@ void AresFunctions::InitAres3_0() // HouseExt NOTE_ARES_FUN(ReverseEngineer, 0x022360); - NOTE_ARES_FUN(GetSideCrew, 0x021230); + NOTE_ARES_FUN(GetCrew, 0x021230); // VoxClass NOTE_ARES_FUN(AresFunctions::FindEVAIndex, 0x063560); @@ -125,7 +125,7 @@ void AresFunctions::InitAres3_0p1() // HouseExt NOTE_ARES_FUN(ReverseEngineer, 0x022DE0); - NOTE_ARES_FUN(GetSideCrew, 0x021CB0); + NOTE_ARES_FUN(GetCrew, 0x021CB0); // VoxClass NOTE_ARES_FUN(AresFunctions::FindEVAIndex, 0x0642B0); diff --git a/src/Utilities/AresFunctions.h b/src/Utilities/AresFunctions.h index 7211cf1a3e..0a3eb40c49 100644 --- a/src/Utilities/AresFunctions.h +++ b/src/Utilities/AresFunctions.h @@ -57,7 +57,7 @@ class AresFunctions // HouseExt static bool(__thiscall* ReverseEngineer)(void*, TechnoTypeClass* pType); - static InfantryTypeClass* (__thiscall* GetSideCrew)(void*); + static InfantryTypeClass* (__thiscall* GetCrew)(void*); // VoxClass static int(__stdcall* FindEVAIndex)(const char* buffer); From 9f0a67c79f3c161e66ad20695d4206e786613d24 Mon Sep 17 00:00:00 2001 From: Fly-Star <100747645+a851903106@users.noreply.github.com> Date: Wed, 9 Sep 2026 13:52:19 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E6=9B=B4=E6=96=B0=20Hooks.cpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Ext/HouseType/Hooks.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ext/HouseType/Hooks.cpp b/src/Ext/HouseType/Hooks.cpp index 43a4f5bc35..7b6204a51f 100644 --- a/src/Ext/HouseType/Hooks.cpp +++ b/src/Ext/HouseType/Hooks.cpp @@ -36,7 +36,7 @@ DEFINE_HOOK(0x68AD0C, ScenarioClass_ReadMap_SetEVAIndex, 0x7) return 0; } -// It takes effect when `Ares.dll` does not exist. +// Ares has taken over TechnoClass_GetCrew, so usually it won't work. DEFINE_HOOK(0x707D40, TechnoClass_GetCrew_NationalOverride, 0x6) { enum { SkipGameCode = 0x707D81 }; From e8a91b5c603c8c19f0c1367cc5897d4552b40960 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Wed, 9 Sep 2026 15:34:13 +0800 Subject: [PATCH 5/6] pass CREDITS check & update Changelog --- CREDITS.md | 1 + docs/Whats-New.md | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CREDITS.md b/CREDITS.md index b6177be989..136c53531e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -446,6 +446,7 @@ This page lists all the individual contributions to the project by their author. - SkipMapSelect Enhancement - Add a global default value for `KeepAlive` - Customized transport plane for teams + - Fix the bug where *Customizable crew type per country* overrides the pre-techno settings - **NetsuNegi**: - Forbidding parallel AI queues by type - Jumpjet crash speed fix when crashing onto building diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 913d3d774a..b1ef96256a 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -442,7 +442,7 @@ HideShakeEffects=false ; boolean - [Draw offset rules for AttachEffect animations](New-or-Enhanced-Logics.md#attached-effects) (by Starkku) - [Allowed customize that whether `Temporal=yes` warhead will cause target building animation poweroff](Fixed-or-Improved-Logics.md#allow-customize-that-whether-temporal-yes-warhead-will-cause-target-building-animation-poweroff) (by NetsuNegi) - Country-based attached effects (by Ollerus) -- [Customizable crew type per country](Fixed-or-Improved-Logics.md#customizable-crew-type-per-country) (by Sovietianqi) +- [Customizable crew type per country](Fixed-or-Improved-Logics.md#customizable-crew-type-per-country) (by Sovietianqi & FlyStar) #### Vanilla fixes: - Fixed the bug where a building with `Factory=BuildingType` owned by the AI did not play `ProductionAnim` when placing a produced building (by Noble_Fish) From d64b4f3b4799e0bb6d89b75f49a13a62ba3d2915 Mon Sep 17 00:00:00 2001 From: Noble_Fish <1065703286@qq.com> Date: Wed, 9 Sep 2026 18:48:42 +0800 Subject: [PATCH 6/6] Fix [Country] Crew parse failure by resolving with FindOrAllocate [Country] sections are parsed before the [InfantryTypes] table is registered, so a strict Find for or any infantry id fails there and Crew stays unset. Use InfantryTypeClass::FindOrAllocate like the vanilla veteran list readers (0x524CB0); the type table gets filled in afterwards by Read_InfantryTypes. --- CREDITS.md | 1 + YRpp | 2 +- docs/Whats-New.md | 2 +- src/Ext/HouseType/Body.cpp | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CREDITS.md b/CREDITS.md index 136c53531e..93584cec32 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -763,6 +763,7 @@ This page lists all the individual contributions to the project by their author. - Fix the bug that setting `WalkRate=0` on a TechnoType crashed the game (integer divide-by-zero) the moment an object of that type started moving - Fix the bug where `Ranged=true` causes projectiles using the new Trajectory to ignore settings such as `BounceTimes` - Customizable infantry sequence rates + - Fix the issue that *Customizable crew type per country* not considering parsing order caused game parsing failure and a warning in the log - **Ollerus**: - Build limit group enhancement - Customizable rocker amplitude diff --git a/YRpp b/YRpp index c6c522f77b..9402d7da0f 160000 --- a/YRpp +++ b/YRpp @@ -1 +1 @@ -Subproject commit c6c522f77b58508588d9a8652c53356e4aef7a96 +Subproject commit 9402d7da0fe14d46703ba871ce3e6b3cde855bfc diff --git a/docs/Whats-New.md b/docs/Whats-New.md index b1ef96256a..f4ee88a0b0 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -442,7 +442,7 @@ HideShakeEffects=false ; boolean - [Draw offset rules for AttachEffect animations](New-or-Enhanced-Logics.md#attached-effects) (by Starkku) - [Allowed customize that whether `Temporal=yes` warhead will cause target building animation poweroff](Fixed-or-Improved-Logics.md#allow-customize-that-whether-temporal-yes-warhead-will-cause-target-building-animation-poweroff) (by NetsuNegi) - Country-based attached effects (by Ollerus) -- [Customizable crew type per country](Fixed-or-Improved-Logics.md#customizable-crew-type-per-country) (by Sovietianqi & FlyStar) +- [Customizable crew type per country](Fixed-or-Improved-Logics.md#customizable-crew-type-per-country) (by Sovietianqi, FlyStar, Noble_Fish) #### Vanilla fixes: - Fixed the bug where a building with `Factory=BuildingType` owned by the AI did not play `ProductionAnim` when placing a produced building (by Noble_Fish) diff --git a/src/Ext/HouseType/Body.cpp b/src/Ext/HouseType/Body.cpp index 6d40b7cd10..56cfd4c7db 100644 --- a/src/Ext/HouseType/Body.cpp +++ b/src/Ext/HouseType/Body.cpp @@ -22,7 +22,7 @@ void HouseTypeExt::LoadFromINIFile(CCINIClass* pINI) this->AttachEffects.LoadFromINI(pINI, pSection); this->AttachEffects_AttachOnOwnerChange.Read(exINI, pSection, "AttachEffect.AttachOnOwnerChange"); - this->Crew.Read(exINI, pSection, "Crew"); + this->Crew.Read(exINI, pSection, "Crew"); } template