Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved factory manufacture #4152

Closed
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
2 changes: 2 additions & 0 deletions src/droiddef.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ typedef std::vector<DROID_ORDER_DATA> 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;
Expand Down
8 changes: 6 additions & 2 deletions src/hci/manufacture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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
Expand Down
58 changes: 54 additions & 4 deletions src/structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1099,14 +1099,20 @@ static void refundFactoryBuildPower(STRUCTURE *psBuilding)
ASSERT_OR_RETURN(, psBuilding && psBuilding->isFactory(), "structure not a factory");
FACTORY *psFactory = &psBuilding->pFunctionality->factory;

if (psFactory->psSubject)
// 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()));
}
}
else 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));
}

}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 &&
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -6327,6 +6354,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,
// update 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)
{
psFactory->psSubjectObsolete = std::make_unique<DROID_TEMPLATE>();
*psFactory->psSubjectObsolete = *psFactory->psSubject;
*psFactory->psSubject = *psTemplate;
}
}

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.
Expand Down
3 changes: 3 additions & 0 deletions src/structuredef.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "weapondef.h"

#include <vector>
#include <memory>

#define NUM_FACTORY_MODULES 2
#define NUM_POWER_MODULES 4
Expand Down Expand Up @@ -205,6 +206,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<DROID_TEMPLATE>
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*/
Expand Down
16 changes: 16 additions & 0 deletions src/template.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]];
Expand Down
Loading