#include "BuildingBuffers.h" #include #include #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& splitterFilterA, const std::vector& 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; } }