Snap belt-drag end tile to a building's input edge
When a belt drag ends with the cursor over a non-belt building or construction site, the end tile now snaps to the input-capable adjacent tile closest to the cursor and points into the target, instead of showing an invalid ghost on the occupied tile. Adds BuildingSystem::getInputPorts(id) (reusing computeInputPorts, refactored into a bodyCells+outputPorts core) as the single source of truth for a target's input-capable adjacent tiles; works for both operational buildings (stored inputPorts) and construction sites (mask-derived). GameWorldView tracks the cursor world position and, in recomputeBeltDragPath, picks the nearest input port and overrides the end tile's rotation. Ghost preview, resolve, and apply consume the snapped path unchanged. Implements REQ-BLD-BELT-DRAG snapping-to-a-building. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Y7N59FsLA5e2kuVdqe4Uhc
This commit is contained in:
@@ -267,16 +267,23 @@ void BuildingSystem::initSalvageBayBuffer(Building& b) const
|
||||
}
|
||||
|
||||
std::vector<Port> BuildingSystem::computeInputPorts(const Building& b) const
|
||||
{
|
||||
return computeInputPorts(b.bodyCells, b.outputPorts);
|
||||
}
|
||||
|
||||
std::vector<Port> BuildingSystem::computeInputPorts(
|
||||
const std::vector<QPoint>& bodyCells,
|
||||
const std::vector<Port>& outputPorts) const
|
||||
{
|
||||
// Build lookup sets for quick membership checks.
|
||||
std::set<std::pair<int, int>> bodySet;
|
||||
for (const QPoint& cell : b.bodyCells)
|
||||
for (const QPoint& cell : bodyCells)
|
||||
{
|
||||
bodySet.insert({cell.x(), cell.y()});
|
||||
}
|
||||
|
||||
std::set<std::pair<int, int>> outputPortTiles;
|
||||
for (const Port& port : b.outputPorts)
|
||||
for (const Port& port : outputPorts)
|
||||
{
|
||||
outputPortTiles.insert({port.tile.x(), port.tile.y()});
|
||||
}
|
||||
@@ -294,7 +301,7 @@ std::vector<Port> BuildingSystem::computeInputPorts(const Building& b) const
|
||||
std::set<std::pair<int, int>> seen;
|
||||
std::vector<Port> inputPorts;
|
||||
|
||||
for (const QPoint& cell : b.bodyCells)
|
||||
for (const QPoint& cell : bodyCells)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
@@ -317,6 +324,30 @@ std::vector<Port> BuildingSystem::computeInputPorts(const Building& b) const
|
||||
return inputPorts;
|
||||
}
|
||||
|
||||
std::vector<Port> BuildingSystem::getInputPorts(BuildingId id) const
|
||||
{
|
||||
if (const Building* building = findBuilding(id))
|
||||
{
|
||||
return building->inputPorts;
|
||||
}
|
||||
if (const ConstructionSite* site = findSite(id))
|
||||
{
|
||||
// A site stores no ports; derive its output ports from the mask (absolute)
|
||||
// and run the same input-edge scan (REQ-BLD-BELT-DRAG, REQ-MAT-INPUT-PORTS).
|
||||
const BuildingDef* def = findBuildingDef(site->type);
|
||||
if (def == nullptr) { return {}; }
|
||||
const ParsedSurfaceMask mask = parseSurfaceMask(def->surfaceMask, site->rotation);
|
||||
std::vector<Port> outputPortsAbsolute;
|
||||
outputPortsAbsolute.reserve(mask.outputPorts.size());
|
||||
for (const Port& port : mask.outputPorts)
|
||||
{
|
||||
outputPortsAbsolute.push_back(Port{ site->anchor + port.tile, port.direction });
|
||||
}
|
||||
return computeInputPorts(site->bodyCells, outputPortsAbsolute);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<Item> BuildingSystem::rollReprocessingOutput(const RecipeDef& recipe)
|
||||
{
|
||||
std::vector<const RecipeOutput*> eligible;
|
||||
|
||||
Reference in New Issue
Block a user