Files
dota_factory/src/lib/sim/PlacementRules.h

72 lines
3.5 KiB
C++

#pragma once
#include <optional>
#include <vector>
#include <QPoint>
#include "BeltDragPath.h"
#include "BuildingId.h"
#include "BuildingType.h"
#include "FactoryState.h"
#include "GameConfig.h"
#include "Rotation.h"
// Where a building may be placed, and what is already sitting on those tiles.
// Free functions over the factory state and the config — they read no other
// system state, so they do not belong to BuildingSystem.
// True if every body cell lies inside the world: 0 <= y < world.height_tiles and
// x >= the current asteroid left edge (REQ-BLD-PLACE-VALID). Terrain type is not
// checked — see isPlacementValid for the full rule.
bool bodyCellsWithinWorldBounds(const FactoryState& state, const GameConfig& config,
const std::vector<QPoint>& bodyCells, QPoint anchor);
// True if the placement satisfies REQ-BLD-PLACE-VALID terrain and world-bounds
// rules: every ship-dock (S) cell sits in space (x >= 0), every other body (A)
// cell sits on the asteroid (x < 0 and x >= the left edge), and every cell has
// 0 <= y < world.height_tiles. There is no right-side bound — space extends
// rightward. Tile occupancy is NOT checked here.
bool isPlacementValid(const FactoryState& state, const GameConfig& config,
BuildingType type, QPoint anchor, Rotation rotation);
// The building or site that a ghost of the given type/anchor/rotation would
// rotate in place rather than replace: same type, same body cells, one owner
// (REQ-BLD-ROTATE-IN-PLACE). Tunnels never qualify.
std::optional<BuildingId> findRotateInPlaceTarget(const FactoryState& state,
const GameConfig& config,
BuildingType type, QPoint anchor,
Rotation rot);
// True if placing here would actually do something: the terrain and bounds rules of
// isPlacementValid hold, and the body cells are either all free or occupied only by
// a building this placement would rotate in place. This is the question the ghost
// asks to colour itself and the click path asks before enqueuing a command
// (REQ-BLD-GHOST, REQ-BLD-PLACE-VALID, REQ-BLD-ROTATE-IN-PLACE).
bool canPlaceBuilding(const FactoryState& state, const GameConfig& config,
BuildingType type, QPoint anchor, Rotation rotation);
// What a belt drag would do to one tile of its path (REQ-BLD-BELT-DRAG).
enum class BeltTileAction
{
PlaceNew, // empty, valid cell: a new belt, subject to affordability
RotateInPlace, // already a belt (or belt site): re-oriented, free
Invalid // occupied by something else, or invalid terrain
};
struct BeltDragResolved
{
BeltTileAction action;
bool affordable; // meaningful only for PlaceNew
std::optional<BuildingId> rotateId; // set only for RotateInPlace
};
// Classifies every tile of a belt drag path against the current factory state,
// spending `buildingBlocksStock` cumulatively across the PlaceNew tiles so a path
// longer than the player can afford is only partly buildable (REQ-BLD-BELT-DRAG).
// Shared so the previewed ghosts and the placement on release cannot disagree.
std::vector<BeltDragResolved> resolveBeltDragPath(const std::vector<BeltPathTile>& path,
const FactoryState& state,
const GameConfig& config,
int buildingBlocksStock);