182 lines
6.2 KiB
C++
182 lines
6.2 KiB
C++
#pragma once
|
|
|
|
#include <functional>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <QPoint>
|
|
#include <QPointF>
|
|
#include <QRect>
|
|
|
|
#include "Item.h"
|
|
#include "ItemType.h"
|
|
#include "Port.h"
|
|
#include "Rotation.h"
|
|
|
|
// Carries item type and fractional world position for the renderer.
|
|
// worldPos is in tile units (1 tile = 1.0 unit); origin matches tile coords.
|
|
struct VisualItem
|
|
{
|
|
ItemType type;
|
|
QPointF worldPos;
|
|
};
|
|
|
|
// Isolated belt-and-splitter transport layer. See architecture.md §Belt Subsystem.
|
|
//
|
|
// Buildings interact only through tryPutItem / tryTakeItem.
|
|
// Rendering reads only through forEachVisualItem.
|
|
// No other system inspects tile contents.
|
|
class BeltSystem
|
|
{
|
|
public:
|
|
explicit BeltSystem(double beltSpeedTilesPerSecond);
|
|
|
|
// -- Placement -----------------------------------------------------------
|
|
// Register a new belt tile. Any items already on this tile are cleared.
|
|
void placeBelt(QPoint tile, Rotation direction);
|
|
|
|
// Register a new tunnel entry tile.
|
|
void placeTunnelEntry(QPoint tile, Rotation direction, int maxDistance);
|
|
|
|
// Register a new tunnel exit tile.
|
|
void placeTunnelExit(QPoint tile, Rotation direction);
|
|
|
|
// Register a new splitter tile. outputA and outputB are the two exit
|
|
// directions (e.g. West and East for a default-rotation splitter).
|
|
// Items entering from any adjacent belt whose direction points into this
|
|
// tile are held and routed to one of the two outputs.
|
|
void placeSplitter(QPoint tile, Rotation outputA, Rotation outputB);
|
|
|
|
// Remove a belt or splitter tile (on demolish). Items are discarded.
|
|
void removeTile(QPoint tile);
|
|
|
|
// -- Splitter filter configuration (REQ-BLD-SPLITTER) -------------------
|
|
// filterA / filterB: empty means "accept all".
|
|
void setSplitterFilters(QPoint tile,
|
|
const std::vector<ItemType>& filterA,
|
|
const std::vector<ItemType>& filterB);
|
|
|
|
struct SplitterInfo
|
|
{
|
|
Rotation outputA;
|
|
Rotation outputB;
|
|
std::vector<ItemType> filterA;
|
|
std::vector<ItemType> filterB;
|
|
};
|
|
std::optional<SplitterInfo> getSplitterInfo(QPoint tile) const;
|
|
|
|
// -- Port interface (buildings <-> belts) --------------------------------
|
|
// port.tile = the belt tile adjacent to the building
|
|
// port.direction = direction items flow on that tile
|
|
//
|
|
// tryPutItem: place item onto tile.
|
|
// Returns false if the tile is not a belt/splitter, or tile full.
|
|
// fromDir: travel direction of the item (used for splitter animation).
|
|
bool tryPutItem(QPoint tile, Item item, Rotation fromDir = Rotation::West);
|
|
|
|
// tryTakeItem: remove and return the leading item from port.tile.
|
|
// Returns nullopt if tile is not a belt, direction mismatches, or tile empty.
|
|
std::optional<Item> tryTakeItem(Port port);
|
|
|
|
// peekItem: return the type of the leading item without removing it.
|
|
// Returns nullopt if tile is not a belt, direction mismatches, or tile empty.
|
|
std::optional<ItemType> peekItem(Port port) const;
|
|
|
|
// -- Maintenance ---------------------------------------------------------
|
|
void clearTiles(const std::vector<QPoint>& tiles); // REQ-UI-BELT-CLEAR
|
|
void tick();
|
|
|
|
// -- Rendering -----------------------------------------------------------
|
|
void forEachVisualItem(QRect viewportTiles,
|
|
std::function<void(VisualItem)> visit) const;
|
|
|
|
private:
|
|
void advanceProgress();
|
|
void advanceTunnelProgress();
|
|
void moveItemsToNextTile();
|
|
void moveTunnelItems();
|
|
void routeSplitterItems();
|
|
|
|
// Place item into back slot of an existing belt tile at progress 0.
|
|
// Returns false if tile is not a belt or is full.
|
|
bool tryPlaceOnBelt(QPoint tile, Item item);
|
|
|
|
// Push an item to any tile type (belt, splitter, tunnel entry, tunnel exit).
|
|
bool tryPushToTile(QPoint dest, Item item, Rotation fromDir);
|
|
|
|
void reevaluateTunnelPairing();
|
|
|
|
static std::pair<int, int> key(QPoint tile);
|
|
static QPoint adjacentTile(QPoint tile, Rotation dir);
|
|
|
|
// Returns the world-space centre of a slot given tile origin and progress.
|
|
static QPointF slotWorldPos(QPoint tile, Rotation dir, double progress);
|
|
|
|
struct BeltItemSlot
|
|
{
|
|
Item item;
|
|
double progress; // [0.0, 1.0]: 0 = just entered, 1 = at output edge
|
|
};
|
|
|
|
struct BeltTile
|
|
{
|
|
Rotation direction;
|
|
// front (highest progress) at index 0; back (just entered) at end. Max 4.
|
|
std::vector<BeltItemSlot> itemSlots;
|
|
};
|
|
|
|
struct SplitterTile
|
|
{
|
|
Rotation outputA;
|
|
Rotation outputB;
|
|
std::vector<ItemType> filterA; // empty = accept all
|
|
std::vector<ItemType> filterB;
|
|
bool nextOutputIsA; // alternation state
|
|
// Unassigned items: [0] = routing candidate (higher progress, caps at 0.5). Max 2.
|
|
std::vector<BeltItemSlot> back;
|
|
std::vector<Rotation> backDir; // feeding belt direction, parallel to back
|
|
std::optional<BeltItemSlot> frontA; // progress [0, 1]; routed to outputA
|
|
std::optional<BeltItemSlot> frontB; // progress [0, 1]; routed to outputB
|
|
};
|
|
|
|
struct TunnelEntryTile
|
|
{
|
|
Rotation direction;
|
|
int maxDistance;
|
|
// front (highest progress) at index 0; back at end. Max 4.
|
|
std::vector<BeltItemSlot> itemSlots;
|
|
};
|
|
|
|
struct TunnelExitTile
|
|
{
|
|
Rotation direction;
|
|
// front (highest progress) at index 0; back at end. Max 4.
|
|
std::vector<BeltItemSlot> itemSlots;
|
|
};
|
|
|
|
struct TunnelTransitItem
|
|
{
|
|
Item item;
|
|
double progress;
|
|
};
|
|
|
|
struct TunnelLink
|
|
{
|
|
QPoint entryTile;
|
|
QPoint exitTile;
|
|
double length;
|
|
std::vector<TunnelTransitItem> items; // front (highest progress) to back
|
|
};
|
|
|
|
double m_progressPerTick; // beltSpeedTilesPerSecond / kTickRateHz
|
|
|
|
std::map<std::pair<int, int>, BeltTile> m_belts;
|
|
std::map<std::pair<int, int>, SplitterTile> m_splitters;
|
|
std::map<std::pair<int, int>, TunnelEntryTile> m_tunnelEntries;
|
|
std::map<std::pair<int, int>, TunnelExitTile> m_tunnelExits;
|
|
std::vector<TunnelLink> m_tunnelLinks;
|
|
};
|
|
|