Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions src/Ext/BuildingType/Hooks.Upgrade.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<BuildingTypeClass const* const>(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<BuildingTypeClass const* const>(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;
Expand Down
227 changes: 155 additions & 72 deletions src/Ext/House/Body.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const BuildingTypeClass*>(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);

Expand Down Expand Up @@ -889,88 +909,171 @@ CanBuildResult HouseExt::BuildLimitGroupCheck(const HouseClass* pThis, const Tec
}

auto const& buildLimit = pItemExt->BuildLimitGroup_Types;
std::vector<int> contributions;
contributions.reserve(buildLimit.size());

for (const auto pType : buildLimit)
{
auto const pBuildingType = abstract_cast<BuildingTypeClass*, true>(pType);
int ownedNow;

if (pBuildingType && (BuildingTypeExt::ExtMap.Find(pBuildingType)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pBuildingType->PowersUpBuilding)))
ownedNow = BuildingTypeExt::GetUpgradesAmount(pBuildingType, const_cast<HouseClass*>(pThis));
else
ownedNow = CountOwnedIncludeDeploy(pThis, pType);

contributions.push_back(ownedNow * TechnoTypeExt::ExtMap.Find(pType)->BuildLimitGroup_Factor);
}

const int factor = pItemExt->BuildLimitGroup_Factor;
const bool notBuildable = pItemExt->BuildLimitGroup_NotBuildableIfQueueMatch;
const bool contentIfAny = pItemExt->BuildLimitGroup_ContentIfAnyMatch;

if (pItemExt->BuildLimitGroup_ContentIfAnyMatch.Get())
if (limits.size() == 1)
{
bool reachedLimit = false;
int sum = 0;
bool inside = false;

for (size_t i = 0; i < std::min(buildLimit.size(), pItemExt->BuildLimitGroup_Nums.size()); i++)
for (size_t i = 0; i < buildLimit.size(); ++i)
{
const auto pType = buildLimit[i];
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
const auto pBuildingType = abstract_cast<BuildingTypeClass*, true>(pType);
int ownedNow = 0;
sum += contributions[i];

if (pBuildingType && (BuildingTypeExt::ExtMap.Find(pBuildingType)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pBuildingType->PowersUpBuilding)))
ownedNow = BuildingTypeExt::GetUpgradesAmount(pBuildingType, const_cast<HouseClass*>(pThis));
else
ownedNow = CountOwnedIncludeDeploy(pThis, pType);
if (buildLimit[i] == pItem)
inside = true;
}

ownedNow *= pTypeExt->BuildLimitGroup_Factor;
if (sum >= limits[0] + 1 - factor)
{
const int num = sum - limits[0];

if (ownedNow >= limits[i] + 1 - factor)
reachedLimit |= (includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType)) ? false : true;
}
if (inside)
RemoveProduction(pThis, pItem, (num + factor - 1) / factor);
else if (num >= 1 - factor || notBuildable)
RemoveProduction(pThis, pItem, -1);

return reachedLimit ? CanBuildResult::TemporarilyUnbuildable : CanBuildResult::Buildable;
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<BuildingTypeClass*, true>(pType);
int owned = 0;

if (pBuildingType && (BuildingTypeExt::ExtMap.Find(pBuildingType)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pBuildingType->PowersUpBuilding)))
owned = BuildingTypeExt::GetUpgradesAmount(pBuildingType, const_cast<HouseClass*>(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)
{
if (contentIfAny)
{
if (num >= 0 || notBuildable)
{
RemoveProduction(pThis, pItem, -1);
return CanBuildResult::TemporarilyUnbuildable;
}
}
else if (num < 0)
{
realReached = false;
}
}
else
{
reachedLimit |= (includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType)) ? false : true;
reached = false;
}
}
}

return reachedLimit ? CanBuildResult::TemporarilyUnbuildable : CanBuildResult::Buildable;
if (reached && (realReached || notBuildable))
{
RemoveProduction(pThis, pItem, -1);
return CanBuildResult::TemporarilyUnbuildable;
}
else
}

if (contentIfAny)
{
for (size_t i = 0; i < std::min(buildLimit.size(), limits.size()); i++)
{
for (size_t i = 0; i < std::min(buildLimit.size(), limits.size()); i++)
const auto pType = buildLimit[i];

if (contributions[i] >= limits[i] + 1 - factor)
{
const auto pType = buildLimit[i];
const auto pTypeExt = TechnoTypeExt::ExtMap.Find(pType);
const auto pBuildingType = abstract_cast<BuildingTypeClass*, true>(pType);
int ownedNow = 0;
if (!includeQueued || !FactoryClass::FindByOwnerAndProduct(pThis, pType))
return CanBuildResult::TemporarilyUnbuildable;
}
}

if (pBuildingType && (BuildingTypeExt::ExtMap.Find(pBuildingType)->PowersUp_Buildings.size() > 0 || BuildingTypeClass::Find(pBuildingType->PowersUpBuilding)))
ownedNow = BuildingTypeExt::GetUpgradesAmount(pBuildingType, const_cast<HouseClass*>(pThis));
else
ownedNow = CountOwnedIncludeDeploy(pThis, pType);
return CanBuildResult::Buildable;
}
else if (limits.size() == 1)
{
int sum = 0;

ownedNow *= pTypeExt->BuildLimitGroup_Factor;
for (int c : contributions) sum += c;

if ((pItem == pType && ownedNow < limits[i] + 1 - factor) || includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType))
return CanBuildResult::Buildable;
if (sum >= limits[0] + 1 - factor)
{
bool anyQueued = false;

if ((pItem != pType && ownedNow < limits[i]) || includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType))
return CanBuildResult::Buildable;
for (const auto pType : buildLimit)
{
if (includeQueued && FactoryClass::FindByOwnerAndProduct(pThis, pType))
{
anyQueued = true;
break;
}
}

return CanBuildResult::TemporarilyUnbuildable;
if (!anyQueued)
return CanBuildResult::TemporarilyUnbuildable;
}

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)
{
if (contributions[i] < limits[i] + 1 - factor)
return CanBuildResult::Buildable;
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;
}
}

Expand All @@ -995,26 +1098,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<const BuildingTypeClass*>(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);
Expand Down
2 changes: 1 addition & 1 deletion src/Ext/House/Body.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ class HouseExt
static std::vector<int> AIProduction_BestChoices;
static std::vector<int> 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);
Expand Down
Loading