let any blueprint transfer configuration, not just single-building ones (if the orientation matches)

This commit is contained in:
2026-08-06 20:29:20 +02:00
parent 08d8b0dd90
commit 98deab932a
4 changed files with 93 additions and 36 deletions

View File

@@ -1198,24 +1198,72 @@ TEST_CASE("resolveBlueprintGhost: a single building with no settings overlaps in
== BlueprintGhostAction::Invalid);
}
TEST_CASE("resolveBlueprintGhost: nothing in a multi-building blueprint transfers",
TEST_CASE("resolveBlueprintGhost: a constellation transfers onto a matching building",
"[blueprint]")
{
// Even a configurable building coinciding with its twin only overlaps once the
// blueprint holds more than one building (REQ-UI-BLUEPRINT-TRANSFER).
// Blueprint size does not gate the transfer itself: a configurable building already
// standing where the blueprint wants it, facing the same way, takes its settings
// whatever else the blueprint holds (REQ-UI-BLUEPRINT-TRANSFER).
PlacementFixture f;
const BuildingId id =
f.bs.place(f.state, BuildingType::Miner, QPoint(-2, 0), Rotation::East, 0).value();
const BlueprintGhostResolved matching =
const BlueprintGhostResolved resolved =
resolveInConstellation(f, BuildingType::Miner, QPoint(-2, 0), Rotation::East);
REQUIRE(matching.action == BlueprintGhostAction::CompatibleOverlap);
CHECK(*matching.targetId == id);
REQUIRE(resolved.action == BlueprintGhostAction::Transfer);
CHECK(*resolved.targetId == id);
}
// ... and a differently-facing twin blocks the whole constellation.
CHECK(resolveInConstellation(f, BuildingType::Miner, QPoint(-2, 0), Rotation::North).action
TEST_CASE("resolveBlueprintGhost: only a single-building blueprint ignores target rotation",
"[blueprint]")
{
// The one thing blueprint size still decides. Inside a constellation a differently
// facing twin cannot be re-oriented, so it blocks the whole placement; alone, the
// gesture transfers anyway because it rotates nothing (REQ-UI-BLUEPRINT-TRANSFER).
//
// A splitter, because the question only arises for a footprint that survives
// rotation. A miner's body is L-shaped ("AA" / "A>"), so a rotated miner ghost covers
// different tiles and coincides with nothing at all -- invalid for a reason that has
// nothing to do with these rules.
PlacementFixture f;
const BuildingId id =
f.bs.place(f.state, BuildingType::Splitter, QPoint(-1, 0), Rotation::East, 0).value();
CHECK(resolveInConstellation(f, BuildingType::Splitter, QPoint(-1, 0), Rotation::North).action
== BlueprintGhostAction::Invalid);
const BlueprintGhostResolved alone =
resolveOne(f, BuildingType::Splitter, QPoint(-1, 0), Rotation::North);
REQUIRE(alone.action == BlueprintGhostAction::Transfer);
CHECK(*alone.targetId == id);
}
TEST_CASE("resolveBlueprintGhost: a constellation mixes transfers and plain overlaps",
"[blueprint]")
{
// One drop can reconfigure some of the buildings already there while leaving others
// alone: the split is by whether the type has settings at all, not by blueprint size
// (REQ-UI-BLUEPRINT-OVERLAP).
PlacementFixture f;
const BuildingId minerId =
f.bs.place(f.state, BuildingType::Miner, QPoint(-2, 0), Rotation::East, 0).value();
const BuildingId smelterId =
f.bs.place(f.state, BuildingType::Smelter, QPoint(-5, 0), Rotation::East, 0).value();
const BlueprintGhostResolved miner =
resolveInConstellation(f, BuildingType::Miner, QPoint(-2, 0), Rotation::East);
REQUIRE(miner.action == BlueprintGhostAction::Transfer);
CHECK(*miner.targetId == minerId);
// A smelter runs an implicit recipe (REQ-BLD-SMELTER), so there is nothing to hand
// over and it is simply left as it is.
const BlueprintGhostResolved smelter =
resolveInConstellation(f, BuildingType::Smelter, QPoint(-5, 0), Rotation::East);
REQUIRE(smelter.action == BlueprintGhostAction::CompatibleOverlap);
CHECK(*smelter.targetId == smelterId);
}
TEST_CASE("resolveBlueprintGhost: an identical tunnel is a compatible overlap", "[blueprint]")