174 lines
5.4 KiB
C++
174 lines
5.4 KiB
C++
#include "BuildingBuffers.h"
|
||
|
||
#include <algorithm>
|
||
#include <cassert>
|
||
|
||
#include "BuildingType.h"
|
||
#include "ItemType.h"
|
||
#include "ModulesConfig.h"
|
||
#include "ShipsConfig.h"
|
||
|
||
void initBuffers(Building& b, const RecipeDef& recipe)
|
||
{
|
||
b.inputBuffer.counts.clear();
|
||
b.inputBuffer.caps.clear();
|
||
for (const RecipeIngredient& ing : recipe.inputs)
|
||
{
|
||
const ItemType type{ing.item};
|
||
b.inputBuffer.counts[type] = 0;
|
||
b.inputBuffer.caps[type] = 2 * ing.amount;
|
||
}
|
||
|
||
b.outputBuffer.items.clear();
|
||
if (b.type == BuildingType::ReprocessingPlant)
|
||
{
|
||
// 1× max-per-roll (REQ-MAT-OUTPUT-BUFFER-REPROCESSING).
|
||
int maxAmount = 0;
|
||
for (const RecipeOutput& out : recipe.outputs)
|
||
{
|
||
if (out.amount > maxAmount)
|
||
{
|
||
maxAmount = out.amount;
|
||
}
|
||
}
|
||
b.outputBuffer.capacity = maxAmount;
|
||
}
|
||
else
|
||
{
|
||
// 2× per-cycle output.
|
||
int totalAmount = 0;
|
||
for (const RecipeOutput& out : recipe.outputs)
|
||
{
|
||
totalAmount += out.amount;
|
||
}
|
||
b.outputBuffer.capacity = 2 * totalAmount;
|
||
}
|
||
}
|
||
|
||
void initAutoBuffers(const GameConfig& config, Building& b)
|
||
{
|
||
b.inputBuffer.counts.clear();
|
||
b.inputBuffer.caps.clear();
|
||
|
||
// Union the inputs of every recipe of this building type; the cap for each
|
||
// item is twice the largest per-cycle requirement across those recipes.
|
||
// Output capacity follows the same rules as initBuffers: the Reprocessing
|
||
// Plant holds one cycle's max output (REQ-MAT-OUTPUT-BUFFER-REPROCESSING),
|
||
// other auto buildings hold twice the largest per-cycle output.
|
||
int outputCapacity = 0;
|
||
for (const RecipeDef& recipe : config.recipes.recipes)
|
||
{
|
||
if (recipe.building != b.type)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
for (const RecipeIngredient& ing : recipe.inputs)
|
||
{
|
||
const ItemType type{ing.item};
|
||
b.inputBuffer.counts[type] = 0;
|
||
b.inputBuffer.caps[type] =
|
||
std::max(b.inputBuffer.caps[type], 2 * ing.amount);
|
||
}
|
||
|
||
if (b.type == BuildingType::ReprocessingPlant)
|
||
{
|
||
int maxAmount = 0;
|
||
for (const RecipeOutput& out : recipe.outputs)
|
||
{
|
||
maxAmount = std::max(maxAmount, out.amount);
|
||
}
|
||
outputCapacity = std::max(outputCapacity, maxAmount);
|
||
}
|
||
else
|
||
{
|
||
int totalAmount = 0;
|
||
for (const RecipeOutput& out : recipe.outputs)
|
||
{
|
||
totalAmount += out.amount;
|
||
}
|
||
outputCapacity = std::max(outputCapacity, 2 * totalAmount);
|
||
}
|
||
}
|
||
|
||
b.outputBuffer.items.clear();
|
||
b.outputBuffer.capacity = outputCapacity;
|
||
}
|
||
|
||
void initShipyardBuffers(const GameConfig& config, Building& b)
|
||
{
|
||
b.inputBuffer.counts.clear();
|
||
b.inputBuffer.caps.clear();
|
||
b.outputBuffer.items.clear();
|
||
b.outputBuffer.capacity = 0;
|
||
const ShipDef* def = config.ships.findShipDef(b.recipeId);
|
||
if (!def)
|
||
{
|
||
return;
|
||
}
|
||
for (const RecipeIngredient& ing : def->schematic.materials)
|
||
{
|
||
const ItemType type{ing.item};
|
||
b.inputBuffer.counts[type] = 0;
|
||
b.inputBuffer.caps[type] = 2 * ing.amount;
|
||
}
|
||
if (b.shipLayout.has_value())
|
||
{
|
||
for (const PlacedModule& pm : b.shipLayout->placedModules)
|
||
{
|
||
const ModuleDef* modDef = config.modules.findModuleDef(pm.moduleId);
|
||
if (!modDef)
|
||
{
|
||
continue;
|
||
}
|
||
for (const RecipeIngredient& ing : modDef->materials)
|
||
{
|
||
const ItemType type{ing.item};
|
||
b.inputBuffer.counts.try_emplace(type, 0);
|
||
b.inputBuffer.caps[type] += 2 * ing.amount;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void initSalvageBayBuffer(const GameConfig& config, Building& b)
|
||
{
|
||
// Salvage Bay has no recipe-driven buffer; its output-buffer holding size for
|
||
// ship drop-off is config-defined (REQ-BLD-SALVAGE-BAY).
|
||
b.outputBuffer.items.clear();
|
||
const BuildingDef* def = config.buildings.findBuildingDef(BuildingType::SalvageBay);
|
||
b.outputBuffer.capacity =
|
||
(def && def->outputBufferCapacity) ? *def->outputBufferCapacity : 0;
|
||
}
|
||
|
||
|
||
void reregisterBeltTile(BeltSystem& belts, const GameConfig& config,
|
||
const Building& building,
|
||
const std::vector<ItemType>& splitterFilterA,
|
||
const std::vector<ItemType>& splitterFilterB)
|
||
{
|
||
switch (building.type)
|
||
{
|
||
case BuildingType::Belt:
|
||
belts.placeBelt(building.anchor, building.rotation);
|
||
break;
|
||
case BuildingType::Splitter:
|
||
assert(building.outputPorts.size() >= 2);
|
||
belts.placeSplitter(building.anchor,
|
||
building.outputPorts[0].direction,
|
||
building.outputPorts[1].direction);
|
||
belts.setSplitterFilters(building.anchor, splitterFilterA, splitterFilterB);
|
||
break;
|
||
case BuildingType::TunnelEntry:
|
||
belts.placeTunnelEntry(building.anchor, building.rotation,
|
||
config.world.tunnelMaxDistance_tiles);
|
||
break;
|
||
case BuildingType::TunnelExit:
|
||
belts.placeTunnelExit(building.anchor, building.rotation);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|