From 14f1833371f7da3286111133fc6ab3066d12c5e5 Mon Sep 17 00:00:00 2001 From: Nikolay Borodin Date: Fri, 13 Dec 2024 19:04:41 +0200 Subject: [PATCH 1/4] Cancel previous template when producing a new template in factories --- src/droiddef.h | 2 ++ src/structure.cpp | 23 +++++++++++++++++++++++ src/template.cpp | 16 ++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/src/droiddef.h b/src/droiddef.h index d84255fd1fe..b9e0fd6e559 100644 --- a/src/droiddef.h +++ b/src/droiddef.h @@ -56,6 +56,8 @@ typedef std::vector OrderList; struct DROID_TEMPLATE : public BASE_STATS { DROID_TEMPLATE(); + bool operator==(const DROID_TEMPLATE& other) const; + bool operator!=(const DROID_TEMPLATE& other) const; BODY_STATS* getBodyStats() const; BRAIN_STATS* getBrainStats() const; diff --git a/src/structure.cpp b/src/structure.cpp index 6e5b4477a58..f0db55cb980 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -6327,6 +6327,29 @@ void factoryProdAdjust(STRUCTURE *psStructure, DROID_TEMPLATE *psTemplate, bool ASSERT_OR_RETURN(, psTemplate != nullptr, "NULL template"); FACTORY *psFactory = &psStructure->pFunctionality->factory; + + // the droid template being produced is different from the one we want to make, + // cancel the current production instead of increasing the counter + if (psFactory->psSubject && *psFactory->psSubject != *psTemplate) + { + bool bFound = false; + for (auto templ : apsTemplateList) + { + if (*templ == *psFactory->psSubject) + { + bFound = true; + break; + } + } + + if (!bFound) + { + cancelProduction(psStructure, ModeImmediate, false); + factoryProdAdjust(psStructure, psTemplate, add); + return; + } + } + if (psFactory->psAssemblyPoint->factoryInc >= asProductionRun[psFactory->psAssemblyPoint->factoryType].size()) { asProductionRun[psFactory->psAssemblyPoint->factoryType].resize(psFactory->psAssemblyPoint->factoryInc + 1); // Don't have a production list, create it. diff --git a/src/template.cpp b/src/template.cpp index b7e2e317911..bbf83dae293 100644 --- a/src/template.cpp +++ b/src/template.cpp @@ -524,6 +524,22 @@ DROID_TEMPLATE::DROID_TEMPLATE() // This constructor replaces a memset in scrAs std::fill_n(asWeaps, MAX_WEAPONS, 0); } +bool DROID_TEMPLATE::operator==(const DROID_TEMPLATE &other) const +{ + return numWeaps == other.numWeaps && + droidType == other.droidType && + multiPlayerID == other.multiPlayerID && + prefab == other.prefab && + enabled == other.enabled && + std::equal(std::begin(asParts), std::end(asParts), std::begin(other.asParts)) && + std::equal(std::begin(asWeaps), std::end(asWeaps), std::begin(other.asWeaps)); +} + +bool DROID_TEMPLATE::operator!=(const DROID_TEMPLATE &other) const +{ + return !(*this == other); +} + BODY_STATS* DROID_TEMPLATE::getBodyStats() const { return &asBodyStats[asParts[COMP_BODY]]; From 1e14cd0318618d4605f96a4e95ed4309b66d043a Mon Sep 17 00:00:00 2001 From: Nikolay Borodin Date: Sat, 14 Dec 2024 03:43:46 +0200 Subject: [PATCH 2/4] Finish the previous template to proceed to the new one --- src/hci/manufacture.cpp | 8 ++++++-- src/structure.cpp | 41 ++++++++++++++++++++++++++++++++++------- src/structuredef.h | 2 ++ 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/hci/manufacture.cpp b/src/hci/manufacture.cpp index 22fd363eda1..f02174c520b 100644 --- a/src/hci/manufacture.cpp +++ b/src/hci/manufacture.cpp @@ -168,7 +168,8 @@ void ManufactureController::updateManufactureOptionsList() DROID_TEMPLATE *ManufactureController::getObjectStatsAt(size_t objectIndex) const { auto factory = getFactoryOrNullptr(getObjectAt(objectIndex)); - return factory == nullptr ? nullptr : factory->psSubject; + auto subject = factory->psSubjectObsolete ? factory->psSubjectObsolete.get() : factory->psSubject; + return factory == nullptr ? nullptr : subject; } void ManufactureController::refresh() @@ -419,7 +420,10 @@ class ManufactureStatsButton: public StatsButton auto productionRemaining = getProduction(factory, droidTemplate).numRemaining(); if (productionRemaining > 0 && factory && StructureIsManufacturingPending(factory)) { - productionRunSizeLabel->setString(WzString::fromUtf8(astringf("%d", productionRemaining))); + auto manufacture = StructureGetFactory(factory); + productionRunSizeLabel->setString(manufacture->psSubjectObsolete ? + WzString::fromUtf8(astringf("1+%d", productionRemaining)) : + WzString::fromUtf8(astringf("%d", productionRemaining))); productionRunSizeLabel->show(); } else diff --git a/src/structure.cpp b/src/structure.cpp index f0db55cb980..24f78f87f87 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -1099,14 +1099,20 @@ static void refundFactoryBuildPower(STRUCTURE *psBuilding) ASSERT_OR_RETURN(, psBuilding && psBuilding->isFactory(), "structure not a factory"); FACTORY *psFactory = &psBuilding->pFunctionality->factory; + // We started building, so give the power back that was used. + if (psFactory->psSubjectObsolete) + { + if (psFactory->buildPointsRemaining < (int)calcTemplateBuild(psFactory->psSubjectObsolete.get())) + { + addPower(psBuilding->player, calcTemplatePower(psFactory->psSubjectObsolete.get())); + } + } if (psFactory->psSubject) { if (psFactory->buildPointsRemaining < (int)calcTemplateBuild(psFactory->psSubject)) { - // We started building, so give the power back that was used. addPower(psBuilding->player, calcTemplatePower(psFactory->psSubject)); } - } } @@ -2071,6 +2077,7 @@ static bool setFunctionality(STRUCTURE *psBuilding, STRUCTURE_TYPE functionType) FACTORY *psFactory = &psBuilding->pFunctionality->factory; psFactory->psSubject = nullptr; + psFactory->psSubjectObsolete = nullptr; // Default the secondary order - AB 22/04/99 psFactory->secondaryOrder = DSS_ARANGE_LONG | DSS_REPLEV_NEVER | DSS_ALEV_ALWAYS | DSS_HALT_GUARD; @@ -3216,7 +3223,14 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission) case REF_CYBORG_FACTORY: case REF_VTOL_FACTORY: { - pSubject = psStructure->pFunctionality->factory.psSubject; + if (psStructure->pFunctionality->factory.psSubjectObsolete) + { + pSubject = psStructure->pFunctionality->factory.psSubjectObsolete.get(); + } + else + { + pSubject = psStructure->pFunctionality->factory.psSubject; + } structureMode = REF_FACTORY; //check here to see if the factory's commander has died if (psStructure->pFunctionality->factory.psCommander && @@ -3508,11 +3522,23 @@ static void aiUpdateStructure(STRUCTURE *psStructure, bool isMission) //script callback, must be called after factory was flagged as idle if (bDroidPlaced) { + bool bObsolete = false; + if (psFactory->psSubjectObsolete) + { + pSubject = psFactory->psSubject; + bObsolete = true; + } + //reset the start time psFactory->timeStarted = ACTION_START_TIME; psFactory->psSubject = nullptr; + psFactory->psSubjectObsolete = nullptr; doNextProduction(psStructure, (DROID_TEMPLATE *)pSubject, ModeImmediate); + if (bObsolete) + { + factoryProdAdjust(psStructure, (DROID_TEMPLATE *)pSubject, true); + } cbNewDroid(psStructure, psDroid); } @@ -6169,6 +6195,7 @@ void cancelProduction(STRUCTURE *psBuilding, QUEUE_MODE mode, bool mayClearProdu //clear the factory's subject refundFactoryBuildPower(psBuilding); psFactory->psSubject = nullptr; + psFactory->psSubjectObsolete = nullptr; delPowerRequest(psBuilding); } @@ -6329,7 +6356,7 @@ void factoryProdAdjust(STRUCTURE *psStructure, DROID_TEMPLATE *psTemplate, bool FACTORY *psFactory = &psStructure->pFunctionality->factory; // the droid template being produced is different from the one we want to make, - // cancel the current production instead of increasing the counter + // update the current production instead of increasing the counter if (psFactory->psSubject && *psFactory->psSubject != *psTemplate) { bool bFound = false; @@ -6344,9 +6371,9 @@ void factoryProdAdjust(STRUCTURE *psStructure, DROID_TEMPLATE *psTemplate, bool if (!bFound) { - cancelProduction(psStructure, ModeImmediate, false); - factoryProdAdjust(psStructure, psTemplate, add); - return; + psFactory->psSubjectObsolete = std::make_unique(); + *psFactory->psSubjectObsolete = *psFactory->psSubject; + *psFactory->psSubject = *psTemplate; } } diff --git a/src/structuredef.h b/src/structuredef.h index 91db40ced26..35837b1f511 100644 --- a/src/structuredef.h +++ b/src/structuredef.h @@ -205,6 +205,8 @@ struct FACTORY UBYTE loopsPerformed; /* how many times the loop has been performed*/ DROID_TEMPLATE *psSubject; ///< The subject the structure is working on. DROID_TEMPLATE *psSubjectPending; ///< The subject the structure is going to working on. (Pending = not yet synchronised.) + std::unique_ptr + psSubjectObsolete; ///< Old droid template that will be deleted after production ends. StatusPending statusPending; ///< Pending = not yet synchronised. unsigned pendingCount; ///< Number of messages sent but not yet processed. UDWORD timeStarted; /* The time the building started on the subject*/ From 1a698084d0237f20f67a3945ffe9c3b772ad1d14 Mon Sep 17 00:00:00 2001 From: Nikolay Borodin Date: Sat, 14 Dec 2024 05:06:07 +0200 Subject: [PATCH 3/4] Added #include --- src/structuredef.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/structuredef.h b/src/structuredef.h index 35837b1f511..2f60b435e3b 100644 --- a/src/structuredef.h +++ b/src/structuredef.h @@ -30,6 +30,7 @@ #include "weapondef.h" #include +#include #define NUM_FACTORY_MODULES 2 #define NUM_POWER_MODULES 4 From 7b376a123bb49580cf041ce14e3987b2ba04a6ac Mon Sep 17 00:00:00 2001 From: Nikolay Borodin Date: Sat, 14 Dec 2024 05:39:02 +0200 Subject: [PATCH 4/4] Use "else if" in power refund --- src/structure.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/structure.cpp b/src/structure.cpp index 24f78f87f87..4cb288edee7 100644 --- a/src/structure.cpp +++ b/src/structure.cpp @@ -1107,7 +1107,7 @@ static void refundFactoryBuildPower(STRUCTURE *psBuilding) addPower(psBuilding->player, calcTemplatePower(psFactory->psSubjectObsolete.get())); } } - if (psFactory->psSubject) + else if (psFactory->psSubject) { if (psFactory->buildPointsRemaining < (int)calcTemplateBuild(psFactory->psSubject)) {