113 lines
3.5 KiB
C++
113 lines
3.5 KiB
C++
#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<std::string>{},
|
|
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 (isAutoRecipeBuildingType(building.type))
|
|
{
|
|
// Smelter/Reprocessing Plant need no recipe selection; buffers are set
|
|
// up from all recipes of the type (REQ-BLD-SMELTER, REQ-BLD-REPROCESSING).
|
|
initAutoBuffers(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);
|
|
}
|
|
}
|
|
}
|
|
|