#include "ConstructionSystem.h" #include "BuildingBuffers.h" #include "BuildingType.h" #include "FactoryQueries.h" #include "PortGeometry.h" #include "SurfaceMask.h" #include "tracing.h" void ConstructionSystem::tick(FactoryState& state, BeltSystem& belts, Tick currentTick) { TRACE(); if (state.constructionQueue.empty()) { return; } ConstructionSite& front = state.constructionQueue.front(); // Guard: if somehow the front site was never started, start it now. if (front.completesAt == 0) { const BuildingDef* def = m_config.buildings.findBuildingDef(front.type); if (def) { front.completesAt = currentTick + secondsToTicks(def->constructionTimeSeconds); } return; } if (currentTick < front.completesAt) { return; } // Promote construction site to an operational Building. const BuildingDef* def = m_config.buildings.findBuildingDef(front.type); const ParsedSurfaceMask mask = parseSurfaceMask( def ? def->surfaceMask : std::vector{}, front.rotation); Building building; building.id = front.id; building.anchor = front.anchor; building.footprint = front.footprint; building.rotation = front.rotation; building.type = front.type; building.recipeId = front.recipeId; building.shipLayout = front.shipLayout; for (const QPoint& cell : mask.bodyCells) { building.bodyCells.push_back(front.anchor + cell); } for (const Port& port : mask.outputPorts) { Port absPort; absPort.tile = front.anchor + port.tile; absPort.direction = port.direction; building.outputPorts.push_back(absPort); } building.emergingItems.resize(building.outputPorts.size()); building.inputPorts = computeInputPorts(building.bodyCells, building.outputPorts); building.incomingItems.assign(building.inputPorts.size(), {}); if (building.type == BuildingType::SalvageBay) { initSalvageBayBuffer(m_config, building); } else if (!building.recipeId.empty()) { if (building.type == BuildingType::Shipyard) { initShipyardBuffers(m_config, building); } else { const RecipeDef* recipe = m_config.recipes.findRecipeDef(building.recipeId, building.type); if (recipe) { initBuffers(building, *recipe); } } } // Register with BeltSystem before the move (mask/building stays valid). Any // filters configured while under construction carry over (REQ-BLD-SITE-CONFIG). reregisterBeltTile(belts, m_config, building, front.splitterFilterA, front.splitterFilterB); state.buildings.push_back(std::move(building)); state.constructionQueue.pop_front(); // Start next queued site if present. if (!state.constructionQueue.empty() && state.constructionQueue.front().completesAt == 0) { const BuildingDef* nextDef = m_config.buildings.findBuildingDef(state.constructionQueue.front().type); if (nextDef) { state.constructionQueue.front().completesAt = currentTick + secondsToTicks(nextDef->constructionTimeSeconds); } } }