extract BuildModeController, fixing a silent blueprint exit

This commit is contained in:
2026-08-05 20:41:57 +02:00
parent 202f583067
commit 26d7448492
7 changed files with 803 additions and 204 deletions

View File

@@ -0,0 +1,261 @@
#include "BuildModeController.h"
#include <memory>
#include <utility>
#include "BlueprintModeExitedEvent.h"
#include "BuilderModeExitedEvent.h"
#include "DeconstructModeChangedEvent.h"
#include "EventManager.h"
namespace
{
Rotation rotateClockwise(Rotation rotation)
{
switch (rotation)
{
case Rotation::North: return Rotation::East;
case Rotation::East: return Rotation::South;
case Rotation::South: return Rotation::West;
case Rotation::West: return Rotation::North;
}
return Rotation::East;
}
Rotation rotateCounterClockwise(Rotation rotation)
{
switch (rotation)
{
case Rotation::North: return Rotation::West;
case Rotation::East: return Rotation::North;
case Rotation::South: return Rotation::East;
case Rotation::West: return Rotation::South;
}
return Rotation::East;
}
} // namespace
BuildMode BuildModeController::getMode() const
{
return m_mode;
}
bool BuildModeController::isBuilderMode() const
{
return m_mode == BuildMode::Builder;
}
bool BuildModeController::isBlueprintMode() const
{
return m_mode == BuildMode::Blueprint;
}
bool BuildModeController::isDeconstructMode() const
{
return m_mode == BuildMode::Deconstruct;
}
void BuildModeController::enterMode(BuildMode mode)
{
if (m_mode == mode) { return; }
// Leave the current mode properly, so its widget hears about it however the
// player left. Each exit clears only its own state.
switch (m_mode)
{
case BuildMode::Builder:
m_draggingBelt = false;
m_beltDragPath.clear();
EventManager::getInstance()->sendEventImmediately(
std::make_shared<BuilderModeExitedEvent>());
break;
case BuildMode::Blueprint:
EventManager::getInstance()->sendEventImmediately(
std::make_shared<BlueprintModeExitedEvent>());
break;
case BuildMode::Deconstruct:
m_deconstructHoverBuildingId.reset();
EventManager::getInstance()->sendEventImmediately(
std::make_shared<DeconstructModeChangedEvent>(false));
break;
case BuildMode::None:
break;
}
m_mode = mode;
if (mode == BuildMode::Deconstruct)
{
EventManager::getInstance()->sendEventImmediately(
std::make_shared<DeconstructModeChangedEvent>(true));
}
}
void BuildModeController::enterBuilderMode(BuildingType type)
{
enterMode(BuildMode::Builder);
m_builderType = type;
m_ghostRotation = Rotation::East;
m_ghostValid = false;
m_tunnelGhostType = BuildingType::TunnelEntry;
m_tunnelPartnerTile.reset();
}
void BuildModeController::enterBlueprintMode(Blueprint blueprint)
{
enterMode(BuildMode::Blueprint);
// The layout starts where the builder ghost last was, so switching from a
// building to a blueprint does not jump the preview across the world.
m_blueprintGhostTile = m_ghostTile;
m_blueprint = std::move(blueprint);
}
void BuildModeController::toggleDeconstructMode()
{
enterMode(isDeconstructMode() ? BuildMode::None : BuildMode::Deconstruct);
}
void BuildModeController::exitBuilderMode()
{
if (!isBuilderMode()) { return; }
enterMode(BuildMode::None);
}
void BuildModeController::exitBlueprintMode()
{
if (!isBlueprintMode()) { return; }
enterMode(BuildMode::None);
}
void BuildModeController::exitCurrentMode()
{
enterMode(BuildMode::None);
}
BuildingType BuildModeController::getBuilderType() const
{
return m_builderType;
}
bool BuildModeController::isTunnelMode() const
{
return isBuilderMode() && m_builderType == BuildingType::TunnelEntry;
}
BuildingType BuildModeController::getEffectiveBuilderType() const
{
return isTunnelMode() ? m_tunnelGhostType : m_builderType;
}
QPoint BuildModeController::getGhostTile() const
{
return m_ghostTile;
}
Rotation BuildModeController::getGhostRotation() const
{
return m_ghostRotation;
}
bool BuildModeController::isGhostValid() const
{
return m_ghostValid;
}
void BuildModeController::setGhostTile(QPoint tile)
{
m_ghostTile = tile;
}
void BuildModeController::setGhostValidity(bool valid)
{
m_ghostValid = valid;
}
void BuildModeController::rotateGhost(bool clockwise)
{
m_ghostRotation = clockwise ? rotateClockwise(m_ghostRotation)
: rotateCounterClockwise(m_ghostRotation);
}
BuildingType BuildModeController::getTunnelGhostType() const
{
return m_tunnelGhostType;
}
const std::optional<QPoint>& BuildModeController::getTunnelPartnerTile() const
{
return m_tunnelPartnerTile;
}
void BuildModeController::setTunnelGhost(BuildingType resolvedType,
std::optional<QPoint> partnerTile)
{
m_tunnelGhostType = resolvedType;
m_tunnelPartnerTile = std::move(partnerTile);
}
bool BuildModeController::isDraggingBelt() const
{
return m_draggingBelt;
}
QPoint BuildModeController::getBeltDragAnchor() const
{
return m_beltDragAnchor;
}
const std::vector<BeltPathTile>& BuildModeController::getBeltDragPath() const
{
return m_beltDragPath;
}
void BuildModeController::beginBeltDrag(QPoint anchorTile)
{
m_draggingBelt = true;
m_beltDragAnchor = anchorTile;
}
void BuildModeController::setBeltDragPath(std::vector<BeltPathTile> path)
{
m_beltDragPath = std::move(path);
}
void BuildModeController::cancelBeltDrag()
{
m_draggingBelt = false;
m_beltDragPath.clear();
}
const Blueprint& BuildModeController::getBlueprint() const
{
return m_blueprint;
}
Blueprint& BuildModeController::getMutableBlueprint()
{
return m_blueprint;
}
QPoint BuildModeController::getBlueprintGhostTile() const
{
return m_blueprintGhostTile;
}
void BuildModeController::setBlueprintGhostTile(QPoint tile)
{
m_blueprintGhostTile = tile;
}
const std::optional<BuildingId>&
BuildModeController::getDeconstructHoverBuildingId() const
{
return m_deconstructHoverBuildingId;
}
void BuildModeController::setDeconstructHoverBuildingId(std::optional<BuildingId> id)
{
m_deconstructHoverBuildingId = std::move(id);
}