Unify tunnel build mode into a single Tunnel button

This commit is contained in:
2026-07-21 21:12:06 +02:00
parent 4ca5b332cd
commit 9b63af6ccb
14 changed files with 522 additions and 63 deletions

View File

@@ -4,6 +4,7 @@
#include "StateChecksum.h"
#include "Tick.h"
#include "TunnelCompletion.h"
#include "tracing.h"
// ---------------------------------------------------------------------------
@@ -177,55 +178,57 @@ void BeltSystem::reevaluateTunnelPairing()
std::vector<TunnelLink> oldLinks;
std::swap(oldLinks, m_tunnelLinks);
// Tunnel index over this system's own (completed) tunnel tiles, shared with the
// scan primitive so the pairing rule lives in one place (REQ-BLD-TUNNEL-PAIR).
const TunnelLookup lookup = [this](QPoint tile) -> std::optional<TunnelTileInfo>
{
const std::map<std::pair<int, int>, TunnelEntryTile>::const_iterator teIt =
m_tunnelEntries.find(key(tile));
if (teIt != m_tunnelEntries.end())
{
return TunnelTileInfo{BuildingType::TunnelEntry, teIt->second.direction};
}
const std::map<std::pair<int, int>, TunnelExitTile>::const_iterator txIt =
m_tunnelExits.find(key(tile));
if (txIt != m_tunnelExits.end())
{
return TunnelTileInfo{BuildingType::TunnelExit, txIt->second.direction};
}
return std::nullopt;
};
for (const std::pair<const std::pair<int, int>, TunnelEntryTile>& entry : m_tunnelEntries)
{
const QPoint entryPos(entry.first.first, entry.first.second);
const Rotation dir = entry.second.direction;
const int maxDist = entry.second.maxDistance;
for (int d = 1; d <= maxDist; ++d)
// The first same-direction tunnel ahead forms a pair only when it is an exit;
// a same-direction entry blocks (firstTunnelFacing stops at it either way).
const std::optional<QPoint> target =
firstTunnelFacing(lookup, entryPos, dir, dir, maxDist);
if (!target.has_value() || m_tunnelExits.find(key(*target)) == m_tunnelExits.end())
{
QPoint probe = entryPos;
for (int step = 0; step < d; ++step)
{
probe = adjacentTile(probe, dir);
}
continue;
}
// Check if a same-direction tunnel entry is here (blocks pairing)
const std::map<std::pair<int, int>, TunnelEntryTile>::const_iterator teIt =
m_tunnelEntries.find(key(probe));
if (teIt != m_tunnelEntries.end() && teIt->second.direction == dir)
TunnelLink link;
link.entryTile = entryPos;
link.exitTile = *target;
// The exit is colinear with the entry along `dir`, so the tile-coordinate
// distance is the Manhattan distance.
link.length = static_cast<double>((*target - entryPos).manhattanLength());
for (const TunnelLink& old : oldLinks)
{
if (old.entryTile == entryPos && old.exitTile == *target)
{
link.items = old.items;
break;
}
// Check if a same-direction tunnel exit is here (forms pair)
const std::map<std::pair<int, int>, TunnelExitTile>::const_iterator txIt =
m_tunnelExits.find(key(probe));
if (txIt != m_tunnelExits.end())
{
if (txIt->second.direction == dir)
{
TunnelLink link;
link.entryTile = entryPos;
link.exitTile = probe;
link.length = static_cast<double>(d);
for (const TunnelLink& old : oldLinks)
{
if (old.entryTile == entryPos && old.exitTile == probe)
{
link.items = old.items;
break;
}
}
m_tunnelLinks.push_back(std::move(link));
break;
}
// Different direction exit — skip, keep searching
}
}
m_tunnelLinks.push_back(std::move(link));
}
}