diff --git a/CREDITS.md b/CREDITS.md index 491db45ce1..d461381b6e 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -543,6 +543,7 @@ This page lists all the individual contributions to the project by their author. - Jumpjet Climbing Logic Enhancement - Fix for pathfinding crashes on big maps due to too small pathfinding node buffer - Fix an issue that units' `LaserTrails` will always lags behind by one frame + - Customized bib & impassable rows & weapons factory direction - **Ollerus**: - Build limit group enhancement - Customizable rocker amplitude diff --git a/docs/New-or-Enhanced-Logics.md b/docs/New-or-Enhanced-Logics.md index 52818ffeaa..d66beff6eb 100644 --- a/docs/New-or-Enhanced-Logics.md +++ b/docs/New-or-Enhanced-Logics.md @@ -586,6 +586,29 @@ Adjacent.Disallowed= ; List of BuildingTypes NoBuildAreaOnBuildup=false ; boolean ``` +### Customized bib & impassable rows & weapons factory direction + +- Now you can use `ExtendedWeaponsFactory` to remove the hard coding of `WeaponsFactory` position and direction, and adjust the position of the generated unit and the direction of the unit's exit separately through the original `ExitCoord` and the newly added `WeaponsFactory.Dir`. Similarly, the directions of `Bib` and `NumberImpassableRows` can also be modified through `Bib.Dir` and `NumberImpassableRows.Dir` respectively. + +In `rulesmd.ini`: +```ini +[General] +ExtendedWeaponsFactory=false ; boolean + +[SOMEBUILDING] ; BuildingType +Bib.Dir=2 ; integer +NumberImpassableRows.Dir=2 ; integer +WeaponsFactory.Dir=2 ; integer +``` + +```{note} +- The available directions are: + - 0 - North (top right) + - 2 - East (bottom right) + - 4 - South (bottom left) + - 6 - West (top left) +``` + ### Destroyable pathfinding obstacles - It is possible to make buildings be considered pathfinding obstacles that can be destroyed by setting `IsDestroyableBlockage` to true. What this does is make the building be considered impassable and impenetrable pathfinding obstacle to every unit that is not flying or have appropriate `MovementZone` (ones that allow destroyable obstacles to be overcome, e.g `(Infantry|Amphibious)Destroyer`) akin to wall overlays and TerrainTypes. diff --git a/docs/Whats-New.md b/docs/Whats-New.md index f8686b7488..701b3e8f78 100644 --- a/docs/Whats-New.md +++ b/docs/Whats-New.md @@ -440,6 +440,7 @@ New: - [Customize hardcoded projectile initial facing behavior](Fixed-or-Improved-Logics.md#customizing-initial-facing-behavior) (by Starkku) - Health bar permanently displayed (by FlyStar) - [`IsSimpleDeployer` facing customization & directional deploy animations](Fixed-or-Improved-Logics.md#issimpleDeployer-facing-and-animation-customization) (by Starkku) +- Customized bib & impassable rows & weapons factory direction (by CrimRecya) Vanilla fixes: - Fixed sidebar not updating queued unit numbers when adding or removing units when the production is on hold (by CrimRecya) diff --git a/src/Ext/Building/Body.cpp b/src/Ext/Building/Body.cpp index 69a1a5c5be..c2ef7c98c7 100644 --- a/src/Ext/Building/Body.cpp +++ b/src/Ext/Building/Body.cpp @@ -360,10 +360,56 @@ void BuildingExt::KickOutStuckUnits(BuildingClass* pThis) auto cell = CellClass::Coord2Cell(buffer); + bool upward = false; + short* pCur = nullptr; + short start = 0; // door + const auto pType = pThis->Type; - const short start = static_cast(pThis->Location.X / Unsorted::LeptonsPerCell + pType->GetFoundationWidth() - 2); // door - const short end = cell.X; // exit - cell.X = start; + + switch (RulesExt::Global()->ExtendedWeaponsFactory ? BuildingTypeExt::ExtMap.Find(pType)->WeaponsFactory_Dir.Get() : 2) + { + + case 0: // North -> left+down/++Y + { + upward = false; + pCur = &cell.Y; + start = static_cast(pThis->Location.Y / Unsorted::LeptonsPerCell + 1); + break; + } + + case 2: // East -> left+up/--X + { + upward = true; + pCur = &cell.X; + start = static_cast(pThis->Location.X / Unsorted::LeptonsPerCell + pType->GetFoundationWidth() - 2); + break; + } + + case 4: // South -> right+up/--Y + { + upward = true; + pCur = &cell.Y; + start = static_cast(pThis->Location.Y / Unsorted::LeptonsPerCell + pType->GetFoundationHeight(false) - 2); + break; + } + + case 6: // West -> right+down/++X + { + upward = false; + pCur = &cell.X; + start = static_cast(pThis->Location.X / Unsorted::LeptonsPerCell + 1); + break; + } + + default: // Invalid direction + { + return; + } + + } + + const short end = *pCur; // exit + *pCur = start; auto pCell = MapClass::Instance.GetCellAt(cell); while (true) @@ -372,7 +418,12 @@ void BuildingExt::KickOutStuckUnits(BuildingClass* pThis) { if (const auto pUnit = abstract_cast(pObject)) { - if (pThis->Owner != pUnit->Owner || pUnit->Locomotor->Destination() != CoordStruct::Empty) + if (pThis->Owner != pUnit->Owner) + continue; + + const auto pLocoDest = pUnit->Locomotor->Destination(); + + if (pLocoDest != CoordStruct::Empty && pLocoDest != pUnit->Location) continue; const auto height = pUnit->GetHeight(); @@ -386,7 +437,7 @@ void BuildingExt::KickOutStuckUnits(BuildingClass* pThis) } } - if (--cell.X < end) + if (upward ? (--(*pCur) < end) : (++(*pCur) > end)) return; // no stuck pCell = MapClass::Instance.GetCellAt(cell); diff --git a/src/Ext/Building/Hooks.cpp b/src/Ext/Building/Hooks.cpp index 92af12c2e1..61e498e39f 100644 --- a/src/Ext/Building/Hooks.cpp +++ b/src/Ext/Building/Hooks.cpp @@ -208,25 +208,6 @@ DEFINE_HOOK(0x44D455, BuildingClass_Mission_Missile_EMPulseBulletWeapon, 0x8) #pragma region KickOutStuckUnits -DEFINE_HOOK(0x44955D, BuildingClass_WeaponFactoryOutsideBusy_WeaponFactoryCell, 0x6) -{ - enum { NotBusy = 0x44969B }; - - GET(BuildingClass* const, pThis, ESI); - - const auto pLink = pThis->GetNthLink(); - - if (!pLink) - return NotBusy; - - const auto pLinkType = pLink->GetTechnoType(); - - if (pLinkType->JumpJet && pLinkType->BalloonHover) - return NotBusy; - - return 0; -} - // Attempt to kick the stuck unit out again by setting the destination DEFINE_HOOK(0x44E202, BuildingClass_Mission_Unload_CheckStuck, 0x6) { @@ -240,17 +221,20 @@ DEFINE_HOOK(0x44E202, BuildingClass_Mission_Unload_CheckStuck, 0x6) if (const auto pUnit = abstract_cast(pThis->GetNthLink())) { // Detecting movement status - if (pUnit->Locomotor->Destination() == CoordStruct::Empty) + const auto pLocoDest = pUnit->Locomotor->Destination(); + + if (pLocoDest == CoordStruct::Empty || pLocoDest == pUnit->Location) { // Evacuate the congestion at the entrance reinterpret_cast(0x449540)(pThis); - const auto pType = pThis->Type; - const auto cell = pThis->GetMapCoords() + pType->FoundationOutside[10]; - const auto door = cell - CellStruct { 1, 0 }; - const auto pDest = MapClass::Instance.GetCellAt(door); + const auto cell = BuildingTypeExt::GetWeaponFactoryDoor(pThis); + const auto pDest = MapClass::Instance.GetCellAt(cell); - // Hover units may stop one cell behind their destination, should forcing them to advance one more cell - pUnit->SetDestination((pUnit->Destination != pDest ? pDest : MapClass::Instance.GetCellAt(cell)), true); + // Hover units may stop one cell behind their destination + if (pUnit->Destination != pDest) + pUnit->SetDestination(pDest, true); + else + pUnit->Locomotor->Move_To(CellClass::Cell2Coord(cell, Unsorted::LevelHeight * pDest->Level)); } } @@ -262,6 +246,15 @@ DEFINE_HOOK(0x44E260, BuildingClass_Mission_Unload_KickOutStuckUnits, 0x7) { GET(BuildingClass*, pThis, EBP); + if (!pThis->IsTether) + { + if (const auto pLink = pThis->GetNthLink()) + { + pThis->SendCommand(RadioCommand::NotifyUnlink, pLink); + pLink->Scatter(pThis->GetCoords(), true, true); + } + } + BuildingExt::KickOutStuckUnits(pThis); return 0; diff --git a/src/Ext/BuildingType/Body.cpp b/src/Ext/BuildingType/Body.cpp index acad4d12e9..c085417d08 100644 --- a/src/Ext/BuildingType/Body.cpp +++ b/src/Ext/BuildingType/Body.cpp @@ -73,6 +73,52 @@ void BuildingTypeExt::PlayBunkerSound(BuildingClass const* pThis, bool buildUp) VocClass::PlayAt(nSound, pThis->Location); } +CellStruct BuildingTypeExt::GetWeaponFactoryDoor(BuildingClass* pThis) +{ + auto cell = pThis->GetMapCoords(); + auto buffer = CoordStruct::Empty; + pThis->GetExitCoords(&buffer, 0); + const auto pType = pThis->Type; + + switch (RulesExt::Global()->ExtendedWeaponsFactory ? BuildingTypeExt::ExtMap.Find(pType)->WeaponsFactory_Dir.Get() : 2) + { + + case 0: + { + cell.X = static_cast(buffer.X / Unsorted::LeptonsPerCell); + break; + } + + case 2: + { + cell.X += static_cast(pType->GetFoundationWidth() - 1); + cell.Y = static_cast(buffer.Y / Unsorted::LeptonsPerCell); + break; + } + + case 4: + { + cell.X = static_cast(buffer.X / Unsorted::LeptonsPerCell); + cell.Y += static_cast(pType->GetFoundationHeight(false) - 1); + break; + } + + case 6: + { + cell.Y = static_cast(buffer.Y / Unsorted::LeptonsPerCell); + break; + } + + default: + { + break; + } + + } + + return cell; +} + int BuildingTypeExt::CountOwnedNowWithDeployOrUpgrade(BuildingTypeClass* pType, HouseClass* pHouse) { const auto upgrades = BuildingTypeExt::GetUpgradesAmount(pType, pHouse); @@ -219,6 +265,13 @@ void BuildingTypeExt::ExtData::LoadFromINIFile(CCINIClass* const pINI) this->Refinery_UseNormalActiveAnim.Read(exArtINI, pArtSection, "Refinery.UseNormalActiveAnim"); + this->Bib_Dir.Read(exINI, pSection, "Bib.Dir"); + this->Bib_Dir = Math::max(0, this->Bib_Dir) & 6; // Only accept 0,2,4,6 + this->NumberImpassableRows_Dir.Read(exINI, pSection, "NumberImpassableRows.Dir"); + this->NumberImpassableRows_Dir = Math::max(0, this->NumberImpassableRows_Dir) & 6; // Only accept 0,2,4,6 + this->WeaponsFactory_Dir.Read(exINI, pSection, "WeaponsFactory.Dir"); + this->WeaponsFactory_Dir = Math::max(0, this->WeaponsFactory_Dir) & 6; // Only accept 0,2,4,6 + // Ares tag this->SpyEffect_Custom.Read(exINI, pSection, "SpyEffect.Custom"); if (SuperWeaponTypeClass::Array.Count > 0) @@ -334,6 +387,9 @@ void BuildingTypeExt::ExtData::Serialize(T& Stm) .Process(this->BuildingRepairedSound) .Process(this->Refinery_UseNormalActiveAnim) .Process(this->HasPowerUpAnim) + .Process(this->Bib_Dir) + .Process(this->NumberImpassableRows_Dir) + .Process(this->WeaponsFactory_Dir) ; } diff --git a/src/Ext/BuildingType/Body.h b/src/Ext/BuildingType/Body.h index 9cf41a7af4..36a5794a2a 100644 --- a/src/Ext/BuildingType/Body.h +++ b/src/Ext/BuildingType/Body.h @@ -99,6 +99,10 @@ class BuildingTypeExt ValueableVector HasPowerUpAnim; + Valueable Bib_Dir; + Valueable NumberImpassableRows_Dir; + Valueable WeaponsFactory_Dir; + ExtData(BuildingTypeClass* OwnerObject) : Extension(OwnerObject) , PowersUp_Owner { AffectedHouse::Owner } , PowersUp_Buildings {} @@ -161,6 +165,9 @@ class BuildingTypeExt , BuildingRepairedSound {} , Refinery_UseNormalActiveAnim { false } , HasPowerUpAnim {} + , Bib_Dir { 2 } + , NumberImpassableRows_Dir { 2 } + , WeaponsFactory_Dir { 2 } { } // Ares 0.A functions @@ -198,7 +205,7 @@ class BuildingTypeExt static bool SaveGlobals(PhobosStreamWriter& Stm); static void PlayBunkerSound(BuildingClass const* pThis, bool buildUp = false); - + static CellStruct GetWeaponFactoryDoor(BuildingClass* pThis); static int GetEnhancedPower(BuildingClass* pBuilding, HouseClass* pHouse); static bool CanUpgrade(BuildingClass* pBuilding, BuildingTypeClass* pUpgradeType, HouseClass* pUpgradeOwner); static int CountOwnedNowWithDeployOrUpgrade(BuildingTypeClass* pBuilding, HouseClass* pHouse); diff --git a/src/Ext/BuildingType/Hooks.cpp b/src/Ext/BuildingType/Hooks.cpp index d47fda7159..2d8d520e0d 100644 --- a/src/Ext/BuildingType/Hooks.cpp +++ b/src/Ext/BuildingType/Hooks.cpp @@ -425,7 +425,304 @@ DEFINE_HOOK(0x73F5A7, UnitClass_IsCellOccupied_UnlimboDirection, 0x8) GET(CellClass* const, pCell, EDI); - return pCell->MapCoords.Y == pBuilding->Location.Y / Unsorted::LeptonsPerCell + pType->FoundationOutside[10].Y ? NextObject : ContinueCheck; + if (!RulesExt::Global()->ExtendedWeaponsFactory) + return pCell->MapCoords.Y == pBuilding->Location.Y / Unsorted::LeptonsPerCell + pType->FoundationOutside[10].Y ? NextObject : ContinueCheck; + + auto buffer = CoordStruct::Empty; + pBuilding->GetExitCoords(&buffer, 0); + const auto cell = CellClass::Coord2Cell(buffer); + const bool pathX = (BuildingTypeExt::ExtMap.Find(pType)->WeaponsFactory_Dir.Get() & 2) != 0; // 2,6/0,4 + const bool onPath = pathX ? pCell->MapCoords.Y == cell.Y : pCell->MapCoords.X == cell.X; + + return onPath ? NextObject : ContinueCheck; +} + +#pragma endregion + +#pragma region WeaponFactoryDirection + +DEFINE_HOOK(0x44457B, BuildingClass_KickOutUnit_UnlimboDirection, 0x5) +{ + if (!RulesExt::Global()->ExtendedWeaponsFactory) + return 0; + + GET(BuildingClass* const, pThis, ESI); + REF_STACK(DirType, dir, STACK_OFFSET(0x144, -0x144)); + + dir = static_cast(BuildingTypeExt::ExtMap.Find(pThis->Type)->WeaponsFactory_Dir.Get() << 5); + + return 0; +} + +DEFINE_HOOK(0x44955D, BuildingClass_WeaponFactoryOutsideBusy_WeaponFactoryCell, 0x6) +{ + enum { StartCheck = 0x4495DF, NotBusy = 0x44969B }; + + GET(BuildingClass* const, pThis, ESI); + + const auto pLink = pThis->GetNthLink(); + + if (!pLink) + return NotBusy; + + const auto pLinkType = pLink->GetTechnoType(); + + if (pLinkType->JumpJet && pLinkType->BalloonHover) + return NotBusy; + + if (!RulesExt::Global()->ExtendedWeaponsFactory) + return 0; + + REF_STACK(CoordStruct, coords, STACK_OFFSET(0x30, -0xC)); + + const auto cell = BuildingTypeExt::GetWeaponFactoryDoor(pThis); + coords = CellClass::Cell2Coord(cell); + + R->EAX(MapClass::Instance.GetCellAt(cell)); + + return StartCheck; +} + +DEFINE_JUMP(LJMP, 0x44DCC7, 0x44DD3C); + +DEFINE_HOOK(0x44E131, BuildingClass_Mission_Unload_WeaponFactoryFix1, 0x5) +{ + enum { SkipGameCode = 0x44E191 }; + + GET(BuildingClass* const, pThis, EBP); + GET(FootClass* const, pLink, EDI); +// REF_STACK(const CoordStruct, coords, STACK_OFFSET(0x50, -0x1C)); + + const auto cell = BuildingTypeExt::GetWeaponFactoryDoor(pThis); + const auto coords = CellClass::Cell2Coord(cell); + + if (RulesExt::Global()->ExtendedWeaponsFactory) + { +// const auto pType = pLink->GetTechnoType(); +// const bool isSubterranean = pType->IsSubterranean; +// pType->IsSubterranean = false; + pLink->SetDestination(MapClass::Instance.GetCellAt(cell), true); +// pType->IsSubterranean = isSubterranean; + } + else + { + pLink->Locomotor->Force_Track(66, coords); + } + + return SkipGameCode; +} + +DEFINE_HOOK(0x44DF72, BuildingClass_Mission_Unload_WeaponFactoryFix2, 0x5) +{ + enum { SkipGameCode = 0x44E1AD }; + + GET(BuildingClass* const, pThis, EBP); + GET_STACK(FootClass* const, pLink, STACK_OFFSET(0x50, -0x30)); +// REF_STACK(const CoordStruct, coords, STACK_OFFSET(0x50, -0x1C)); + + const auto cell = BuildingTypeExt::GetWeaponFactoryDoor(pThis); + const auto coords = CellClass::Cell2Coord(cell); + + if (RulesExt::Global()->ExtendedWeaponsFactory) + pLink->SetDestination(MapClass::Instance.GetCellAt(cell), true); + else + pLink->Locomotor->Force_Track(66, coords); + + R->EDI(pLink); + + return SkipGameCode; +} + +DEFINE_HOOK(0x44DF1C, BuildingClass_Mission_Unload_WeaponFactoryFix3, 0x7) +{ + if (!RulesExt::Global()->ExtendedWeaponsFactory) + return 0; + + enum { SkipGameCode = 0x44DF47 }; + + GET(BuildingClass* const, pThis, EBP); + GET_STACK(FootClass* const, pLink, STACK_OFFSET(0x50, -0x30)); + REF_STACK(CellStruct, cell, STACK_OFFSET(0x50, -0x34)); +// REF_STACK(const CoordStruct, coords, STACK_OFFSET(0x50, -0x1C)); + + cell = BuildingTypeExt::GetWeaponFactoryDoor(pThis); + + R->ESI(pLink); + + return SkipGameCode; +} + +DEFINE_HOOK(0x742D98, UnitClass_SetDestination_WeaponFactoryCell, 0x6) +{ + if (!RulesExt::Global()->ExtendedWeaponsFactory) + return 0; + + enum { SkipGameCode = 0x742DFB }; + + GET(BuildingClass* const, pLink, ESI); + + const auto cell = BuildingTypeExt::GetWeaponFactoryDoor(pLink); + + R->EAX(MapClass::Instance.GetCellAt(cell)); + + return SkipGameCode; +} + +DEFINE_HOOK(0x516D3C, HoverLocomotionClass_IsIonSensitive_WeaponFactoryCell, 0x5) +{ + if (!RulesExt::Global()->ExtendedWeaponsFactory) + return 0; + + enum { Right = 0x516DFF, IsNot = 0x516DF6 }; + + GET(BuildingClass* const, pBuilding, EAX); + GET(ILocomotion* const, iLoco, ESI); + + const auto location = CellClass::Coord2Cell(static_cast(iLoco)->LinkedTo->Location); + bool notIon = false; + auto buffer = CoordStruct::Empty; + pBuilding->GetExitCoords(&buffer, 0); + const auto cell = CellClass::Coord2Cell(buffer); + const auto pType = pBuilding->Type; + + switch (BuildingTypeExt::ExtMap.Find(pType)->WeaponsFactory_Dir.Get()) + { + + case 0: + { + notIon |= (cell.X == location.X + && cell.Y != location.Y + && (pBuilding->Location.Y / Unsorted::LeptonsPerCell) != location.Y); + + break; + } + + case 2: + { + notIon |= (cell.Y == location.Y + && cell.X != location.X + && (pBuilding->Location.X / Unsorted::LeptonsPerCell + pType->GetFoundationWidth() - 1) != location.X); + + break; + } + + case 4: + { + notIon |= (cell.X == location.X + && cell.Y != location.Y + && (pBuilding->Location.Y / Unsorted::LeptonsPerCell + pType->GetFoundationHeight(false) - 1) != location.Y); + + break; + } + + case 6: + { + notIon |= (cell.Y == location.Y + && cell.X != location.X + && (pBuilding->Location.X / Unsorted::LeptonsPerCell) != location.X); + + break; + } + + default: + { + break; + } + + } + + return notIon ? IsNot : Right; +} + +DEFINE_HOOK(0x7443D9, UnitClass_ReadyToNextMission_WeaponFactoryCell, 0x5) +{ + enum { SkipGameCode = 0x744463 }; + return RulesExt::Global()->ExtendedWeaponsFactory ? SkipGameCode : 0; +} + +#pragma endregion + +#pragma region ImpassableRowsDirection + +DEFINE_HOOK(0x458A00, BuildingClass_IsCellNotPassable_ImpassableRowsDirection, 0x6) +{ + enum { SkipGameCode = 0x458A76 }; + + GET(BuildingClass* const, pThis, ECX); + GET_STACK(CellClass* const, pCell, STACK_OFFSET(0x0, 0x4)); + + auto isCellNotPassable = [pThis, pCell]() -> bool + { + if (pCell->GetBuilding() != pThis) + return false; + + const auto pType = pThis->Type; + + if (pType->NumberImpassableRows == -1) + return true; + + if (pType->Bunker && pThis->BunkerLinkedItem) + return true; + + switch (BuildingTypeExt::ExtMap.Find(pType)->NumberImpassableRows_Dir.Get()) + { + + case 0: + { + const int y = pThis->Location.Y / Unsorted::LeptonsPerCell; + const int maxPassableY = y + pType->GetFoundationHeight(false) - 1 - pType->NumberImpassableRows; + return pCell->MapCoords.Y > maxPassableY; + } + + case 2: + { + const int x = pThis->Location.X / Unsorted::LeptonsPerCell; + const int minPassableX = x + pType->NumberImpassableRows; + return pCell->MapCoords.X < minPassableX; + } + + case 4: + { + const int y = pThis->Location.Y / Unsorted::LeptonsPerCell; + const int minPassableY = y + pType->NumberImpassableRows; + return pCell->MapCoords.Y < minPassableY; + } + + case 6: + { + const int x = pThis->Location.X / Unsorted::LeptonsPerCell; + const int maxPassableX = x + pType->GetFoundationWidth() - 1 - pType->NumberImpassableRows; + return pCell->MapCoords.X > maxPassableX; + } + + default: + { + return true; + } + + } + }; + + R->EAX(isCellNotPassable()); + + return SkipGameCode; +} + +#pragma endregion + +#pragma region BibDirection + +// The input parameter of GetFoundationHeight is incorrect, and there is no call to input the incorrect parameter, so no need to consider it +DEFINE_HOOK(0x73F7DD, BuildingClass_IsCellNotPassable_BibDirection, 0x8) +{ + enum { SkipGameCode = 0x73F816 }; + + GET(CellClass* const, pCell, EDI); + GET(BuildingTypeClass* const, pType, EAX); + + R->ECX(MapClass::Instance.GetCellAt(Unsorted::AdjacentCell[BuildingTypeExt::ExtMap.Find(pType)->Bib_Dir.Get()] + pCell->MapCoords)); + + return SkipGameCode; } #pragma endregion diff --git a/src/Ext/Rules/Body.cpp b/src/Ext/Rules/Body.cpp index c30c2e8849..a3d889c7e3 100644 --- a/src/Ext/Rules/Body.cpp +++ b/src/Ext/Rules/Body.cpp @@ -313,6 +313,8 @@ void RulesExt::ExtData::LoadBeforeTypeData(RulesClass* pThis, CCINIClass* pINI) this->InfantryAutoDeploy.Read(exINI, GameStrings::General, "InfantryAutoDeploy"); + this->ExtendedWeaponsFactory.Read(exINI, GameStrings::General, "ExtendedWeaponsFactory"); + // Section AITargetTypes int itemsCount = pINI->GetKeyCount("AITargetTypes"); for (int i = 0; i < itemsCount; ++i) @@ -577,6 +579,7 @@ void RulesExt::ExtData::Serialize(T& Stm) .Process(this->AttackMove_StopWhenTargetAcquired) .Process(this->Parasite_GrappleAnim) .Process(this->InfantryAutoDeploy) + .Process(this->ExtendedWeaponsFactory) ; } diff --git a/src/Ext/Rules/Body.h b/src/Ext/Rules/Body.h index 2584a189dc..e9ddfd3156 100644 --- a/src/Ext/Rules/Body.h +++ b/src/Ext/Rules/Body.h @@ -257,13 +257,15 @@ class RulesExt NullableIdx Parasite_GrappleAnim; + Valueable InfantryAutoDeploy; + + Valueable ExtendedWeaponsFactory; + // cache tint color int TintColorIronCurtain; int TintColorForceShield; int TintColorBerserk; - Valueable InfantryAutoDeploy; - ExtData(RulesClass* OwnerObject) : Extension(OwnerObject) , Storage_TiberiumIndex { -1 } , HarvesterDumpAmount { 0.0f } @@ -467,7 +469,10 @@ class RulesExt , AttackMove_StopWhenTargetAcquired { } , Parasite_GrappleAnim {} + , InfantryAutoDeploy { false } + + , ExtendedWeaponsFactory { false } { } virtual ~ExtData() = default;