allow the probabilistic recipe output of the reprocessing plant to yield more than 1 item of a type per cycle
This commit is contained in:
@@ -1,47 +1,13 @@
|
||||
#include "ProductionRules.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
|
||||
#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)
|
||||
{
|
||||
@@ -177,9 +143,44 @@ bool hasInputsToStart(const GameConfig& config, const Building& b)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool outputBufferHasRoom(const Building& b, int outputItemCount)
|
||||
bool outputBufferHasRoom(const Building& b, const ItemType& type, int itemCount)
|
||||
{
|
||||
return b.getOutputItemCount() + outputItemCount <= b.outputBuffer.capacity;
|
||||
const std::map<ItemType, int>::const_iterator capIt = b.outputBuffer.caps.find(type);
|
||||
const int cap = (capIt != b.outputBuffer.caps.end()) ? capIt->second : 0;
|
||||
return b.getOutputItemCount(type) + itemCount <= cap;
|
||||
}
|
||||
|
||||
bool recipeOutputsFit(const Building& b, const RecipeDef& recipe)
|
||||
{
|
||||
if (b.type == BuildingType::ReprocessingPlant)
|
||||
{
|
||||
// One roll yields one of these, so each is measured on its own -- but all of them
|
||||
// have to fit, since which one it will be is not known yet.
|
||||
for (const RecipeOutput& out : recipe.outputs)
|
||||
{
|
||||
if (!outputBufferHasRoom(b, ItemType{out.item}, out.amount))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// A deterministic cycle deposits all of its outputs together. An item listed more
|
||||
// than once is produced in the sum of those amounts, so it is judged once, as a sum.
|
||||
std::map<ItemType, int> perCycle;
|
||||
for (const RecipeOutput& out : recipe.outputs)
|
||||
{
|
||||
perCycle[ItemType{out.item}] += out.amount;
|
||||
}
|
||||
for (const std::pair<const ItemType, int>& entry : perCycle)
|
||||
{
|
||||
if (!outputBufferHasRoom(b, entry.first, entry.second))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool canStartCycle(const GameConfig& config, const Building& b)
|
||||
@@ -193,8 +194,7 @@ bool canStartCycle(const GameConfig& config, const Building& b)
|
||||
|
||||
for (const RecipeDef* recipe : gatherCandidateRecipes(config, b))
|
||||
{
|
||||
if (recipeInputsAvailable(b, *recipe)
|
||||
&& outputBufferHasRoom(b, getCycleOutputItemCount(b, *recipe)))
|
||||
if (recipeInputsAvailable(b, *recipe) && recipeOutputsFit(b, *recipe))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user