move two placement queries out of the view into PlacementRules
This commit is contained in:
@@ -563,36 +563,11 @@ ScrollBounds GameWorldView::getScrollBounds() const
|
||||
// Placement helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
bool GameWorldView::isValidPlacement(BuildingType type, QPoint anchor,
|
||||
Rotation rot) const
|
||||
bool GameWorldView::canPlaceBuildingHere(BuildingType type, QPoint anchor,
|
||||
Rotation rot) const
|
||||
{
|
||||
// Terrain and world-bounds validity are owned by the simulation
|
||||
// (REQ-BLD-PLACE-VALID); the presentation layer only adds the occupancy /
|
||||
// rotate-in-place check.
|
||||
if (!isPlacementValid(m_sim->getFactoryState(), m_sim->getConfig(), type, anchor, rot))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const BuildingDef* def = m_config->buildings.findBuildingDef(type);
|
||||
if (!def) { return false; }
|
||||
const ParsedSurfaceMask parsed = parseSurfaceMask(def->surfaceMask, rot);
|
||||
|
||||
bool anyOccupied = false;
|
||||
for (const QPoint& relCell : parsed.bodyCells)
|
||||
{
|
||||
if (isTileOccupied(m_sim->getFactoryState(), anchor + relCell))
|
||||
{
|
||||
anyOccupied = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (anyOccupied)
|
||||
{
|
||||
return findRotateInPlaceTarget(m_sim->getFactoryState(), m_sim->getConfig(), type, anchor, rot).has_value();
|
||||
}
|
||||
return true;
|
||||
return canPlaceBuilding(m_sim->getFactoryState(), m_sim->getConfig(),
|
||||
type, anchor, rot);
|
||||
}
|
||||
|
||||
std::optional<BuildingId> GameWorldView::buildingAtTile(QPoint tile) const
|
||||
@@ -736,7 +711,7 @@ void GameWorldView::placeBlueprintAtTile(QPoint center)
|
||||
// Locked building types are excluded from this placement entirely
|
||||
// (REQ-LOCK-BUILDING, REQ-LOCK-UI-BLUEPRINT): not validity-checked here.
|
||||
if (!m_sim->isBuildingUnlocked(bb.type)) { continue; }
|
||||
if (!isValidPlacement(bb.type, center + bb.offset, bb.rotation)) { return; }
|
||||
if (!canPlaceBuildingHere(bb.type, center + bb.offset, bb.rotation)) { return; }
|
||||
}
|
||||
|
||||
// Cost only applies to buildings that are genuinely new (not rotate-in-place),
|
||||
@@ -878,7 +853,7 @@ void GameWorldView::placeAtTile(QPoint tile)
|
||||
const BuildingType type = m_buildMode.getEffectiveBuilderType();
|
||||
const Rotation rotation = m_buildMode.getGhostRotation();
|
||||
|
||||
if (!isValidPlacement(type, tile, rotation))
|
||||
if (!canPlaceBuildingHere(type, tile, rotation))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -980,46 +955,11 @@ void GameWorldView::recomputeBeltDragPath(QPoint cursorTile)
|
||||
m_buildMode.setBeltDragPath(std::move(path));
|
||||
}
|
||||
|
||||
std::vector<GameWorldView::BeltDragResolved> GameWorldView::resolveBeltDragPath() const
|
||||
std::vector<BeltDragResolved> GameWorldView::resolveBeltDragPath() const
|
||||
{
|
||||
std::vector<BeltDragResolved> resolved;
|
||||
resolved.reserve(m_buildMode.getBeltDragPath().size());
|
||||
|
||||
const BuildingDef* def = m_config->buildings.findBuildingDef(BuildingType::Belt);
|
||||
const int beltCost = (def != nullptr) ? def->cost : 0;
|
||||
const int stock = m_sim->getBuildingBlocksStock();
|
||||
int spent = 0;
|
||||
|
||||
for (const BeltPathTile& entry : m_buildMode.getBeltDragPath())
|
||||
{
|
||||
BeltDragResolved item;
|
||||
const std::optional<BuildingId> rotateTarget =
|
||||
findRotateInPlaceTarget(m_sim->getFactoryState(), m_sim->getConfig(), BuildingType::Belt, entry.tile, entry.rotation);
|
||||
if (rotateTarget.has_value())
|
||||
{
|
||||
// A tile holding only a belt (or belt site) is re-oriented, no cost.
|
||||
item.action = BeltTileAction::RotateInPlace;
|
||||
item.affordable = true;
|
||||
item.rotateId = rotateTarget;
|
||||
}
|
||||
else if (isValidPlacement(BuildingType::Belt, entry.tile, entry.rotation))
|
||||
{
|
||||
// Empty, valid cell: a new belt, subject to cumulative affordability.
|
||||
item.action = BeltTileAction::PlaceNew;
|
||||
item.affordable = (spent + beltCost <= stock);
|
||||
item.rotateId = std::nullopt;
|
||||
if (item.affordable) { spent += beltCost; }
|
||||
}
|
||||
else
|
||||
{
|
||||
// Occupied by a non-belt building/site, or otherwise invalid terrain.
|
||||
item.action = BeltTileAction::Invalid;
|
||||
item.affordable = false;
|
||||
item.rotateId = std::nullopt;
|
||||
}
|
||||
resolved.push_back(item);
|
||||
}
|
||||
return resolved;
|
||||
return ::resolveBeltDragPath(m_buildMode.getBeltDragPath(),
|
||||
m_sim->getFactoryState(), m_sim->getConfig(),
|
||||
m_sim->getBuildingBlocksStock());
|
||||
}
|
||||
|
||||
void GameWorldView::applyBeltDragPath()
|
||||
@@ -1947,7 +1887,7 @@ void GameWorldView::drawOverlays(QPainter& painter, const WorldCoordinates& coor
|
||||
// REQ-LOCK-UI-BLUEPRINT), so they are not ghosted either.
|
||||
if (!m_sim->isBuildingUnlocked(bb.type)) { continue; }
|
||||
const QPoint anchor = m_buildMode.getBlueprintGhostTile() + bb.offset;
|
||||
const bool valid = isValidPlacement(bb.type, anchor, bb.rotation);
|
||||
const bool valid = canPlaceBuildingHere(bb.type, anchor, bb.rotation);
|
||||
drawBuildingGhost(painter, coordinates, bb.type, anchor, bb.rotation,
|
||||
valid, /*showPortTargetGlyphs*/ false);
|
||||
}
|
||||
@@ -2442,7 +2382,7 @@ void GameWorldView::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
m_buildMode.setGhostTile(tile);
|
||||
m_buildMode.setGhostValidity(
|
||||
isValidPlacement(m_buildMode.getBuilderType(), tile,
|
||||
canPlaceBuildingHere(m_buildMode.getBuilderType(), tile,
|
||||
m_buildMode.getGhostRotation()));
|
||||
|
||||
if (m_buildMode.isTunnelMode())
|
||||
@@ -2569,7 +2509,7 @@ void GameWorldView::rotateGhost(bool clockwise)
|
||||
{
|
||||
m_buildMode.rotateGhost(clockwise);
|
||||
m_buildMode.setGhostValidity(
|
||||
isValidPlacement(m_buildMode.getBuilderType(), m_buildMode.getGhostTile(),
|
||||
canPlaceBuildingHere(m_buildMode.getBuilderType(), m_buildMode.getGhostTile(),
|
||||
m_buildMode.getGhostRotation()));
|
||||
// A new facing changes which tunnels the ghost could complete (REQ-BLD-TUNNEL-MODE).
|
||||
if (m_buildMode.isTunnelMode()) { updateTunnelGhost(); }
|
||||
|
||||
Reference in New Issue
Block a user