re-cover copy-settings through single-building blueprints

This commit is contained in:
2026-08-06 19:44:55 +02:00
parent 9a3b6c10d6
commit 08d8b0dd90
13 changed files with 542 additions and 65 deletions

View File

@@ -928,7 +928,8 @@ void WorldRenderer::drawOverlays(QPainter& painter, const WorldCoordinates& coor
const BeltPathTile& entry = frame.buildMode.getBeltDragPath()[index];
drawBuildingGhost(painter, coordinates, BuildingType::Belt,
entry.tile, entry.rotation,
/*valid*/ item.action != BeltTileAction::Invalid,
item.action != BeltTileAction::Invalid
? GhostTint::Normal : GhostTint::Invalid,
/*showPortTargetGlyphs*/ true);
}
}
@@ -960,7 +961,8 @@ void WorldRenderer::drawOverlays(QPainter& painter, const WorldCoordinates& coor
drawBuildingGhost(painter, coordinates,
frame.buildMode.getEffectiveBuilderType(),
ghostTile, frame.buildMode.getGhostRotation(),
frame.buildMode.isGhostValid(),
frame.buildMode.isGhostValid()
? GhostTint::Normal : GhostTint::Invalid,
/*showPortTargetGlyphs*/ true);
}
}
@@ -968,15 +970,34 @@ void WorldRenderer::drawOverlays(QPainter& painter, const WorldCoordinates& coor
// Blueprint placement ghost
if (frame.buildMode.isBlueprintMode())
{
// The stored building count, not the count after locked types are dropped, so the
// transfer rule does not shift as the player unlocks things
// (REQ-UI-BLUEPRINT-TRANSFER).
const bool holdsOneBuilding =
frame.buildMode.getBlueprint().buildings.size() == 1;
for (const BlueprintBuilding& bb : frame.buildMode.getBlueprint().buildings)
{
// Locked building types are omitted from the blueprint (REQ-LOCK-BUILDING,
// REQ-LOCK-UI-BLUEPRINT), so they are not ghosted either.
if (!m_sim.isBuildingUnlocked(bb.type)) { continue; }
const QPoint anchor = frame.buildMode.getBlueprintGhostTile() + bb.offset;
const bool valid = canPlaceBuilding(m_sim.getFactoryState(), m_sim.getConfig(), bb.type, anchor, bb.rotation);
// The same classifier the click path uses, so the color always predicts what
// clicking would do (REQ-UI-BLUEPRINT-OVERLAP, REQ-UI-BLUEPRINT-TRANSFER). A
// compatible overlap is an ordinary valid ghost.
const BlueprintGhostResolved resolved = resolveBlueprintGhost(
m_sim.getFactoryState(), m_sim.getConfig(), bb.type, anchor, bb.rotation,
holdsOneBuilding);
GhostTint tint = GhostTint::Normal;
if (resolved.action == BlueprintGhostAction::Transfer)
{
tint = GhostTint::Transfer;
}
else if (resolved.action == BlueprintGhostAction::Invalid)
{
tint = GhostTint::Invalid;
}
drawBuildingGhost(painter, coordinates, bb.type, anchor, bb.rotation,
valid, /*showPortTargetGlyphs*/ false);
tint, /*showPortTargetGlyphs*/ false);
}
}
@@ -1048,7 +1069,7 @@ void WorldRenderer::drawBuildingGhost(QPainter& painter,
const WorldCoordinates& coordinates,
BuildingType type,
QPoint anchorTile, Rotation rotation,
bool valid, bool showPortTargetGlyphs)
GhostTint tint, bool showPortTargetGlyphs)
{
const BuildingDef* def = m_sim.getConfig().buildings.findBuildingDef(type);
if (!def) { return; }
@@ -1058,15 +1079,18 @@ void WorldRenderer::drawBuildingGhost(QPainter& painter,
if (it == m_visuals.buildings.end()) { return; }
const BuildingVisuals& bv = it->second;
// Valid ghosts show the building type's own colors; invalid ghosts override
// with the distinct invalid color (REQ-BLD-GHOST, REQ-BLD-PLACE-VALID). The
// invalid color's RGB is taken at full opacity so it does not double-dim
// against the setOpacity below (the configured color carries its own alpha).
const QColor invalidColor(m_visuals.overlays.ghostInvalid.red(),
m_visuals.overlays.ghostInvalid.green(),
m_visuals.overlays.ghostInvalid.blue());
const QColor fillColor = valid ? bv.fill : invalidColor;
const QColor lineColor = valid ? bv.outline : invalidColor;
// Normal ghosts show the building type's own colors; the other two tints override
// them with a single flat color -- invalid (REQ-BLD-GHOST, REQ-BLD-PLACE-VALID) or
// configuration transfer (REQ-UI-BLUEPRINT-TRANSFER). An override's RGB is taken at
// full opacity so it does not double-dim against the setOpacity below (the
// configured color carries its own alpha).
const QColor& configured = tint == GhostTint::Transfer
? m_visuals.overlays.configTransfer
: m_visuals.overlays.ghostInvalid;
const QColor overrideColor(configured.red(), configured.green(), configured.blue());
const bool useOwnColors = tint == GhostTint::Normal;
const QColor fillColor = useOwnColors ? bv.fill : overrideColor;
const QColor lineColor = useOwnColors ? bv.outline : overrideColor;
const ParsedSurfaceMask parsed = parseSurfaceMask(def->surfaceMask, rotation);
if (parsed.bodyCells.empty()) { return; }