implement blueprints

This commit is contained in:
2026-04-26 21:56:49 +02:00
parent 4605c2e443
commit 71677b806a
8 changed files with 453 additions and 3 deletions

View File

@@ -452,6 +452,29 @@ void GameWorldView::stepSpeed(int delta)
setGameSpeed(kSpeeds[next]);
}
void GameWorldView::placeBlueprintAtTile(QPoint center)
{
const Blueprint& bp = *m_blueprintMode;
for (const BlueprintBuilding& bb : bp.buildings)
{
if (!isValidPlacement(bb.type, center + bb.offset, bb.rotation)) { return; }
}
int totalCost = 0;
for (const BlueprintBuilding& bb : bp.buildings)
{
const BuildingDef* def = findBuildingDef(bb.type);
if (def) { totalCost += def->cost; }
}
if (m_sim->buildingBlocksStock() < totalCost) { return; }
for (const BlueprintBuilding& bb : bp.buildings)
{
m_sim->tryPlaceBuilding(bb.type, center + bb.offset, bb.rotation);
}
}
void GameWorldView::placeAtTile(QPoint tile)
{
if (!m_builderType.has_value())
@@ -776,6 +799,32 @@ void GameWorldView::drawOverlays(QPainter& painter)
}
}
// Blueprint placement ghost
if (m_blueprintMode.has_value())
{
for (const BlueprintBuilding& bb : m_blueprintMode->buildings)
{
const QPoint anchor = m_blueprintGhostTile + bb.offset;
const bool valid = isValidPlacement(bb.type, anchor, bb.rotation);
const QColor& ghostColor = valid
? m_visuals->overlays.ghostValid
: m_visuals->overlays.ghostInvalid;
const BuildingDef* def = findBuildingDef(bb.type);
if (!def) { continue; }
const ParsedSurfaceMask parsed = parseSurfaceMask(def->surfaceMask, bb.rotation);
for (const QPoint& cell : parsed.bodyCells)
{
painter.fillRect(tileRect(anchor + cell), ghostColor);
}
for (const Port& port : parsed.outputPorts)
{
drawPortGlyph(painter,
anchor + portBodyTile(port.tile, port.direction),
port.direction, Qt::white);
}
}
}
// Demolish hover tint
if (m_demolishMode && m_demolishHoverId != kInvalidEntityId)
{
@@ -883,6 +932,14 @@ void GameWorldView::keyPressEvent(QKeyEvent* event)
m_ghostRotation = rotateClockwise(m_ghostRotation);
m_ghostValid = isValidPlacement(*m_builderType, m_ghostTile, m_ghostRotation);
}
else if (m_blueprintMode.has_value())
{
for (BlueprintBuilding& bb : m_blueprintMode->buildings)
{
bb.offset = QPoint(-bb.offset.y(), bb.offset.x());
bb.rotation = rotateClockwise(bb.rotation);
}
}
break;
case Qt::Key_Q:
if (m_builderType.has_value())
@@ -890,6 +947,14 @@ void GameWorldView::keyPressEvent(QKeyEvent* event)
m_ghostRotation = rotateCounterClockwise(m_ghostRotation);
m_ghostValid = isValidPlacement(*m_builderType, m_ghostTile, m_ghostRotation);
}
else if (m_blueprintMode.has_value())
{
for (BlueprintBuilding& bb : m_blueprintMode->buildings)
{
bb.offset = QPoint(bb.offset.y(), -bb.offset.x());
bb.rotation = rotateCounterClockwise(bb.rotation);
}
}
break;
case Qt::Key_Escape:
emit escapeMenuRequested();
@@ -919,9 +984,10 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
{
if (event->button() != Qt::LeftButton)
{
if (event->button() == Qt::RightButton && m_builderType.has_value())
if (event->button() == Qt::RightButton)
{
exitBuilderMode();
if (m_builderType.has_value()) { exitBuilderMode(); }
else if (m_blueprintMode.has_value()) { exitBlueprintMode(); }
}
return;
}
@@ -942,6 +1008,10 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
placeAtTile(tile);
}
}
else if (m_blueprintMode.has_value())
{
placeBlueprintAtTile(tile);
}
else if (m_demolishMode)
{
EntityId hovered = buildingAtTile(tile);
@@ -1012,6 +1082,10 @@ void GameWorldView::mouseMoveEvent(QMouseEvent* event)
placeAtTile(tile);
}
}
else if (m_blueprintMode.has_value())
{
m_blueprintGhostTile = tile;
}
else if (m_demolishMode)
{
m_demolishHoverId = buildingAtTile(tile);
@@ -1088,7 +1162,8 @@ void GameWorldView::toggleDemolishMode()
}
else
{
if (m_builderType.has_value()) { exitBuilderMode(); }
if (m_builderType.has_value()) { exitBuilderMode(); }
if (m_blueprintMode.has_value()) { exitBlueprintMode(); }
m_demolishMode = true;
}
emit demolishModeChanged(m_demolishMode);
@@ -1100,9 +1175,25 @@ void GameWorldView::enterBuilderMode(BuildingType type)
m_ghostRotation = Rotation::East;
m_ghostValid = false;
m_demolishMode = false;
m_blueprintMode.reset();
emit demolishModeChanged(false);
}
void GameWorldView::enterBlueprintMode(Blueprint blueprint)
{
if (m_builderType.has_value()) { exitBuilderMode(); }
m_demolishMode = false;
emit demolishModeChanged(false);
m_blueprintGhostTile = m_ghostTile;
m_blueprintMode = std::move(blueprint);
}
void GameWorldView::exitBlueprintMode()
{
m_blueprintMode.reset();
emit blueprintModeExited();
}
void GameWorldView::exitBuilderMode()
{
m_builderType.reset();
@@ -1127,6 +1218,7 @@ void GameWorldView::setGameSpeed(double multiplier)
void GameWorldView::resetForNewGame()
{
exitBuilderMode();
exitBlueprintMode();
m_activeBeams.clear();
m_toasts.clear();
m_ghostRotation = Rotation::East;