Highlight tunnel connections in green when selected

This commit is contained in:
2026-07-21 21:16:21 +02:00
parent a75222f111
commit a8a6a04f1e
6 changed files with 220 additions and 12 deletions

View File

@@ -889,20 +889,11 @@ BuildingType GameWorldView::effectiveBuilderType() const
return inTunnelMode() ? m_tunnelGhostType : *m_builderType;
}
void GameWorldView::updateTunnelGhost()
std::map<std::pair<int, int>, TunnelTileInfo> GameWorldView::collectTunnelTiles() const
{
m_tunnelGhostType = BuildingType::TunnelEntry;
m_tunnelPartnerTile.reset();
// The connection preview and entry/exit switch only apply at a valid placement
// (REQ-BLD-TUNNEL-MODE); at an invalid position the ghost stays a plain entry.
if (!m_ghostValid)
{
return;
}
// Index every tunnel entry/exit — built or still a construction site — by its
// single-cell tile, so a just-placed entry (not yet constructed) is matchable.
// single-cell tile, so a just-placed tunnel (not yet constructed) is matchable
// (REQ-BLD-TUNNEL-MODE, REQ-BLD-TUNNEL-SELECT-HIGHLIGHT).
std::map<std::pair<int, int>, TunnelTileInfo> tunnels;
for (const Building& b : m_sim->getBuildings().getAllBuildings())
{
@@ -918,7 +909,22 @@ void GameWorldView::updateTunnelGhost()
tunnels[{s.anchor.x(), s.anchor.y()}] = TunnelTileInfo{s.type, s.rotation};
}
}
return tunnels;
}
void GameWorldView::updateTunnelGhost()
{
m_tunnelGhostType = BuildingType::TunnelEntry;
m_tunnelPartnerTile.reset();
// The connection preview and entry/exit switch only apply at a valid placement
// (REQ-BLD-TUNNEL-MODE); at an invalid position the ghost stays a plain entry.
if (!m_ghostValid)
{
return;
}
const std::map<std::pair<int, int>, TunnelTileInfo> tunnels = collectTunnelTiles();
const TunnelLookup lookup = [&tunnels](QPoint tile) -> std::optional<TunnelTileInfo>
{
const std::map<std::pair<int, int>, TunnelTileInfo>::const_iterator it =
@@ -1819,8 +1825,71 @@ void GameWorldView::drawBeams(QPainter& painter)
painter.setRenderHints(savedHints);
}
void GameWorldView::drawSelectedTunnelConnections(QPainter& painter)
{
if (m_selectedBuildingIds.empty()) { return; }
const std::map<std::pair<int, int>, TunnelTileInfo> tunnels = collectTunnelTiles();
if (tunnels.empty()) { return; }
const TunnelLookup lookup = [&tunnels](QPoint tile) -> std::optional<TunnelTileInfo>
{
const std::map<std::pair<int, int>, TunnelTileInfo>::const_iterator it =
tunnels.find({tile.x(), tile.y()});
if (it == tunnels.end()) { return std::nullopt; }
return it->second;
};
// Collect the tiles to highlight in a set so a connection selected from both ends
// (or overlapping runs) is filled exactly once — filling a semi-transparent green
// twice would darken it (REQ-BLD-TUNNEL-SELECT-HIGHLIGHT).
std::set<std::pair<int, int>> highlightTiles;
for (const BuildingId id : m_selectedBuildingIds)
{
std::optional<QPoint> anchor;
std::optional<BuildingType> type;
Rotation rotation = Rotation::East;
if (const Building* b = m_sim->getBuildings().findBuilding(id))
{
anchor = b->anchor; type = b->type; rotation = b->rotation;
}
else if (const ConstructionSite* s = m_sim->getBuildings().findSite(id))
{
anchor = s->anchor; type = s->type; rotation = s->rotation;
}
if (!type.has_value()
|| (*type != BuildingType::TunnelEntry && *type != BuildingType::TunnelExit))
{
continue;
}
const std::optional<QPoint> partner = findTunnelPartner(
lookup, *anchor, *type, rotation, m_config->world.tunnelMaxDistance_tiles);
if (!partner.has_value()) { continue; }
// Add every tile from the selected end to its partner inclusive (colinear run).
const QPoint delta = *partner - *anchor;
const QPoint stepDir((delta.x() > 0) - (delta.x() < 0),
(delta.y() > 0) - (delta.y() < 0));
for (QPoint t = *anchor; ; t += stepDir)
{
highlightTiles.insert({t.x(), t.y()});
if (t == *partner) { break; }
}
}
const QColor green = m_visuals->overlays.tunnelPreview;
for (const std::pair<int, int>& tile : highlightTiles)
{
painter.fillRect(tileRect(QPoint(tile.first, tile.second)), green);
}
}
void GameWorldView::drawOverlays(QPainter& painter)
{
// Green connection highlight for any selected tunnel end (REQ-BLD-TUNNEL-SELECT-HIGHLIGHT).
drawSelectedTunnelConnections(painter);
// Builder-mode ghost
if (m_builderType.has_value())
{

View File

@@ -1,9 +1,11 @@
#pragma once
#include <map>
#include <optional>
#include <random>
#include <set>
#include <string>
#include <utility>
#include <vector>
#include <QElapsedTimer>
@@ -42,6 +44,7 @@
#include "Rotation.h"
#include "Tick.h"
#include "TickDriver.h"
#include "TunnelCompletion.h"
#include "VisualsConfig.h"
struct Command;
@@ -214,6 +217,12 @@ private:
// Recomputes m_tunnelGhostType and m_tunnelPartnerTile from the current ghost
// tile, rotation, and sub-tile cursor position. Only meaningful in tunnel mode.
void updateTunnelGhost();
// Indexes every tunnel entry/exit — built or still a construction site — by its
// single-cell tile. Shared by the placement preview and the selection highlight.
std::map<std::pair<int, int>, TunnelTileInfo> collectTunnelTiles() const;
// Draws the green connection highlight for every selected tunnel end that has a
// matching end (REQ-BLD-TUNNEL-SELECT-HIGHLIGHT).
void drawSelectedTunnelConnections(QPainter& painter);
// Belt drag placement (REQ-BLD-BELT-DRAG).
// Per-path-tile decision, shared by ghost drawing and release-time placement.