From a5d0d40b32e231a2b6676800d45304f7e516564e Mon Sep 17 00:00:00 2001 From: Coronia <2217891145@qq.com> Date: Tue, 7 Jul 2026 12:44:49 +0800 Subject: [PATCH 1/2] refract BuildLimitGroup for Upgrade --- src/Ext/BuildingType/Hooks.Upgrade.cpp | 15 +- src/Ext/House/Body.cpp | 218 ++++++++++++++++--------- src/Ext/House/Body.h | 2 +- 3 files changed, 150 insertions(+), 85 deletions(-) diff --git a/src/Ext/BuildingType/Hooks.Upgrade.cpp b/src/Ext/BuildingType/Hooks.Upgrade.cpp index b1a78b31ab..f0eaddb958 100644 --- a/src/Ext/BuildingType/Hooks.Upgrade.cpp +++ b/src/Ext/BuildingType/Hooks.Upgrade.cpp @@ -100,18 +100,13 @@ DEFINE_HOOK(0x4F8361, HouseClass_CanBuild_UpgradesInteraction, 0x5) GET_STACK(bool const, includeInProduction, 0xC); GET(CanBuildResult const, resultOfAres, EAX); - if (auto const pBuilding = abstract_cast(pItem)) - { - if (resultOfAres == CanBuildResult::Buildable && BuildingTypeExt::ExtMap.Find(pBuilding)->PowersUp_Buildings.size() > 0) - R->EAX(CheckBuildLimit(pThis, pBuilding, includeInProduction)); - } + if (resultOfAres != CanBuildResult::Buildable) + return 0; - if (resultOfAres == CanBuildResult::Buildable) + if (auto const pBuilding = abstract_cast(pItem)) { - R->EAX(HouseExt::BuildLimitGroupCheck(pThis, pItem, buildLimitOnly, includeInProduction)); - - if (HouseExt::ReachedBuildLimit(pThis, pItem, true)) - R->EAX(CanBuildResult::TemporarilyUnbuildable); + if (BuildingTypeExt::ExtMap.Find(pBuilding)->PowersUp_Buildings.size() > 0) + R->EAX(HouseExt::BuildLimitGroupUpgradeCheck(pThis, pItem, buildLimitOnly, includeInProduction)); } return 0; diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp index 49176529ef..a7ef1c2d29 100644 --- a/src/Ext/House/Body.cpp +++ b/src/Ext/House/Body.cpp @@ -846,7 +846,27 @@ static int CountOwnedIncludeDeploy(const HouseClass* pThis, const TechnoTypeClas return count; } -CanBuildResult HouseExt::BuildLimitGroupCheck(const HouseClass* pThis, const TechnoTypeClass* pItem, bool buildLimitOnly, bool includeQueued) +static void RemoveProduction(const HouseClass* pHouse, const TechnoTypeClass* pType, int num) +{ + const auto absType = pType->WhatAmI(); + const auto buildCat = (absType == AbstractType::BuildingType ? static_cast(pType)->BuildCat : BuildCat::DontCare); + const auto pFactory = pHouse->GetPrimaryFactory(absType, pType->Naval, buildCat); + + if (pFactory) + { + int queued = pFactory->CountTotal(pType); + + if (num >= 0) + queued = Math::min(num, queued); + + for (int i = 0; i < queued; i++) + { + pFactory->RemoveOneFromQueue(pType); + } + } +} + +CanBuildResult HouseExt::BuildLimitGroupUpgradeCheck(const HouseClass* pThis, const TechnoTypeClass* pItem, bool buildLimitOnly, bool includeQueued) { const auto pItemExt = TechnoTypeExt::ExtMap.Find(pItem); @@ -889,88 +909,158 @@ CanBuildResult HouseExt::BuildLimitGroupCheck(const HouseClass* pThis, const Tec } auto const& buildLimit = pItemExt->BuildLimitGroup_Types; - const int factor = pItemExt->BuildLimitGroup_Factor; + std::vector contributions; + contributions.reserve(buildLimit.size()); - if (pItemExt->BuildLimitGroup_ContentIfAnyMatch.Get()) + for (const auto pType : buildLimit) { - bool reachedLimit = false; + auto const pBuildingType = abstract_cast(pType); + int ownedNow; - for (size_t i = 0; i < std::min(buildLimit.size(), pItemExt->BuildLimitGroup_Nums.size()); i++) - { - const auto pType = buildLimit[i]; - const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType); - const auto pBuildingType = abstract_cast(pType); - int ownedNow = 0; + if (pBuildingType && (BuildingTypeExt::ExtMap.Find(pBuildingType)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pBuildingType->PowersUpBuilding))) + ownedNow = BuildingTypeExt::GetUpgradesAmount(pBuildingType, const_cast(pThis)); + else + ownedNow = CountOwnedIncludeDeploy(pThis, pType); - if (pBuildingType && (BuildingTypeExt::ExtMap.Find(pBuildingType)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pBuildingType->PowersUpBuilding))) - ownedNow = BuildingTypeExt::GetUpgradesAmount(pBuildingType, const_cast(pThis)); - else - ownedNow = CountOwnedIncludeDeploy(pThis, pType); + contributions.push_back(ownedNow * TechnoTypeExt::ExtMap.Find(pType)->BuildLimitGroup_Factor); + } - ownedNow *= pTypeExt->BuildLimitGroup_Factor; + const int factor = pItemExt->BuildLimitGroup_Factor; + const bool notBuildable = pItemExt->BuildLimitGroup_NotBuildableIfQueueMatch; + const bool contentIfAny = pItemExt->BuildLimitGroup_ContentIfAnyMatch; - if (ownedNow >= limits[i] + 1 - factor) - reachedLimit |= (includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType)) ? false : true; - } + if (limits.size() == 1) + { + int sum = 0; + + for (int c : contributions) sum += c; - return reachedLimit ? CanBuildResult::TemporarilyUnbuildable : CanBuildResult::Buildable; + if (sum >= limits[0] + 1 - factor) + { + RemoveProduction(pThis, pItem, (sum + factor - 1) / factor); + return CanBuildResult::TemporarilyUnbuildable; + } } else { - if (limits.size() == 1U) + const size_t size = Math::min(limits.size(), buildLimit.size()); + bool reached = true; + bool realReached = true; + + for (size_t i = 0; i < size; i++) { - int sum = 0; - bool reachedLimit = false; + const auto pTmpType = buildLimit[i]; + const int num = contributions[i] - limits[i]; - for (const auto pType : buildLimit) + if (pItem == pTmpType) { - const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType); - const auto pBuildingType = abstract_cast(pType); - int owned = 0; - - if (pBuildingType && (BuildingTypeExt::ExtMap.Find(pBuildingType)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pBuildingType->PowersUpBuilding))) - owned = BuildingTypeExt::GetUpgradesAmount(pBuildingType, const_cast(pThis)); - else - owned = CountOwnedIncludeDeploy(pThis, pType); - - sum += owned * pTypeExt->BuildLimitGroup_Factor; + if (num >= 1 - factor) + { + if (contentIfAny) + { + RemoveProduction(pThis, pItem, (num + factor - 1) / factor); + return CanBuildResult::TemporarilyUnbuildable; + } + else if (num < 1 - factor) + { + realReached = false; + } + } } - - if (sum >= limits[0] + 1 - factor) + else { - for (const auto pType : buildLimit) + if (num >= 0) { - reachedLimit |= (includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType)) ? false : true; + if (contentIfAny) + { + if (num >= 0 || notBuildable) + { + RemoveProduction(pThis, pItem, -1); + return CanBuildResult::TemporarilyUnbuildable; + } + } + else if (num < 0) + { + realReached = false; + } + } + else + { + reached = false; } } + } + + if (reached && (realReached || notBuildable)) + { + RemoveProduction(pThis, pItem, -1); + return CanBuildResult::TemporarilyUnbuildable; + } + } + + if (contentIfAny) + { + for (size_t i = 0; i < std::min(buildLimit.size(), limits.size()); i++) + { + const auto pType = buildLimit[i]; - return reachedLimit ? CanBuildResult::TemporarilyUnbuildable : CanBuildResult::Buildable; + if (contributions[i] >= limits[i] + 1 - factor) + { + if (!includeQueued || !FactoryClass::FindByOwnerAndProduct(pThis, pType)) + return CanBuildResult::TemporarilyUnbuildable; + } } - else + + return CanBuildResult::Buildable; + } + else if (limits.size() == 1) + { + int sum = 0; + + for (int c : contributions) sum += c; + + if (sum >= limits[0] + 1 - factor) { - for (size_t i = 0; i < std::min(buildLimit.size(), limits.size()); i++) + bool anyQueued = false; + + for (const auto pType : buildLimit) { - const auto pType = buildLimit[i]; - const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType); - const auto pBuildingType = abstract_cast(pType); - int ownedNow = 0; + if (includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType)) + { + anyQueued = true; + break; + } + } - if (pBuildingType && (BuildingTypeExt::ExtMap.Find(pBuildingType)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pBuildingType->PowersUpBuilding))) - ownedNow = BuildingTypeExt::GetUpgradesAmount(pBuildingType, const_cast(pThis)); - else - ownedNow = CountOwnedIncludeDeploy(pThis, pType); + if (!anyQueued) + return CanBuildResult::TemporarilyUnbuildable; + } - ownedNow *= pTypeExt->BuildLimitGroup_Factor; + return CanBuildResult::Buildable; + } + else + { + for (size_t i = 0; i < std::min(buildLimit.size(), limits.size()); i++) + { + const auto pType = buildLimit[i]; - if ((pItem == pType && ownedNow < limits[i] + 1 - factor) || includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType)) + if (pItem == pType) + { + if (contributions[i] < limits[i] + 1 - factor) return CanBuildResult::Buildable; - - if ((pItem != pType && ownedNow < limits[i]) || includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType)) + else if (includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType)) + return CanBuildResult::Buildable; + } + else + { + if (contributions[i] < limits[i]) + return CanBuildResult::Buildable; + else if (includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType)) return CanBuildResult::Buildable; } - - return CanBuildResult::TemporarilyUnbuildable; } + + return CanBuildResult::TemporarilyUnbuildable; } } @@ -995,26 +1085,6 @@ static int QueuedNum(const HouseClass* pHouse, const TechnoTypeClass* pType) return queued; } -static void RemoveProduction(const HouseClass* pHouse, const TechnoTypeClass* pType, int num) -{ - const auto absType = pType->WhatAmI(); - const auto buildCat = (absType == AbstractType::BuildingType ? static_cast(pType)->BuildCat : BuildCat::DontCare); - const auto pFactory = pHouse->GetPrimaryFactory(absType, pType->Naval, buildCat); - - if (pFactory) - { - int queued = pFactory->CountTotal(pType); - - if (num >= 0) - queued = Math::min(num, queued); - - for (int i = 0; i < queued; i++) - { - pFactory->RemoveOneFromQueue(pType); - } - } -} - bool HouseExt::ReachedBuildLimit(const HouseClass* pHouse, const TechnoTypeClass* pType, bool ignoreQueued) { const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType); diff --git a/src/Ext/House/Body.h b/src/Ext/House/Body.h index ab0276b395..5c1f70cea3 100644 --- a/src/Ext/House/Body.h +++ b/src/Ext/House/Body.h @@ -206,7 +206,7 @@ class HouseExt static std::vector AIProduction_BestChoices; static std::vector AIProduction_BestChoicesNaval; - static CanBuildResult BuildLimitGroupCheck(const HouseClass* pThis, const TechnoTypeClass* pItem, bool buildLimitOnly, bool includeQueued); + static CanBuildResult BuildLimitGroupUpgradeCheck(const HouseClass* pThis, const TechnoTypeClass* pItem, bool buildLimitOnly, bool includeQueued); static bool ReachedBuildLimit(const HouseClass* pHouse, const TechnoTypeClass* pType, bool ignoreQueued); static void CalculatePowerSurplus(HouseClass* pThis); From cc6f6282d5656f18f0abbb9e5124655ae43fe1b6 Mon Sep 17 00:00:00 2001 From: Coronia <2217891145@qq.com> Date: Tue, 7 Jul 2026 12:49:24 +0800 Subject: [PATCH 2/2] fix --- src/Ext/House/Body.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/Ext/House/Body.cpp b/src/Ext/House/Body.cpp index a7ef1c2d29..3f93c91f55 100644 --- a/src/Ext/House/Body.cpp +++ b/src/Ext/House/Body.cpp @@ -932,12 +932,25 @@ CanBuildResult HouseExt::BuildLimitGroupUpgradeCheck(const HouseClass* pThis, co if (limits.size() == 1) { int sum = 0; + bool inside = false; - for (int c : contributions) sum += c; + for (size_t i = 0; i < buildLimit.size(); ++i) + { + sum += contributions[i]; + + if (buildLimit[i] == pItem) + inside = true; + } if (sum >= limits[0] + 1 - factor) { - RemoveProduction(pThis, pItem, (sum + factor - 1) / factor); + const int num = sum - limits[0]; + + if (inside) + RemoveProduction(pThis, pItem, (num + factor - 1) / factor); + else if (num >= 1 - factor || notBuildable) + RemoveProduction(pThis, pItem, -1); + return CanBuildResult::TemporarilyUnbuildable; } }