Files
dota_factory/src/lib/sim/Building.h

161 lines
6.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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)
};
// Per-material output buffer for a production building. The items are held in one
// production-ordered queue -- that is the order they leave at the output port
// (REQ-MAT-OUTPUT-EMERGE) -- while the capacity is per item type, so one item's backlog
// never occupies another's room (REQ-MAT-OUTPUT-BUFFER).
struct OutputBuffer
{
std::vector<Item> items; // production order; feeds the output belt
std::map<ItemType, int> caps; // max items per material (2x its per-cycle amount)
};
// 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;
}
// The same over one material, which is what its own capacity is measured against
// (REQ-MAT-OUTPUT-BUFFER).
int getOutputItemCount(const ItemType& type) const
{
int count = 0;
for (const Item& item : outputBuffer.items)
{
if (item.type == type) { ++count; }
}
for (const std::vector<BeltItemSlot>& lane : emergingItems)
{
for (const BeltItemSlot& slot : lane)
{
if (slot.item.type == type) { ++count; }
}
}
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;
// True while this building sits in the deconstruction queue (REQ-BLD-DECON-QUEUE).
// A queued building stops operating immediately (all tick loops skip it) but keeps
// occupying its tiles until its deconstruction completes.
bool queuedForDeconstruction = false;
};