134 lines
4.9 KiB
C++
134 lines
4.9 KiB
C++
#pragma once
|
||
|
||
#include <map>
|
||
#include <optional>
|
||
#include <string>
|
||
#include <vector>
|
||
|
||
#include <QPoint>
|
||
#include <QSize>
|
||
|
||
#include "BuildingType.h"
|
||
#include "BuildingId.h"
|
||
|
||
#include "entt/entity/entity.hpp"
|
||
#include "BeltSlot.h"
|
||
#include "Item.h"
|
||
#include "ItemType.h"
|
||
#include "Port.h"
|
||
#include "Rotation.h"
|
||
#include "ShipLayout.h"
|
||
#include "Tick.h"
|
||
|
||
// Per-material input buffer for a production building.
|
||
struct InputBuffer
|
||
{
|
||
std::map<ItemType, int> counts; // current item counts per material
|
||
std::map<ItemType, int> caps; // max items per material (2× per-cycle requirement)
|
||
};
|
||
|
||
// Output buffer shared by all output materials for a production building.
|
||
struct OutputBuffer
|
||
{
|
||
std::vector<Item> items;
|
||
int capacity = 0; // 2× per-cycle output; 1× for ReprocessingPlant
|
||
};
|
||
|
||
// Active production cycle for a building.
|
||
struct Production
|
||
{
|
||
std::string recipeId;
|
||
Tick completesAt = 0;
|
||
std::vector<Item> chosenOutputs; // resolved at cycle start (reprocessing rolls here)
|
||
};
|
||
|
||
// A building placed on the map that is still under construction.
|
||
// Occupies tiles but does not produce.
|
||
struct ConstructionSite
|
||
{
|
||
BuildingId id = kInvalidBuildingId;
|
||
QPoint anchor; // top-left of body bounding box
|
||
QSize footprint;
|
||
std::vector<QPoint> bodyCells; // absolute world tile coordinates
|
||
Rotation rotation = Rotation::East;
|
||
BuildingType type = BuildingType::Miner;
|
||
std::string recipeId; // may be configured before completion
|
||
Tick completesAt = 0; // 0 = queued but not yet started
|
||
std::optional<ShipLayoutConfig> shipLayout;
|
||
|
||
// Splitter output filters configured before completion (REQ-BLD-SITE-CONFIG).
|
||
// Empty = accept all; applied to the BeltSystem when the splitter is built.
|
||
std::vector<ItemType> splitterFilterA;
|
||
std::vector<ItemType> splitterFilterB;
|
||
};
|
||
|
||
// A fully constructed, operational building.
|
||
struct Building
|
||
{
|
||
BuildingId id = kInvalidBuildingId;
|
||
QPoint anchor; // top-left of body bounding box
|
||
QSize footprint;
|
||
Rotation rotation = Rotation::East;
|
||
BuildingType type = BuildingType::Miner;
|
||
std::string recipeId; // empty = none selected
|
||
|
||
InputBuffer inputBuffer;
|
||
OutputBuffer outputBuffer;
|
||
std::optional<Production> production;
|
||
|
||
// Items currently emerging from each output port on its virtual output belt
|
||
// (REQ-MAT-OUTPUT-EMERGE); one lane per output port, parallel to outputPorts.
|
||
// Each lane holds slots at progress [0.5, 1.0], front (highest progress) first.
|
||
// An emerging item still counts as residing in the output buffer until it hands
|
||
// off onto a real belt at progress 1.0.
|
||
std::vector<std::vector<BeltItemSlot>> emergingItems;
|
||
|
||
// Total items held on the output side: buffered plus still-emerging. The
|
||
// output-buffer capacity rule (REQ-MAT-OUTPUT-BUFFER) counts emerging items,
|
||
// since they have not yet left the building.
|
||
int getOutputItemCount() const
|
||
{
|
||
int count = static_cast<int>(outputBuffer.items.size());
|
||
for (const std::vector<BeltItemSlot>& lane : emergingItems)
|
||
{
|
||
count += static_cast<int>(lane.size());
|
||
}
|
||
return count;
|
||
}
|
||
|
||
// Items currently travelling inward on each input port's virtual input belt
|
||
// (REQ-MAT-INPUT-INTAKE); one lane per input port, parallel to inputPorts. Each
|
||
// lane holds slots at progress [0.0, 0.5], front (highest progress) first. An
|
||
// in-transit item has reserved a slot in its per-material input buffer but is
|
||
// not yet consumable — it enters the buffer only on reaching progress 0.5.
|
||
std::vector<std::vector<BeltItemSlot>> incomingItems;
|
||
|
||
// Buffered plus in-transit count of one input material. The acceptance/space
|
||
// test (REQ-MAT-INPUT-PORTS, REQ-MAT-INPUT-INTAKE) counts in-transit items, so
|
||
// buffered + reserved never exceeds the material's cap (REQ-MAT-INPUT-BUFFER).
|
||
int pendingInputCount(const ItemType& type) const
|
||
{
|
||
int count = 0;
|
||
const std::map<ItemType, int>::const_iterator it = inputBuffer.counts.find(type);
|
||
if (it != inputBuffer.counts.end()) { count = it->second; }
|
||
for (const std::vector<BeltItemSlot>& lane : incomingItems)
|
||
{
|
||
for (const BeltItemSlot& slot : lane)
|
||
{
|
||
if (slot.item.type == type) { ++count; }
|
||
}
|
||
}
|
||
return count;
|
||
}
|
||
|
||
// Pre-computed from surface mask at placement; in absolute world coordinates.
|
||
std::vector<QPoint> bodyCells;
|
||
std::vector<Port> outputPorts;
|
||
std::vector<Port> inputPorts; // perimeter tiles (minus output-port tiles),
|
||
// direction pointing INTO building
|
||
|
||
// Module layout for shipyards (REQ-MOD-LAYOUT).
|
||
std::optional<ShipLayoutConfig> shipLayout;
|
||
};
|
||
|