124 lines
5.1 KiB
C++
124 lines
5.1 KiB
C++
#pragma once
|
|
|
|
#include <optional>
|
|
#include <vector>
|
|
|
|
#include <QPoint>
|
|
|
|
#include "BeltDragPath.h"
|
|
#include "Blueprint.h"
|
|
#include "BuildingId.h"
|
|
#include "BuildingType.h"
|
|
#include "Rotation.h"
|
|
|
|
// Which of the mutually exclusive world-interaction modes is active
|
|
// (REQ-UI-HOTKEYS, REQ-BLD-GHOST, REQ-UI-BLUEPRINT-PLACE, REQ-BLD-DECONSTRUCT).
|
|
enum class BuildMode
|
|
{
|
|
None, // plain selection
|
|
Builder, // placing one building type, ghost following the cursor
|
|
Blueprint, // placing a saved multi-building layout
|
|
Deconstruct // marking buildings for demolition
|
|
};
|
|
|
|
// The active build mode and the transient state that belongs to it.
|
|
//
|
|
// These modes were previously three independent flags, and every entry point
|
|
// cleared the other two by hand — inconsistently, which is how entering builder
|
|
// mode came to drop a blueprint without announcing it. Here exclusivity is
|
|
// structural: one mode is active, and every transition runs through enterMode(),
|
|
// which exits whatever was active first and publishes the same events regardless
|
|
// of which way the player got there.
|
|
//
|
|
// Everything needing the simulation — placement validity, tunnel matching, belt
|
|
// path building — stays with the caller, which computes and hands back the result
|
|
// (setGhostValidity, setTunnelGhost, setBeltDragPath). That keeps this a plain
|
|
// value that can be tested without a world.
|
|
class BuildModeController
|
|
{
|
|
public:
|
|
BuildMode getMode() const;
|
|
bool isBuilderMode() const;
|
|
bool isBlueprintMode() const;
|
|
bool isDeconstructMode() const;
|
|
|
|
// --- transitions ----------------------------------------------------------
|
|
// Each leaves the previously active mode with its proper exit event.
|
|
void enterBuilderMode(BuildingType type);
|
|
void enterBlueprintMode(Blueprint blueprint);
|
|
// Leaves deconstruct mode if it is active, enters it otherwise
|
|
// (REQ-BLD-DECONSTRUCT-CLICK).
|
|
void toggleDeconstructMode();
|
|
void exitBuilderMode();
|
|
void exitBlueprintMode();
|
|
// Backs out of whichever mode is active, if any (the Q key and right-click).
|
|
void exitCurrentMode();
|
|
|
|
// --- builder mode ---------------------------------------------------------
|
|
// Only meaningful while isBuilderMode().
|
|
BuildingType getBuilderType() const;
|
|
// True while the builder type is TunnelEntry, where the ghost resolves to an
|
|
// entry or an exit by hovered position (REQ-BLD-TUNNEL-MODE).
|
|
bool isTunnelMode() const;
|
|
// The type the ghost currently represents: the position-resolved tunnel type in
|
|
// tunnel mode, the plain builder type otherwise.
|
|
BuildingType getEffectiveBuilderType() const;
|
|
|
|
QPoint getGhostTile() const;
|
|
Rotation getGhostRotation() const;
|
|
bool isGhostValid() const;
|
|
void setGhostTile(QPoint tile);
|
|
void setGhostValidity(bool valid);
|
|
// Turns the ghost one quarter turn. Validity is not rechecked here; the caller
|
|
// does that and calls setGhostValidity, because only it can see the world.
|
|
void rotateGhost(bool clockwise);
|
|
|
|
BuildingType getTunnelGhostType() const;
|
|
const std::optional<QPoint>& getTunnelPartnerTile() const;
|
|
void setTunnelGhost(BuildingType resolvedType, std::optional<QPoint> partnerTile);
|
|
|
|
// --- belt drag placement (REQ-BLD-BELT-DRAG) ------------------------------
|
|
bool isDraggingBelt() const;
|
|
QPoint getBeltDragAnchor() const;
|
|
const std::vector<BeltPathTile>& getBeltDragPath() const;
|
|
void beginBeltDrag(QPoint anchorTile);
|
|
void setBeltDragPath(std::vector<BeltPathTile> path);
|
|
// Drops the drag without placing anything, staying in builder mode.
|
|
void cancelBeltDrag();
|
|
|
|
// --- blueprint mode -------------------------------------------------------
|
|
// Only meaningful while isBlueprintMode().
|
|
const Blueprint& getBlueprint() const;
|
|
// Mutable so the caller can rotate the layout in place; rotating a blueprint
|
|
// needs building footprints from the config, which does not belong here.
|
|
Blueprint& getMutableBlueprint();
|
|
QPoint getBlueprintGhostTile() const;
|
|
void setBlueprintGhostTile(QPoint tile);
|
|
|
|
// --- deconstruct mode -----------------------------------------------------
|
|
const std::optional<BuildingId>& getDeconstructHoverBuildingId() const;
|
|
void setDeconstructHoverBuildingId(std::optional<BuildingId> id);
|
|
|
|
private:
|
|
// The single transition point: leaves the active mode, then enters `mode`.
|
|
void enterMode(BuildMode mode);
|
|
|
|
BuildMode m_mode = BuildMode::None;
|
|
|
|
BuildingType m_builderType = BuildingType::Belt;
|
|
QPoint m_ghostTile;
|
|
Rotation m_ghostRotation = Rotation::East;
|
|
bool m_ghostValid = false;
|
|
BuildingType m_tunnelGhostType = BuildingType::TunnelEntry;
|
|
std::optional<QPoint> m_tunnelPartnerTile;
|
|
|
|
bool m_draggingBelt = false;
|
|
QPoint m_beltDragAnchor;
|
|
std::vector<BeltPathTile> m_beltDragPath;
|
|
|
|
Blueprint m_blueprint;
|
|
QPoint m_blueprintGhostTile;
|
|
|
|
std::optional<BuildingId> m_deconstructHoverBuildingId;
|
|
};
|