From fe8f4472c1781a1b19f074026e9691a92d0fcae9 Mon Sep 17 00:00:00 2001 From: Starkku Date: Tue, 27 Aug 2024 18:30:23 +0300 Subject: [PATCH] Allow excluding specific factory buildings from providing MultipleFactory bonus --- CREDITS.md | 1 + docs/Fixed-or-Improved-Logics.md | 10 +++++ docs/Whats-New.md | 1 + src/Ext/BuildingType/Body.cpp | 2 + src/Ext/BuildingType/Body.h | 2 + src/Ext/House/Body.cpp | 68 ++++++++++++++++++++++++++++++++ src/Ext/House/Body.h | 14 +++++++ src/Ext/House/Hooks.cpp | 31 +++++++++++++++ 8 files changed, 129 insertions(+) diff --git a/CREDITS.md b/CREDITS.md index 667fff4b2b..006dc2b80e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -236,6 +236,7 @@ This page lists all the individual contributions to the project by their author. - Customizing height at which subterranean units travel - `MovementZone=Subterannean` harvester fix - AI superweapon delay timer customization + - Disabling `MultipleFactory` bonus from specific BuildingType - **Morton (MortonPL)**: - `XDrawOffset` for animations - Shield passthrough & absorption diff --git a/docs/Fixed-or-Improved-Logics.md b/docs/Fixed-or-Improved-Logics.md index c4a6ca02cc..b4a7837d6a 100644 --- a/docs/Fixed-or-Improved-Logics.md +++ b/docs/Fixed-or-Improved-Logics.md @@ -360,6 +360,16 @@ In `rulesmd.ini`: SellBuildupLength=23 ; integer, number of buildup frames to play ``` +### Exclude Factory from providing multiple factory bonus + +- It is now possible to exclude a building with `Factory` from counting towards `MultipleFactory` bonus. + +In `rulesmd.ini`: +```ini +[SOMEBUILDING] ; BuildingType +ExcludeFromMultipleFactoryBonus=false ; boolean +``` + ## Particle systems ### Fire particle target coordinate adjustment when firer rotates diff --git a/docs/Whats-New.md b/docs/Whats-New.md index 489bfdd2cb..825ab7cdc6 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -441,6 +441,7 @@ New: - Allow customizing voxel light source position (by Kerbiter, Morton, based on knowledge of thomassnedon) - Option to fix voxel light source being offset and incorrectly tilting on slopes (by Kerbiter) - AI superweapon delay timer customization (by Starkku) +- Disabling `MultipleFactory` bonus from specific BuildingType (by Starkku) Vanilla fixes: - Allow AI to repair structures built from base nodes/trigger action 125/SW delivery in single player missions (by Trsdy) diff --git a/src/Ext/BuildingType/Body.cpp b/src/Ext/BuildingType/Body.cpp index 6863d35cf6..fd094732fc 100644 --- a/src/Ext/BuildingType/Body.cpp +++ b/src/Ext/BuildingType/Body.cpp @@ -131,6 +131,7 @@ void BuildingTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->CanC4_AllowZeroDamage.Read(exINI, pSection, "CanC4.AllowZeroDamage"); this->InitialStrength_Cloning.Read(exINI, pSection, "InitialStrength.Cloning"); + this->ExcludeFromMultipleFactoryBonus.Read(exINI, pSection, "ExcludeFromMultipleFactoryBonus"); this->Grinding_AllowAllies.Read(exINI, pSection, "Grinding.AllowAllies"); this->Grinding_AllowOwner.Read(exINI, pSection, "Grinding.AllowOwner"); @@ -233,6 +234,7 @@ void BuildingTypeExt::ExtData::Serialize(T& Stm) .Process(this->AllowAirstrike) .Process(this->CanC4_AllowZeroDamage) .Process(this->InitialStrength_Cloning) + .Process(this->ExcludeFromMultipleFactoryBonus) .Process(this->Refinery_UseStorage) .Process(this->Grinding_AllowAllies) .Process(this->Grinding_AllowOwner) diff --git a/src/Ext/BuildingType/Body.h b/src/Ext/BuildingType/Body.h index d31cacc10a..043b0ee393 100644 --- a/src/Ext/BuildingType/Body.h +++ b/src/Ext/BuildingType/Body.h @@ -32,6 +32,7 @@ class BuildingTypeExt Valueable CanC4_AllowZeroDamage; Valueable Refinery_UseStorage; Valueable> InitialStrength_Cloning; + Valueable ExcludeFromMultipleFactoryBonus; ValueableIdx Grinding_Sound; Valueable Grinding_Weapon; @@ -75,6 +76,7 @@ class BuildingTypeExt , AllowAirstrike {} , CanC4_AllowZeroDamage { false } , InitialStrength_Cloning { { 1.0, 0.0 } } + , ExcludeFromMultipleFactoryBonus { false } , Refinery_UseStorage { false } , Grinding_AllowAllies { false } , Grinding_AllowOwner { true } diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp index 59b82738c7..673536259b 100644 --- a/src/Ext/House/Body.cpp +++ b/src/Ext/House/Body.cpp @@ -494,6 +494,69 @@ int HouseExt::ExtData::CountOwnedPresentAndLimboed(TechnoTypeClass* pTechnoType) return count; } +void HouseExt::ExtData::UpdateNonMFBFactoryCounts(AbstractType rtti, bool remove, bool isNaval) +{ + int* count = nullptr; + + switch (rtti) + { + case AbstractType::Aircraft: + case AbstractType::AircraftType: + count = &this->NumAirpads_NonMFB; + break; + case AbstractType::Building: + case AbstractType::BuildingType: + count = &this->NumConYards_NonMFB; + break; + case AbstractType::Infantry: + case AbstractType::InfantryType: + count = &this->NumBarracks_NonMFB; + break; + case AbstractType::Unit: + case AbstractType::UnitType: + count = isNaval ? &this->NumShipyards_NonMFB : &this->NumWarFactories_NonMFB; + break; + default: + break; + } + + if (count) + *count += remove ? -1 : 1; +} + +int HouseExt::ExtData::GetFactoryCountWithoutNonMFB(AbstractType rtti, bool isNaval) +{ + auto const pThis = this->OwnerObject(); + int count = 0; + + switch (rtti) + { + case AbstractType::Aircraft: + case AbstractType::AircraftType: + count = pThis->NumAirpads - this->NumAirpads_NonMFB; + break; + case AbstractType::Building: + case AbstractType::BuildingType: + count = pThis->NumConYards - this->NumConYards_NonMFB; + break; + case AbstractType::Infantry: + case AbstractType::InfantryType: + count = pThis->NumBarracks - this->NumBarracks_NonMFB; + break; + case AbstractType::Unit: + case AbstractType::UnitType: + if (isNaval) + count = pThis->NumShipyards - this->NumShipyards_NonMFB; + else + count = pThis->NumWarFactories - this->NumWarFactories_NonMFB; + break; + default: + break; + } + + return Math::max(count, 0); +} + void HouseExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) { const char* pSection = this->OwnerObject()->PlainName; @@ -533,6 +596,11 @@ void HouseExt::ExtData::Serialize(T& Stm) .Process(this->RepairBaseNodes) .Process(this->LastBuiltNavalVehicleType) .Process(this->ProducingNavalUnitTypeIndex) + .Process(this->NumAirpads_NonMFB) + .Process(this->NumBarracks_NonMFB) + .Process(this->NumWarFactories_NonMFB) + .Process(this->NumConYards_NonMFB) + .Process(this->NumShipyards_NonMFB) ; } diff --git a/src/Ext/House/Body.h b/src/Ext/House/Body.h index 68ae82ee02..33634ce962 100644 --- a/src/Ext/House/Body.h +++ b/src/Ext/House/Body.h @@ -43,6 +43,13 @@ class HouseExt int LastBuiltNavalVehicleType; int ProducingNavalUnitTypeIndex; + // Factories that exist but don't count towards multiple factory bonus. + int NumAirpads_NonMFB; + int NumBarracks_NonMFB; + int NumWarFactories_NonMFB; + int NumConYards_NonMFB; + int NumShipyards_NonMFB; + ExtData(HouseClass* OwnerObject) : Extension(OwnerObject) , PowerPlantEnhancers {} , OwnedLimboDeliveredBuildings {} @@ -59,12 +66,19 @@ class HouseExt , RepairBaseNodes { false,false,false } , LastBuiltNavalVehicleType { -1 } , ProducingNavalUnitTypeIndex { -1 } + , NumAirpads_NonMFB { 0 } + , NumBarracks_NonMFB { 0 } + , NumWarFactories_NonMFB { 0 } + , NumConYards_NonMFB { 0 } + , NumShipyards_NonMFB { 0 } { } bool OwnsLimboDeliveredBuilding(BuildingClass* pBuilding); void AddToLimboTracking(TechnoTypeClass* pTechnoType); void RemoveFromLimboTracking(TechnoTypeClass* pTechnoType); int CountOwnedPresentAndLimboed(TechnoTypeClass* pTechnoType); + void UpdateNonMFBFactoryCounts(AbstractType rtti, bool remove, bool isNaval); + int GetFactoryCountWithoutNonMFB(AbstractType rtti, bool isNaval); virtual ~ExtData() = default; diff --git a/src/Ext/House/Hooks.cpp b/src/Ext/House/Hooks.cpp index f0a198aef0..ad359b511a 100644 --- a/src/Ext/House/Hooks.cpp +++ b/src/Ext/House/Hooks.cpp @@ -306,3 +306,34 @@ DEFINE_HOOK(0x4F9038, HouseClass_AI_Superweapons, 0x5) return 0; } + +DEFINE_HOOK_AGAIN(0x4FFA99, HouseClass_ExcludeFromMultipleFactoryBonus, 0x6) +DEFINE_HOOK(0x4FF9C9, HouseClass_ExcludeFromMultipleFactoryBonus, 0x6) +{ + GET(BuildingClass*, pBuilding, ESI); + + if (BuildingTypeExt::ExtMap.Find(pBuilding->Type)->ExcludeFromMultipleFactoryBonus) + { + GET(HouseClass*, pThis, EDI); + GET(bool, isNaval, ECX); + + auto const pExt = HouseExt::ExtMap.Find(pThis); + pExt->UpdateNonMFBFactoryCounts(pBuilding->Type->Factory, R->Origin() == 0x4FF9C9, isNaval); + } + + return 0; +} + +DEFINE_HOOK(0x500910, HouseClass_GetFactoryCount, 0x5) +{ + enum { SkipGameCode = 0x50095D }; + + GET(HouseClass*, pThis, ECX); + GET_STACK(AbstractType, rtti, 0x4); + GET_STACK(bool, isNaval, 0x8); + + auto const pExt = HouseExt::ExtMap.Find(pThis); + R->EAX(pExt->GetFactoryCountWithoutNonMFB(rtti, isNaval)); + + return SkipGameCode; +}