fix issue where status light was flickering to yellow for one tick between cycles
This commit is contained in:
@@ -1,10 +1,47 @@
|
||||
#include "ProductionRules.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "BuildingType.h"
|
||||
#include "ItemType.h"
|
||||
#include "ModulesConfig.h"
|
||||
#include "ShipsConfig.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Items one cycle of this recipe would deposit into the output buffer. A Reprocessing
|
||||
// Plant rolls exactly one of its outputs per cycle (REQ-BLD-REPROCESSING) and the roll
|
||||
// happens in the simulation, so the smallest amount any roll could yield is what decides
|
||||
// whether a cycle could start at all; a larger roll may still not fit.
|
||||
int getCycleOutputItemCount(const Building& b, const RecipeDef& recipe)
|
||||
{
|
||||
if (recipe.outputs.empty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (b.type == BuildingType::ReprocessingPlant)
|
||||
{
|
||||
int smallest = std::numeric_limits<int>::max();
|
||||
for (const RecipeOutput& out : recipe.outputs)
|
||||
{
|
||||
smallest = std::min(smallest, out.amount);
|
||||
}
|
||||
return smallest;
|
||||
}
|
||||
|
||||
int total = 0;
|
||||
for (const RecipeOutput& out : recipe.outputs)
|
||||
{
|
||||
total += out.amount;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<const RecipeDef*>
|
||||
gatherCandidateRecipes(const GameConfig& config, const Building& b)
|
||||
{
|
||||
@@ -128,8 +165,8 @@ bool hasInputsToStart(const GameConfig& config, const Building& b)
|
||||
}
|
||||
|
||||
// Recipe buildings: startable if any candidate recipe's inputs are satisfied.
|
||||
// A Miner recipe has no inputs, so an idle Miner is always startable and its
|
||||
// only idle reason is a full output buffer.
|
||||
// A Miner recipe has no inputs, so an idle Miner is always startable here and its
|
||||
// only idle reason is an output buffer without room for the next cycle.
|
||||
for (const RecipeDef* recipe : gatherCandidateRecipes(config, b))
|
||||
{
|
||||
if (recipeInputsAvailable(b, *recipe))
|
||||
@@ -139,6 +176,32 @@ bool hasInputsToStart(const GameConfig& config, const Building& b)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool outputBufferHasRoom(const Building& b, int outputItemCount)
|
||||
{
|
||||
return b.getOutputItemCount() + outputItemCount <= b.outputBuffer.capacity;
|
||||
}
|
||||
|
||||
bool canStartCycle(const GameConfig& config, const Building& b)
|
||||
{
|
||||
// A shipyard's completed cycle spawns a ship instead of filling an output buffer
|
||||
// (REQ-BLD-SHIPYARD), so holding the materials is the whole condition.
|
||||
if (b.type == BuildingType::Shipyard)
|
||||
{
|
||||
return hasInputsToStart(config, b);
|
||||
}
|
||||
|
||||
for (const RecipeDef* recipe : gatherCandidateRecipes(config, b))
|
||||
{
|
||||
if (recipeInputsAvailable(b, *recipe)
|
||||
&& outputBufferHasRoom(b, getCycleOutputItemCount(b, *recipe)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<ProductionStatus>
|
||||
getProductionStatus(const GameConfig& config, const Building& building)
|
||||
{
|
||||
@@ -169,9 +232,18 @@ getProductionStatus(const GameConfig& config, const Building& building)
|
||||
return ProductionStatus::Producing;
|
||||
}
|
||||
|
||||
// Idle: missing inputs (red) take precedence over a full output buffer
|
||||
// (yellow). If inputs are present yet the building is idle, the only remaining
|
||||
// reason it could not start a cycle is a full output buffer (REQ-MAT-CYCLE).
|
||||
// Idle, but blocked by neither condition: the building is only between cycles and
|
||||
// the simulation starts the next one on a following tick. A building running back
|
||||
// to back sits here for exactly one tick per cycle, since tickProduction never
|
||||
// starts a cycle in the tick one completed, so this must read as producing rather
|
||||
// than blink (REQ-UI-STATUS-LIGHT, REQ-MAT-CYCLE).
|
||||
if (canStartCycle(config, building))
|
||||
{
|
||||
return ProductionStatus::Producing;
|
||||
}
|
||||
|
||||
// Idle for a reason: a missing input (red) takes precedence over an output buffer
|
||||
// with no room for the next cycle's output (yellow).
|
||||
return hasInputsToStart(config, building) ? ProductionStatus::Blocked
|
||||
: ProductionStatus::Starved;
|
||||
: ProductionStatus::Starved;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user