Rename Demolish to Deconstruct
This commit is contained in:
@@ -335,7 +335,7 @@ salvage_color = "#33ccff"
|
|||||||
width_px = 2
|
width_px = 2
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# Build / demolish / selection overlays
|
# Build / deconstruct / selection overlays
|
||||||
#
|
#
|
||||||
# All overlay colors carry an alpha channel so they composite over the
|
# All overlay colors carry an alpha channel so they composite over the
|
||||||
# underlying scene.
|
# underlying scene.
|
||||||
@@ -344,7 +344,7 @@ width_px = 2
|
|||||||
[overlays]
|
[overlays]
|
||||||
ghost_valid = "#ffffff44" # builder-mode ghost, placement allowed (REQ-BLD-GHOST)
|
ghost_valid = "#ffffff44" # builder-mode ghost, placement allowed (REQ-BLD-GHOST)
|
||||||
ghost_invalid = "#ff000044" # builder-mode ghost, placement invalid (REQ-BLD-PLACE-VALID)
|
ghost_invalid = "#ff000044" # builder-mode ghost, placement invalid (REQ-BLD-PLACE-VALID)
|
||||||
demolish_tint = "#ff000033" # demolish-mode hover tint
|
deconstruct_tint = "#ff000033" # deconstruct-mode hover tint
|
||||||
selection_rect = "#00ff00" # box-drag selection rectangle (REQ-UI-MULTI-SELECT)
|
selection_rect = "#00ff00" # box-drag selection rectangle (REQ-UI-MULTI-SELECT)
|
||||||
tile_highlight = "#ffffff22" # tile under cursor
|
tile_highlight = "#ffffff22" # tile under cursor
|
||||||
selected_outline = "#ffff00" # outline drawn around currently-selected building(s)
|
selected_outline = "#ffff00" # outline drawn around currently-selected building(s)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ This document captures the architectural decisions for the project. It is a comp
|
|||||||
A strict separation between the game simulation and the Qt Widgets UI.
|
A strict separation between the game simulation and the Qt Widgets UI.
|
||||||
|
|
||||||
- The **simulation** is a pure C++ library that depends only on Qt Core and Qt Gui (QPoint, QVector2D, QRect, etc., as required by the coding guidelines), toml++, and tinyexpr. It contains no QtWidgets, no painting, and no QApplication. Note: in Qt 5, vector math types such as QVector2D live in Qt::Gui rather than Qt::Core, so the lib links both.
|
- The **simulation** is a pure C++ library that depends only on Qt Core and Qt Gui (QPoint, QVector2D, QRect, etc., as required by the coding guidelines), toml++, and tinyexpr. It contains no QtWidgets, no painting, and no QApplication. Note: in Qt 5, vector math types such as QVector2D live in Qt::Gui rather than Qt::Core, so the lib links both.
|
||||||
- The **UI** reads simulation state and renders it. It owns all widgets, painting, and input handling, and drives the simulation via a small command interface (place building, demolish, clear belt tiles, change recipe, set game speed, etc.).
|
- The **UI** reads simulation state and renders it. It owns all widgets, painting, and input handling, and drives the simulation via a small command interface (place building, deconstruct, clear belt tiles, change recipe, set game speed, etc.).
|
||||||
|
|
||||||
This split is enforced at the CMake target level (see below). Tests link only against the simulation library and run without a display server.
|
This split is enforced at the CMake target level (see below). Tests link only against the simulation library and run without a display server.
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ Schematic drops: when an enemy station set is destroyed, the simulation generate
|
|||||||
|
|
||||||
### UI Events
|
### UI Events
|
||||||
|
|
||||||
All UI interactions — building selection, builder/blueprint mode transitions, speed changes, demolish mode, escape menu, layout dialog requests — are communicated via EventManager events rather than Qt signals/slots. Each event is a small struct inheriting `Event` (e.g., `SelectionChangedEvent`, `BuildingTypeSelectedEvent`, `SpeedChangeRequestedEvent`). Widgets register as `CombinedEventHandler` for the events they care about and emit events via `EventManager::sendEventImmediately()`.
|
All UI interactions — building selection, builder/blueprint mode transitions, speed changes, deconstruct mode, escape menu, layout dialog requests — are communicated via EventManager events rather than Qt signals/slots. Each event is a small struct inheriting `Event` (e.g., `SelectionChangedEvent`, `BuildingTypeSelectedEvent`, `SpeedChangeRequestedEvent`). Widgets register as `CombinedEventHandler` for the events they care about and emit events via `EventManager::sendEventImmediately()`.
|
||||||
|
|
||||||
Bidirectional interactions use separate request/notification event types to avoid infinite recursion (e.g., `ExitBuilderModeRequestedEvent` from `BuildButtonGrid` → `GameWorldView`, vs. `BuilderModeExitedEvent` from `GameWorldView` → `BuildButtonGrid`).
|
Bidirectional interactions use separate request/notification event types to avoid infinite recursion (e.g., `ExitBuilderModeRequestedEvent` from `BuildButtonGrid` → `GameWorldView`, vs. `BuilderModeExitedEvent` from `GameWorldView` → `BuildButtonGrid`).
|
||||||
|
|
||||||
@@ -325,7 +325,7 @@ Sim and UI run on the same thread for v1. `paintEvent` reads sim state directly
|
|||||||
4. **Scrap** — glyphs at world positions.
|
4. **Scrap** — glyphs at world positions.
|
||||||
5. **Ships** — colored arrows oriented by velocity; color keyed to role (player combat / salvage / repair / enemy).
|
5. **Ships** — colored arrows oriented by velocity; color keyed to role (player combat / salvage / repair / enemy).
|
||||||
6. **Laser beams** — lines derived from live `BeamFiredEvent`s kept by the renderer for 0.3 s, colored per `BeamKind` (weapon/repair/salvage) (REQ-SHP-FIRING-BEAM).
|
6. **Laser beams** — lines derived from live `BeamFiredEvent`s kept by the renderer for 0.3 s, colored per `BeamKind` (weapon/repair/salvage) (REQ-SHP-FIRING-BEAM).
|
||||||
7. **Build overlays** — ghost in builder mode (REQ-BLD-GHOST), demolish-mode tint, tile highlight under cursor, box-drag selection rectangle.
|
7. **Build overlays** — ghost in builder mode (REQ-BLD-GHOST), deconstruct-mode tint, tile highlight under cursor, box-drag selection rectangle.
|
||||||
8. **Screen-space UI** — screen-anchored elements, drawn after resetting the world-space transform.
|
8. **Screen-space UI** — screen-anchored elements, drawn after resetting the world-space transform.
|
||||||
|
|
||||||
### Coordinates and Scrolling
|
### Coordinates and Scrolling
|
||||||
@@ -372,7 +372,7 @@ width_px = 2
|
|||||||
[overlays]
|
[overlays]
|
||||||
ghost_valid = "#ffffff44"
|
ghost_valid = "#ffffff44"
|
||||||
ghost_invalid = "#ff000044"
|
ghost_invalid = "#ff000044"
|
||||||
demolish_tint = "#ff000033"
|
deconstruct_tint = "#ff000033"
|
||||||
selection_rect = "#00ff00"
|
selection_rect = "#00ff00"
|
||||||
|
|
||||||
[toast]
|
[toast]
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ data, not the UI gesture. Example: placing a miner records
|
|||||||
One command per sim-mutating operation (the complete mutation surface):
|
One command per sim-mutating operation (the complete mutation surface):
|
||||||
|
|
||||||
- `PlaceBuilding`
|
- `PlaceBuilding`
|
||||||
- `Demolish`
|
- `Deconstruct`
|
||||||
- `RotateInPlace`
|
- `RotateInPlace`
|
||||||
- `SetRecipe`
|
- `SetRecipe`
|
||||||
- `SetShipLayout`
|
- `SetShipLayout`
|
||||||
@@ -125,7 +125,7 @@ the only way production code can reach them is `apply(command)`.
|
|||||||
> `BeltSystem` directly, and every production `buildings()`/`belts()` call is a const query.
|
> `BeltSystem` directly, and every production `buildings()`/`belts()` call is a const query.
|
||||||
> So:
|
> So:
|
||||||
>
|
>
|
||||||
> - `Simulation::tryPlaceBuilding`, `demolish`, and `applySchematicChoice` are **private**.
|
> - `Simulation::tryPlaceBuilding`, `deconstruct`, and `applySchematicChoice` are **private**.
|
||||||
> - The mutable subsystem accessors are private and renamed `buildingsMutable()` /
|
> - The mutable subsystem accessors are private and renamed `buildingsMutable()` /
|
||||||
> `beltsMutable()`; only `const BuildingSystem& buildings() const` / `belts() const` are
|
> `beltsMutable()`; only `const BuildingSystem& buildings() const` / `belts() const` are
|
||||||
> public (queries). UI query sites bind to the const overload unchanged.
|
> public (queries). UI query sites bind to the const overload unchanged.
|
||||||
@@ -377,7 +377,7 @@ The whole feature rests on a deterministic sim, so prove that before building on
|
|||||||
|
|
||||||
Reshape mutations to flow through one path; behaviour unchanged.
|
Reshape mutations to flow through one path; behaviour unchanged.
|
||||||
|
|
||||||
- Defined `Command` base + derived types (`PlaceBuilding`, `Demolish`, `RotateInPlace`,
|
- Defined `Command` base + derived types (`PlaceBuilding`, `Deconstruct`, `RotateInPlace`,
|
||||||
`SetRecipe`, `SetShipLayout`, `SetSiteSplitterFilters`, `SetSplitterFilters`,
|
`SetRecipe`, `SetShipLayout`, `SetSiteSplitterFilters`, `SetSplitterFilters`,
|
||||||
`ClearBeltTiles`, `ApplySchematicChoice`, `Reset`) in `lib`, each with a `playerId` (always 0
|
`ClearBeltTiles`, `ApplySchematicChoice`, `Reset`) in `lib`, each with a `playerId` (always 0
|
||||||
now). `PlaceBuilding` is atomic (carries optional config — see the refinement note above).
|
now). `PlaceBuilding` is atomic (carries optional config — see the refinement note above).
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ Any ship, module, building, or assembler recipe id that appears in no unlock gro
|
|||||||
- REQ-BLD-ROTATE: While in builder mode, pressing Shift+R rotates the ghost 90° clockwise and R rotates it 90° counter-clockwise. Rotation affects the direction of the output port.
|
- REQ-BLD-ROTATE: While in builder mode, pressing Shift+R rotates the ghost 90° clockwise and R rotates it 90° counter-clockwise. Rotation affects the direction of the output port.
|
||||||
- REQ-BLD-PLACE: Clicking a valid tile in builder mode places a construction site and adds it to the build queue, consuming building blocks from the global stock. (For belts, placement is instead deferred to a drag gesture and happens on mouse release — REQ-BLD-BELT-DRAG.)
|
- REQ-BLD-PLACE: Clicking a valid tile in builder mode places a construction site and adds it to the build queue, consuming building blocks from the global stock. (For belts, placement is instead deferred to a drag gesture and happens on mouse release — REQ-BLD-BELT-DRAG.)
|
||||||
- REQ-BLD-PLACE-VALID: A placement position is valid only if (a) every footprint cell in the rotated `surface_mask` is satisfied by the underlying terrain — `A` cells coincide with asteroid tiles, `S` cells coincide with space tiles — (b) no footprint cell overlaps an existing placed building or construction site, except as allowed by REQ-BLD-ROTATE-IN-PLACE, and (c) the player has enough building blocks to afford the building. The ghost (REQ-BLD-GHOST) is rendered in a distinct "invalid" color — overriding its per-building coloring (REQ-BLD-GHOST) — when the current cursor position fails any of these conditions.
|
- REQ-BLD-PLACE-VALID: A placement position is valid only if (a) every footprint cell in the rotated `surface_mask` is satisfied by the underlying terrain — `A` cells coincide with asteroid tiles, `S` cells coincide with space tiles — (b) no footprint cell overlaps an existing placed building or construction site, except as allowed by REQ-BLD-ROTATE-IN-PLACE, and (c) the player has enough building blocks to afford the building. The ghost (REQ-BLD-GHOST) is rendered in a distinct "invalid" color — overriding its per-building coloring (REQ-BLD-GHOST) — when the current cursor position fails any of these conditions.
|
||||||
- REQ-BLD-ROTATE-IN-PLACE: If the ghost's footprint exactly coincides with the footprint of an existing placed building or construction site of the same building type, clicking places no new construction site and consumes no building blocks. Instead, the existing building or site is rotated to match the ghost's rotation. If the target is a construction site, its construction progress is preserved. **Exception:** Tunnel Entries and Tunnel Exits are never rotated in place — re-orienting a tunnel requires demolishing and re-placing it (REQ-BLD-TUNNEL-MODE). A tunnel ghost whose footprint coincides with an existing tunnel is therefore treated as an ordinary occupied-tile placement (invalid in normal builder mode; skipped in blueprint placement mode). This applies in both normal builder mode and blueprint placement mode; in blueprint placement mode it is evaluated per building in the blueprint independently — buildings in the blueprint whose footprint coincides with an existing same-type building or site are rotated in place, while the remaining buildings in the blueprint are placed as normal construction sites (subject to the usual validity checks and total cost).
|
- REQ-BLD-ROTATE-IN-PLACE: If the ghost's footprint exactly coincides with the footprint of an existing placed building or construction site of the same building type, clicking places no new construction site and consumes no building blocks. Instead, the existing building or site is rotated to match the ghost's rotation. If the target is a construction site, its construction progress is preserved. **Exception:** Tunnel Entries and Tunnel Exits are never rotated in place — re-orienting a tunnel requires deconstructing and re-placing it (REQ-BLD-TUNNEL-MODE). A tunnel ghost whose footprint coincides with an existing tunnel is therefore treated as an ordinary occupied-tile placement (invalid in normal builder mode; skipped in blueprint placement mode). This applies in both normal builder mode and blueprint placement mode; in blueprint placement mode it is evaluated per building in the blueprint independently — buildings in the blueprint whose footprint coincides with an existing same-type building or site are rotated in place, while the remaining buildings in the blueprint are placed as normal construction sites (subject to the usual validity checks and total cost).
|
||||||
- REQ-BLD-BELT-DRAG: **Belt drag placement.** For belts, placement is a deferred drag gesture rather than immediate per-tile placement: construction sites are not placed while the cursor hovers new tiles, but only once the player releases the left mouse button. Pressing the left mouse button in the game world while in belt builder mode starts a drag anchored at the tile under the cursor. As the cursor moves, a **rectilinear (L-shaped) path** of belt tiles is computed from the anchor tile to the tile under the cursor: the path first runs along the axis **parallel to the belt's current orientation** (REQ-BLD-ROTATE) — stepping toward the cursor's coordinate on that axis to a corner tile — and then runs along the orthogonal axis to the cursor tile. When the cursor shares the anchor's row or column the path degenerates to a straight line, and when it is on the anchor tile the path is a single tile.
|
- REQ-BLD-BELT-DRAG: **Belt drag placement.** For belts, placement is a deferred drag gesture rather than immediate per-tile placement: construction sites are not placed while the cursor hovers new tiles, but only once the player releases the left mouse button. Pressing the left mouse button in the game world while in belt builder mode starts a drag anchored at the tile under the cursor. As the cursor moves, a **rectilinear (L-shaped) path** of belt tiles is computed from the anchor tile to the tile under the cursor: the path first runs along the axis **parallel to the belt's current orientation** (REQ-BLD-ROTATE) — stepping toward the cursor's coordinate on that axis to a corner tile — and then runs along the orthogonal axis to the cursor tile. When the cursor shares the anchor's row or column the path degenerates to a straight line, and when it is on the anchor tile the path is a single tile.
|
||||||
- **Snapping to a building.** When the tile under the cursor is occupied by a non-belt building or construction site (the **target**), the path does not end on that occupied tile. Instead the end tile is the tile **closest to the cursor** (by distance from the cursor position to the tile) among the tiles orthogonally adjacent to the target across one of its **input-capable edges** — any footprint edge that is not one of the target's output ports, i.e. an edge on which the target can accept an incoming item (REQ-MAT-INPUT-PORTS for buildings, REQ-MAT-ACCEPT-DIR for splitters and tunnels). The geometrically closest such tile is **always** used, even if it turns out not to be a valid belt endpoint — in that case it is previewed and applied by the ordinary rules below (invalid color and skipped if occupied by a non-belt building or invalid terrain; re-oriented if it already holds a belt). The rest of the L-shaped path is computed from the anchor to this end tile exactly as above. The end tile's belt direction points **toward the target** (across the shared input edge), overriding the "final tile keeps its incoming step" rule; this applies whether the end tile is a newly placed belt or an existing belt re-oriented in place, and is reflected both in the ghost preview and in the placement on release.
|
- **Snapping to a building.** When the tile under the cursor is occupied by a non-belt building or construction site (the **target**), the path does not end on that occupied tile. Instead the end tile is the tile **closest to the cursor** (by distance from the cursor position to the tile) among the tiles orthogonally adjacent to the target across one of its **input-capable edges** — any footprint edge that is not one of the target's output ports, i.e. an edge on which the target can accept an incoming item (REQ-MAT-INPUT-PORTS for buildings, REQ-MAT-ACCEPT-DIR for splitters and tunnels). The geometrically closest such tile is **always** used, even if it turns out not to be a valid belt endpoint — in that case it is previewed and applied by the ordinary rules below (invalid color and skipped if occupied by a non-belt building or invalid terrain; re-oriented if it already holds a belt). The rest of the L-shaped path is computed from the anchor to this end tile exactly as above. The end tile's belt direction points **toward the target** (across the shared input edge), overriding the "final tile keeps its incoming step" rule; this applies whether the end tile is a newly placed belt or an existing belt re-oriented in place, and is reflected both in the ghost preview and in the placement on release.
|
||||||
- **Rotating during the drag.** Rotating the belt with R / Shift+R (REQ-BLD-ROTATE) while a drag is in progress re-picks the path's primary axis immediately from the new orientation and re-derives the whole path from the anchor to the current cursor tile, without waiting for the next cursor movement.
|
- **Rotating during the drag.** Rotating the belt with R / Shift+R (REQ-BLD-ROTATE) while a drag is in progress re-picks the path's primary axis immediately from the new orientation and re-derives the whole path from the anchor to the current cursor tile, without waiting for the next cursor movement.
|
||||||
@@ -142,12 +142,12 @@ Any ship, module, building, or assembler recipe id that appears in no unlock gro
|
|||||||
- **Resolving the type.** If neither match exists, the ghost is a Tunnel Entry (the default). If only one kind of match exists, the ghost is the kind that produces it (Tunnel Exit for an exit-completion match, Tunnel Entry for an entry-completion match). If **both** an exit-completion match (an existing Entry) and an entry-completion match (an existing Exit) exist, the mode resolves to the completion whose **existing partner building is closer to the mouse cursor position** — the actual sub-tile cursor position, not the hovered tile's center — and the ghost becomes the corresponding type (a Tunnel Exit to complete the nearer Entry, or a Tunnel Entry to complete the nearer Exit). Because the comparison uses the sub-tile cursor position, when the two partners are at the same tile distance the player can move the cursor within the hovered tile to switch which end is placed. When more than one candidate qualifies on a side, the nearest qualifying partner on that side is used.
|
- **Resolving the type.** If neither match exists, the ghost is a Tunnel Entry (the default). If only one kind of match exists, the ghost is the kind that produces it (Tunnel Exit for an exit-completion match, Tunnel Entry for an entry-completion match). If **both** an exit-completion match (an existing Entry) and an entry-completion match (an existing Exit) exist, the mode resolves to the completion whose **existing partner building is closer to the mouse cursor position** — the actual sub-tile cursor position, not the hovered tile's center — and the ghost becomes the corresponding type (a Tunnel Exit to complete the nearer Entry, or a Tunnel Entry to complete the nearer Exit). Because the comparison uses the sub-tile cursor position, when the two partners are at the same tile distance the player can move the cursor within the hovered tile to switch which end is placed. When more than one candidate qualifies on a side, the nearest qualifying partner on that side is used.
|
||||||
- **Connection preview (green).** Whenever a completion match is resolved, the matched existing partner building is highlighted green, and every tile strictly between that partner and the hovered ghost tile (along the tunnel's straight run) is marked green, previewing the connection that placing the ghost would create.
|
- **Connection preview (green).** Whenever a completion match is resolved, the matched existing partner building is highlighted green, and every tile strictly between that partner and the hovered ghost tile (along the tunnel's straight run) is marked green, previewing the connection that placing the ghost would create.
|
||||||
- **Invalid positions.** The completion tests, type switch, and green preview apply only while the hovered position is a valid placement (REQ-BLD-PLACE-VALID). At an invalid position the ordinary invalid-colored ghost is shown (REQ-BLD-GHOST) with no green preview and no switch away from the default Tunnel Entry.
|
- **Invalid positions.** The completion tests, type switch, and green preview apply only while the hovered position is a valid placement (REQ-BLD-PLACE-VALID). At an invalid position the ordinary invalid-colored ghost is shown (REQ-BLD-GHOST) with no green preview and no switch away from the default Tunnel Entry.
|
||||||
- REQ-BLD-DEMOLISH: The player can demolish a placed factory building. Demolishing a **fully-built** factory building does not remove it instantly: it is added to the deconstruction queue (REQ-BLD-DECON-QUEUE) and, once its deconstruction completes, `world.toml [world].refund_percentage` percent of the original building block cost (default 75%) is returned to the global stock. Exception: if the building is still in the construction queue (not yet fully built, including the one currently being constructed), it is **not** queued for deconstruction but removed instantly from the construction queue, and the **full** building block cost is refunded immediately. The HQ and player defence stations cannot be demolished.
|
- REQ-BLD-DECONSTRUCT: The player can deconstruct a placed factory building. Deconstructing a **fully-built** factory building does not remove it instantly: it is added to the deconstruction queue (REQ-BLD-DECON-QUEUE) and, once its deconstruction completes, `world.toml [world].refund_percentage` percent of the original building block cost (default 75%) is returned to the global stock. Exception: if the building is still in the construction queue (not yet fully built, including the one currently being constructed), it is **not** queued for deconstruction but removed instantly from the construction queue, and the **full** building block cost is refunded immediately. The HQ and player defence stations cannot be deconstructed.
|
||||||
- REQ-BLD-DECON-QUEUE: Fully-built factory buildings marked for demolition (REQ-BLD-DEMOLISH) enter a **deconstruction queue** that is processed one building at a time and runs in parallel with the construction queue (REQ-BLD-QUEUE) — the two queues advance independently and simultaneously. Each building takes `world.toml [world].deconstruction_time_seconds` (default 0.1) to deconstruct, the same duration for every building type. When a building's deconstruction completes it is removed from the world and its refund is credited (REQ-BLD-DEMOLISH). A building **stops operating the moment it enters the queue**: it runs no production and transports no items, and no longer participates as a live building (its tunnel pairing is re-evaluated as if it were gone, REQ-BLD-TUNNEL-PAIR), but it still physically occupies its tiles until removed, so those tiles stay blocked for placement. A queued building can be taken back out of the deconstruction queue before it is removed (REQ-BLD-DEMOLISH-CLICK, REQ-BLD-DEMOLISH-BOX) — including the one currently being deconstructed; doing so discards any deconstruction progress, credits no refund, and the building resumes operating (and re-pairs, REQ-BLD-TUNNEL-PAIR). Construction sites never enter the deconstruction queue (REQ-BLD-DEMOLISH). Every building in the deconstruction queue is rendered with the demolish tint — the `visuals.toml [overlays].demolish_tint` color, the same tint applied to a building hovered in demolish mode (REQ-UI-DEMOLISH-BORDER) — so queued buildings are visually distinct.
|
- REQ-BLD-DECON-QUEUE: Fully-built factory buildings marked for demolition (REQ-BLD-DECONSTRUCT) enter a **deconstruction queue** that is processed one building at a time and runs in parallel with the construction queue (REQ-BLD-QUEUE) — the two queues advance independently and simultaneously. Each building takes `world.toml [world].deconstruction_time_seconds` (default 0.1) to deconstruct, the same duration for every building type. When a building's deconstruction completes it is removed from the world and its refund is credited (REQ-BLD-DECONSTRUCT). A building **stops operating the moment it enters the queue**: it runs no production and transports no items, and no longer participates as a live building (its tunnel pairing is re-evaluated as if it were gone, REQ-BLD-TUNNEL-PAIR), but it still physically occupies its tiles until removed, so those tiles stay blocked for placement. A queued building can be taken back out of the deconstruction queue before it is removed (REQ-BLD-DECONSTRUCT-CLICK, REQ-BLD-DECONSTRUCT-BOX) — including the one currently being deconstructed; doing so discards any deconstruction progress, credits no refund, and the building resumes operating (and re-pairs, REQ-BLD-TUNNEL-PAIR). Construction sites never enter the deconstruction queue (REQ-BLD-DECONSTRUCT). Every building in the deconstruction queue is rendered with the deconstruct tint — the `visuals.toml [overlays].deconstruct_tint` color, the same tint applied to a building hovered in deconstruct mode (REQ-UI-DECONSTRUCT-BORDER) — so queued buildings are visually distinct.
|
||||||
- REQ-BLD-DEMOLISH-CLICK: While in demolish mode (REQ-UI-HOTKEYS, REQ-UI-DEMOLISH-BUTTON), left-clicking a placed factory building or construction site in the game world marks it for demolition, following the rules of REQ-BLD-DEMOLISH: a fully-built building is added to the deconstruction queue (REQ-BLD-DECON-QUEUE), and a construction site is removed instantly with the full refund. Left-clicking a fully-built building that is **already in the deconstruction queue** instead removes it from the queue (un-queues it, REQ-BLD-DECON-QUEUE), with no refund; repeated clicks on the same building therefore alternate between queueing and un-queueing it. Clicking a building that cannot be demolished (the HQ or a player defence station, per REQ-BLD-DEMOLISH), or clicking empty world space, has no effect. Demolish mode stays active after each action so the player can continue without re-entering the mode; it is exited via the Q toggle (REQ-UI-HOTKEYS) or the Demolish button (REQ-UI-DEMOLISH-BUTTON).
|
- REQ-BLD-DECONSTRUCT-CLICK: While in deconstruct mode (REQ-UI-HOTKEYS, REQ-UI-DECONSTRUCT-BUTTON), left-clicking a placed factory building or construction site in the game world marks it for demolition, following the rules of REQ-BLD-DECONSTRUCT: a fully-built building is added to the deconstruction queue (REQ-BLD-DECON-QUEUE), and a construction site is removed instantly with the full refund. Left-clicking a fully-built building that is **already in the deconstruction queue** instead removes it from the queue (un-queues it, REQ-BLD-DECON-QUEUE), with no refund; repeated clicks on the same building therefore alternate between queueing and un-queueing it. Clicking a building that cannot be deconstructed (the HQ or a player defence station, per REQ-BLD-DECONSTRUCT), or clicking empty world space, has no effect. Deconstruct mode stays active after each action so the player can continue without re-entering the mode; it is exited via the Q toggle (REQ-UI-HOTKEYS) or the Deconstruct button (REQ-UI-DECONSTRUCT-BUTTON).
|
||||||
- REQ-BLD-DEMOLISH-BOX: While in demolish mode (REQ-UI-HOTKEYS, REQ-UI-DEMOLISH-BUTTON), the player can click and drag a selection box in the game world. A selection rectangle is drawn while dragging, using the same box-drag gesture and coverage semantics as the multi-select box (REQ-UI-MULTI-SELECT). On mouse up, following the rules of REQ-BLD-DEMOLISH: every construction site covered by the box is removed instantly with the full refund; and among the fully-built demolishable buildings covered by the box, if **all** of them are already in the deconstruction queue they are all removed from it (un-queued, REQ-BLD-DECON-QUEUE), otherwise every covered building not yet in the queue is added to the deconstruction queue (already-queued ones stay). Buildings that cannot be demolished (the HQ and player defence stations, per REQ-BLD-DEMOLISH) are excluded from the box demolition; ships and defence stations are never affected.
|
- REQ-BLD-DECONSTRUCT-BOX: While in deconstruct mode (REQ-UI-HOTKEYS, REQ-UI-DECONSTRUCT-BUTTON), the player can click and drag a selection box in the game world. A selection rectangle is drawn while dragging, using the same box-drag gesture and coverage semantics as the multi-select box (REQ-UI-MULTI-SELECT). On mouse up, following the rules of REQ-BLD-DECONSTRUCT: every construction site covered by the box is removed instantly with the full refund; and among the fully-built deconstructible buildings covered by the box, if **all** of them are already in the deconstruction queue they are all removed from it (un-queued, REQ-BLD-DECON-QUEUE), otherwise every covered building not yet in the queue is added to the deconstruction queue (already-queued ones stay). Buildings that cannot be deconstructed (the HQ and player defence stations, per REQ-BLD-DECONSTRUCT) are excluded from the box demolition; ships and defence stations are never affected.
|
||||||
- REQ-BLD-SITE-CONFIG: A construction site — a building that has been placed but is still queued or under construction (REQ-BLD-QUEUE) — can be selected and configured exactly like the equivalent operational building, before it finishes building. Whatever configuration the building type supports is available on the site: the recipe for a Miner or Assembler (REQ-UI-SELECT-BUTTON), the produced-ship schematic and its module layout for a Shipyard (REQ-UI-SELECT-BUTTON, REQ-MOD-UI-PREVIEW, REQ-MOD-UI-DIALOG), and the output filters for a Splitter (REQ-BLD-SPLITTER) — all set through the same Selected Building Panel controls (REQ-UI-CONFIG-INLINE). Only currently unlocked recipes and schematics are offered, exactly as for operational buildings (REQ-LOCK-UI-RECIPE, REQ-LOCK-UI-SCHEMATIC, REQ-LOCK-UI-SPLITTER). The configuration is stored on the construction site and carries over unchanged when construction completes, so the building becomes operational already configured. A construction site has no input/output buffers and runs no production cycle, so the buffer and production-progress portions of the panel (REQ-UI-SINGLE-SELECTION, REQ-UI-PRODUCTION-PROGRESS) are not shown for it; only its construction progress (REQ-UI-CONSTRUCTION-PROGRESS) and its configuration controls appear. (Blueprint placement already applies a stored recipe or schematic to a construction site on placement per REQ-UI-BLUEPRINT-PLACE; this requirement additionally lets the player set or change that configuration directly on an existing site.)
|
- REQ-BLD-SITE-CONFIG: A construction site — a building that has been placed but is still queued or under construction (REQ-BLD-QUEUE) — can be selected and configured exactly like the equivalent operational building, before it finishes building. Whatever configuration the building type supports is available on the site: the recipe for a Miner or Assembler (REQ-UI-SELECT-BUTTON), the produced-ship schematic and its module layout for a Shipyard (REQ-UI-SELECT-BUTTON, REQ-MOD-UI-PREVIEW, REQ-MOD-UI-DIALOG), and the output filters for a Splitter (REQ-BLD-SPLITTER) — all set through the same Selected Building Panel controls (REQ-UI-CONFIG-INLINE). Only currently unlocked recipes and schematics are offered, exactly as for operational buildings (REQ-LOCK-UI-RECIPE, REQ-LOCK-UI-SCHEMATIC, REQ-LOCK-UI-SPLITTER). The configuration is stored on the construction site and carries over unchanged when construction completes, so the building becomes operational already configured. A construction site has no input/output buffers and runs no production cycle, so the buffer and production-progress portions of the panel (REQ-UI-SINGLE-SELECTION, REQ-UI-PRODUCTION-PROGRESS) are not shown for it; only its construction progress (REQ-UI-CONSTRUCTION-PROGRESS) and its configuration controls appear. (Blueprint placement already applies a stored recipe or schematic to a construction site on placement per REQ-UI-BLUEPRINT-PLACE; this requirement additionally lets the player set or change that configuration directly on an existing site.)
|
||||||
- REQ-BLD-COPY-CONFIG: **Copy building settings (hold Shift).** While the Shift key is held, the player can copy one building's settings onto other buildings of the same type, so several identical machines can be set up without opening each one's panel. This gesture is available only in the default selection mode; while a builder, blueprint placement, or demolish mode is active it is disabled, so it never clashes with placement or demolition clicks.
|
- REQ-BLD-COPY-CONFIG: **Copy building settings (hold Shift).** While the Shift key is held, the player can copy one building's settings onto other buildings of the same type, so several identical machines can be set up without opening each one's panel. This gesture is available only in the default selection mode; while a builder, blueprint placement, or deconstruct mode is active it is disabled, so it never clashes with placement or demolition clicks.
|
||||||
- **Shift + right-click** a building copies its current settings into a temporary cache, along with the building's type. The settings copied are whatever that building type supports: the selected recipe (Miner, Assembler), the selected schematic together with its module layout (Shipyard), or the two output filters (Splitter, REQ-BLD-SPLITTER). Copying succeeds only when there is something to copy — a Miner or Assembler with a recipe selected, a Shipyard with a schematic selected, or any Splitter (whose output filters, even when empty/accept-all, always constitute valid settings). Shift + right-clicking a configurable building with nothing yet selected, a building type that has no settings at all (Smelter, Reprocessing Plant, Salvage Bay, belt/tunnel tiles, the HQ), or empty world space, has no effect and leaves any existing cache unchanged.
|
- **Shift + right-click** a building copies its current settings into a temporary cache, along with the building's type. The settings copied are whatever that building type supports: the selected recipe (Miner, Assembler), the selected schematic together with its module layout (Shipyard), or the two output filters (Splitter, REQ-BLD-SPLITTER). Copying succeeds only when there is something to copy — a Miner or Assembler with a recipe selected, a Shipyard with a schematic selected, or any Splitter (whose output filters, even when empty/accept-all, always constitute valid settings). Shift + right-clicking a configurable building with nothing yet selected, a building type that has no settings at all (Smelter, Reprocessing Plant, Salvage Bay, belt/tunnel tiles, the HQ), or empty world space, has no effect and leaves any existing cache unchanged.
|
||||||
- **Shift + left-click** a building of the **same type** as the cached one applies the cached settings to it, exactly as if the player had made that selection through the selected building panel — with the same effects as a normal selection change (buffer clearing per REQ-MAT-INPUT-BUFFER and REQ-MAT-OUTPUT-BUFFER, and, for a Shipyard, in-progress cycle cancellation per REQ-BLD-SHIPYARD). This can be repeated on any number of same-type buildings while Shift stays held. Shift + left-clicking a building of a different type than the cached one, any building while the cache is empty, or empty world space, has no effect.
|
- **Shift + left-click** a building of the **same type** as the cached one applies the cached settings to it, exactly as if the player had made that selection through the selected building panel — with the same effects as a normal selection change (buffer clearing per REQ-MAT-INPUT-BUFFER and REQ-MAT-OUTPUT-BUFFER, and, for a Shipyard, in-progress cycle cancellation per REQ-BLD-SHIPYARD). This can be repeated on any number of same-type buildings while Shift stays held. Shift + left-clicking a building of a different type than the cached one, any building while the cache is empty, or empty world space, has no effect.
|
||||||
- Both operational buildings and construction sites take part as source and target (REQ-BLD-SITE-CONFIG); settings applied to a construction site carry over unchanged when it finishes building.
|
- Both operational buildings and construction sites take part as source and target (REQ-BLD-SITE-CONFIG); settings applied to a construction site carry over unchanged when it finishes building.
|
||||||
@@ -171,12 +171,12 @@ Any ship, module, building, or assembler recipe id that appears in no unlock gro
|
|||||||
- In all alternation cases, if one output is blocked the item goes to the other output until it unblocks.
|
- In all alternation cases, if one output is blocked the item goes to the other output until it unblocks.
|
||||||
- REQ-BLD-TUNNEL-ENTRY: **Tunnel Entry** (1×1): The sending end of a tunnel pair. The player sets a direction (N, S, E, W) at placement, rotatable with R/Shift+R. Items arriving from an adjacent belt tile on a non-output edge (i.e. not the mouth edge in the entry's facing direction — see REQ-MAT-ACCEPT-DIR) whose direction points into the entry are forwarded through the tunnel to the paired Tunnel Exit (see REQ-BLD-TUNNEL-PAIR, REQ-BLD-TUNNEL-TRANSIT). If the entry is unpaired, or if the paired exit's output is blocked, the entry blocks like a full belt tile.
|
- REQ-BLD-TUNNEL-ENTRY: **Tunnel Entry** (1×1): The sending end of a tunnel pair. The player sets a direction (N, S, E, W) at placement, rotatable with R/Shift+R. Items arriving from an adjacent belt tile on a non-output edge (i.e. not the mouth edge in the entry's facing direction — see REQ-MAT-ACCEPT-DIR) whose direction points into the entry are forwarded through the tunnel to the paired Tunnel Exit (see REQ-BLD-TUNNEL-PAIR, REQ-BLD-TUNNEL-TRANSIT). If the entry is unpaired, or if the paired exit's output is blocked, the entry blocks like a full belt tile.
|
||||||
- REQ-BLD-TUNNEL-EXIT: **Tunnel Exit** (1×1): The receiving end of a tunnel pair. The player sets a direction at placement, rotatable with R/Shift+R. Items received from the paired Tunnel Entry emerge from the output side of the exit tile — the tile adjacent in the exit's facing direction — continuing in that direction. If the exit is unpaired or its output is blocked, it holds received items until they can advance.
|
- REQ-BLD-TUNNEL-EXIT: **Tunnel Exit** (1×1): The receiving end of a tunnel pair. The player sets a direction at placement, rotatable with R/Shift+R. Items received from the paired Tunnel Entry emerge from the output side of the exit tile — the tile adjacent in the exit's facing direction — continuing in that direction. If the exit is unpaired or its output is blocked, it holds received items until they can advance.
|
||||||
- REQ-BLD-TUNNEL-PAIR: **Tunnel pairing rules.** Pairing is re-evaluated for all Tunnel Entries whenever any Tunnel Entry or Tunnel Exit is placed, demolished, or enters or leaves the deconstruction queue (REQ-BLD-DECON-QUEUE; a tunnel end that is queued for deconstruction counts as removed for pairing).
|
- REQ-BLD-TUNNEL-PAIR: **Tunnel pairing rules.** Pairing is re-evaluated for all Tunnel Entries whenever any Tunnel Entry or Tunnel Exit is placed, deconstructed, or enters or leaves the deconstruction queue (REQ-BLD-DECON-QUEUE; a tunnel end that is queued for deconstruction counts as removed for pairing).
|
||||||
- A Tunnel Entry searches tile-by-tile in its facing direction for a partner. Any tunnel building (entry or exit) that faces a *different* direction is ignored and skipped. The search stops at the first tunnel building that faces the *same* direction as the searching entry.
|
- A Tunnel Entry searches tile-by-tile in its facing direction for a partner. Any tunnel building (entry or exit) that faces a *different* direction is ignored and skipped. The search stops at the first tunnel building that faces the *same* direction as the searching entry.
|
||||||
- If that first same-direction tunnel building is a Tunnel Exit, is within `tunnel_max_distance` tiles of the entry, and is not already paired with a closer entry, the two form a pair.
|
- If that first same-direction tunnel building is a Tunnel Exit, is within `tunnel_max_distance` tiles of the entry, and is not already paired with a closer entry, the two form a pair.
|
||||||
- Otherwise the entry is unpaired.
|
- Otherwise the entry is unpaired.
|
||||||
- Pairing is one-to-one: each Tunnel Entry pairs with at most one Tunnel Exit, and vice versa. A Tunnel Exit is claimed by the nearest Tunnel Entry that can validly reach it; all other entries for which it would otherwise qualify are unpaired.
|
- Pairing is one-to-one: each Tunnel Entry pairs with at most one Tunnel Exit, and vice versa. A Tunnel Exit is claimed by the nearest Tunnel Entry that can validly reach it; all other entries for which it would otherwise qualify are unpaired.
|
||||||
- When one end of a pair is demolished, the pair is dissolved and any items currently in transit are discarded.
|
- When one end of a pair is deconstructed, the pair is dissolved and any items currently in transit are discarded.
|
||||||
- REQ-BLD-TUNNEL-TRANSIT: **Tunnel transit.** Items inside a tunnel are not rendered (they travel invisibly). Transit time equals the tile-coordinate distance between entry and exit divided by `world.toml [world].belt_speed_tiles_per_second`, matching the time a chain of belt tiles of equivalent length would take. Multiple items may be in transit simultaneously, spaced as they would be on a belt chain of the same length. Clearing a tunnel entry or exit tile (REQ-UI-BELT-CLEAR) also discards all items currently in transit through that tunnel.
|
- REQ-BLD-TUNNEL-TRANSIT: **Tunnel transit.** Items inside a tunnel are not rendered (they travel invisibly). Transit time equals the tile-coordinate distance between entry and exit divided by `world.toml [world].belt_speed_tiles_per_second`, matching the time a chain of belt tiles of equivalent length would take. Multiple items may be in transit simultaneously, spaced as they would be on a belt chain of the same length. Clearing a tunnel entry or exit tile (REQ-UI-BELT-CLEAR) also discards all items currently in transit through that tunnel.
|
||||||
- REQ-BLD-TUNNEL-SELECT-HIGHLIGHT: **Selected-tunnel connection highlight.** While a Tunnel Entry or Tunnel Exit — operational building or construction site — is part of the current selection (single selection or multi-selection, REQ-UI-MULTI-SELECT), its tunnel connection is marked green in the game world, using the same `visuals.toml [overlays].tunnel_preview` green as the placement connection preview (REQ-BLD-TUNNEL-MODE). The matching end is found by applying the pairing scan of REQ-BLD-TUNNEL-PAIR over both built tunnels **and** construction-site tunnels (site-inclusive, matching the placement preview): for a selected entry, the first same-direction tunnel within `tunnel_max_distance` along its facing direction, if it is a Tunnel Exit; for a selected exit, the first same-direction tunnel within `tunnel_max_distance` opposite its facing direction, if it is a Tunnel Entry. When a matching end is found, the entry tile, the exit tile, and every tile strictly between them (along the tunnel's straight run) are marked green. A selected tunnel with no matching end shows no green highlight (it still receives the normal selection outline). In multi-selection each selected tunnel end that has a matching end contributes its connection, and a given connection is shown whenever either of its ends is selected. The highlight is presentation-only and has no effect on the simulation.
|
- REQ-BLD-TUNNEL-SELECT-HIGHLIGHT: **Selected-tunnel connection highlight.** While a Tunnel Entry or Tunnel Exit — operational building or construction site — is part of the current selection (single selection or multi-selection, REQ-UI-MULTI-SELECT), its tunnel connection is marked green in the game world, using the same `visuals.toml [overlays].tunnel_preview` green as the placement connection preview (REQ-BLD-TUNNEL-MODE). The matching end is found by applying the pairing scan of REQ-BLD-TUNNEL-PAIR over both built tunnels **and** construction-site tunnels (site-inclusive, matching the placement preview): for a selected entry, the first same-direction tunnel within `tunnel_max_distance` along its facing direction, if it is a Tunnel Exit; for a selected exit, the first same-direction tunnel within `tunnel_max_distance` opposite its facing direction, if it is a Tunnel Entry. When a matching end is found, the entry tile, the exit tile, and every tile strictly between them (along the tunnel's straight run) are marked green. A selected tunnel with no matching end shows no green highlight (it still receives the normal selection outline). In multi-selection each selected tunnel end that has a matching end contributes its connection, and a given connection is shown whenever either of its ends is selected. The highlight is presentation-only and has no effect on the simulation.
|
||||||
|
|
||||||
@@ -458,7 +458,7 @@ The screen is divided into two columns: a main column (75% width) containing the
|
|||||||
- REQ-UI-BOSS-STATUS: The header bar displays, to the left of the speed buttons, the current boss wave counter (REQ-WAV-BOSS-COUNTER) and the time remaining on the boss countdown (REQ-WAV-BOSS-COUNTDOWN). The boss wave counter is shown as `Boss Wave #<x>` and the countdown as `Next boss: <M:SS>`, where `<M:SS>` is the remaining seconds formatted as whole minutes and two-digit seconds. Both values update continuously as the simulation runs.
|
- REQ-UI-BOSS-STATUS: The header bar displays, to the left of the speed buttons, the current boss wave counter (REQ-WAV-BOSS-COUNTER) and the time remaining on the boss countdown (REQ-WAV-BOSS-COUNTDOWN). The boss wave counter is shown as `Boss Wave #<x>` and the countdown as `Next boss: <M:SS>`, where `<M:SS>` is the remaining seconds formatted as whole minutes and two-digit seconds. Both values update continuously as the simulation runs.
|
||||||
- REQ-UI-SPEED: The game speed controls in the header bar are buttons for 0×, 0.5×, 1×, 2×, and 10× speed. The currently active speed is shown as selected. All game simulation (production, movement, threat accumulation, wave timing) scales with the selected speed. 0× pauses the game.
|
- REQ-UI-SPEED: The game speed controls in the header bar are buttons for 0×, 0.5×, 1×, 2×, and 10× speed. The currently active speed is shown as selected. All game simulation (production, movement, threat accumulation, wave timing) scales with the selected speed. 0× pauses the game.
|
||||||
- REQ-UI-PAUSE-BORDER: While the game is paused (speed 0×, whether set via the speed controls (REQ-UI-SPEED), the Space toggle (REQ-UI-HOTKEYS), or an auto-pausing modal), a vignette border is drawn around the edges of the game world view to make the paused state hard to miss. The border is black and fades in the alpha channel from fully transparent at its inner (center-facing) edge to 50% opacity at the viewport edge, over a thickness of 100 pixels (capped at half the smaller viewport dimension on very small views).
|
- REQ-UI-PAUSE-BORDER: While the game is paused (speed 0×, whether set via the speed controls (REQ-UI-SPEED), the Space toggle (REQ-UI-HOTKEYS), or an auto-pausing modal), a vignette border is drawn around the edges of the game world view to make the paused state hard to miss. The border is black and fades in the alpha channel from fully transparent at its inner (center-facing) edge to 50% opacity at the viewport edge, over a thickness of 100 pixels (capped at half the smaller viewport dimension on very small views).
|
||||||
- REQ-UI-DEMOLISH-BORDER: While demolish mode is active (REQ-UI-DEMOLISH-BUTTON, REQ-UI-HOTKEYS), a vignette border is drawn around the edges of the game world view to signal the mode, matching the geometry of the paused-state vignette (REQ-UI-PAUSE-BORDER): a 100-pixel thickness (capped at half the smaller viewport dimension on very small views) with the four sides meeting along mitred corner diagonals. It fades in the alpha channel from fully transparent at its inner (center-facing) edge to the demolish tint color at the viewport edge. The color — including its alpha, which sets the peak opacity at the viewport edge — is read from `visuals.toml [overlays].demolish_tint`, the same demolish-mode color used for the hover tint. The border is presentation-only and has no effect on the simulation. If the game is both paused and in demolish mode, both vignettes are drawn and compose over each other.
|
- REQ-UI-DECONSTRUCT-BORDER: While deconstruct mode is active (REQ-UI-DECONSTRUCT-BUTTON, REQ-UI-HOTKEYS), a vignette border is drawn around the edges of the game world view to signal the mode, matching the geometry of the paused-state vignette (REQ-UI-PAUSE-BORDER): a 100-pixel thickness (capped at half the smaller viewport dimension on very small views) with the four sides meeting along mitred corner diagonals. It fades in the alpha channel from fully transparent at its inner (center-facing) edge to the deconstruct tint color at the viewport edge. The color — including its alpha, which sets the peak opacity at the viewport edge — is read from `visuals.toml [overlays].deconstruct_tint`, the same deconstruct-mode color used for the hover tint. The border is presentation-only and has no effect on the simulation. If the game is both paused and in deconstruct mode, both vignettes are drawn and compose over each other.
|
||||||
- REQ-UI-EXPAND-BUTTON: The header bar shows an asteroid expansion button captioned `Expand: <x> Blocks`, where `<x>` is the current expansion cost computed from `world.toml [expansion].cost_building_blocks_formula` at the current number of purchased expansions (REQ-EXP-COST). Clicking the button unlocks the next asteroid expansion (REQ-EXP-UNLOCK, REQ-GW-ASTEROID-EXPAND), spending that many building blocks from the global stock. The button is disabled when the player cannot currently afford the cost (consistent with REQ-UI-BUILD-DISABLED). The caption updates as the cost changes with each purchased expansion.
|
- REQ-UI-EXPAND-BUTTON: The header bar shows an asteroid expansion button captioned `Expand: <x> Blocks`, where `<x>` is the current expansion cost computed from `world.toml [expansion].cost_building_blocks_formula` at the current number of purchased expansions (REQ-EXP-COST). Clicking the button unlocks the next asteroid expansion (REQ-EXP-UNLOCK, REQ-GW-ASTEROID-EXPAND), spending that many building blocks from the global stock. The button is disabled when the player cannot currently afford the cost (consistent with REQ-UI-BUILD-DISABLED). The caption updates as the cost changes with each purchased expansion.
|
||||||
- REQ-UI-WORLD-SIZE: The game world view occupies the full height below the header bar in the main column (75% of the screen width).
|
- REQ-UI-WORLD-SIZE: The game world view occupies the full height below the header bar in the main column (75% of the screen width).
|
||||||
- REQ-UI-PANEL-COLUMN: The side panel column occupies 25% of the screen width and the full screen height. It is divided into three equal-height panels stacked top to bottom: selected building panel (top), build button grid (middle), and blueprint panel (bottom).
|
- REQ-UI-PANEL-COLUMN: The side panel column occupies 25% of the screen width and the full screen height. It is divided into three equal-height panels stacked top to bottom: selected building panel (top), build button grid (middle), and blueprint panel (bottom).
|
||||||
@@ -492,7 +492,7 @@ The screen is divided into two columns: a main column (75% width) containing the
|
|||||||
- **W** — increases game speed by one step in the sequence 0×, 0.5×, 1×, 2×, 10× (no wrap-around past 10×).
|
- **W** — increases game speed by one step in the sequence 0×, 0.5×, 1×, 2×, 10× (no wrap-around past 10×).
|
||||||
- **S** — decreases game speed by one step in the same sequence (no wrap-around past 0×).
|
- **S** — decreases game speed by one step in the same sequence (no wrap-around past 0×).
|
||||||
- **A / D** — scroll the view left / right (REQ-UI-SCROLL).
|
- **A / D** — scroll the view left / right (REQ-UI-SCROLL).
|
||||||
- **Q** — context-sensitive. If a build mode is active (builder mode or blueprint placement mode), pressing Q exits it. Otherwise, pressing Q toggles demolish mode: it enters demolish mode if inactive, or exits demolish mode if already active. (See also REQ-UI-DEMOLISH-BUTTON for the equivalent button.)
|
- **Q** — context-sensitive. If a build mode is active (builder mode or blueprint placement mode), pressing Q exits it. Otherwise, pressing Q toggles deconstruct mode: it enters deconstruct mode if inactive, or exits deconstruct mode if already active. (See also REQ-UI-DECONSTRUCT-BUTTON for the equivalent button.)
|
||||||
- **R / Shift+R** — in builder mode, rotate the ghost counter-clockwise / clockwise (REQ-BLD-ROTATE).
|
- **R / Shift+R** — in builder mode, rotate the ghost counter-clockwise / clockwise (REQ-BLD-ROTATE).
|
||||||
- **T** — create a temporary blueprint from the current selection and enter its placement mode (REQ-UI-BLUEPRINT-TEMP).
|
- **T** — create a temporary blueprint from the current selection and enter its placement mode (REQ-UI-BLUEPRINT-TEMP).
|
||||||
- **Escape** — opens the escape menu (REQ-UI-GAME-MENU).
|
- **Escape** — opens the escape menu (REQ-UI-GAME-MENU).
|
||||||
@@ -553,9 +553,9 @@ The screen is divided into two columns: a main column (75% width) containing the
|
|||||||
|
|
||||||
- REQ-UI-BUILD-GRID: All placeable building types are shown as a flat grid of buttons with no grouping. Tunnel Entry and Tunnel Exit share a single **Tunnel** button (REQ-BLD-TUNNEL-MODE) rather than one button each.
|
- REQ-UI-BUILD-GRID: All placeable building types are shown as a flat grid of buttons with no grouping. Tunnel Entry and Tunnel Exit share a single **Tunnel** button (REQ-BLD-TUNNEL-MODE) rather than one button each.
|
||||||
- REQ-UI-BUILD-COST: Each button caption shows the building name and its building block cost, e.g. "Belt: 2 Blocks".
|
- REQ-UI-BUILD-COST: Each button caption shows the building name and its building block cost, e.g. "Belt: 2 Blocks".
|
||||||
- REQ-UI-BUILD-TOOLTIP: Each building-type button shows a hover tooltip with the descriptive text defined for that building type in `buildings.toml` (the optional per-building tooltip field). This tooltip is distinct from the recipe/schematic selection tooltip (REQ-UI-SELECT-TOOLTIP). If a building type defines no tooltip text, its button shows no tooltip. The Demolish button (REQ-UI-DEMOLISH-BUTTON) is not a building type and has no config-defined tooltip.
|
- REQ-UI-BUILD-TOOLTIP: Each building-type button shows a hover tooltip with the descriptive text defined for that building type in `buildings.toml` (the optional per-building tooltip field). This tooltip is distinct from the recipe/schematic selection tooltip (REQ-UI-SELECT-TOOLTIP). If a building type defines no tooltip text, its button shows no tooltip. The Deconstruct button (REQ-UI-DECONSTRUCT-BUTTON) is not a building type and has no config-defined tooltip.
|
||||||
- REQ-UI-BUILD-DISABLED: Buttons for buildings the player cannot currently afford are shown as disabled.
|
- REQ-UI-BUILD-DISABLED: Buttons for buildings the player cannot currently afford are shown as disabled.
|
||||||
- REQ-UI-DEMOLISH-BUTTON: A dedicated **Demolish** button is shown in the build button grid. Clicking it toggles demolish mode on and off, equivalent to the Q demolish toggle (REQ-UI-HOTKEYS). The button is shown in a visually active/pressed state while demolish mode is active.
|
- REQ-UI-DECONSTRUCT-BUTTON: A dedicated **Deconstruct** button is shown in the build button grid. Clicking it toggles deconstruct mode on and off, equivalent to the Q deconstruct toggle (REQ-UI-HOTKEYS). The button is shown in a visually active/pressed state while deconstruct mode is active.
|
||||||
|
|
||||||
### Blueprint Panel
|
### Blueprint Panel
|
||||||
|
|
||||||
@@ -563,7 +563,7 @@ The screen is divided into two columns: a main column (75% width) containing the
|
|||||||
|
|
||||||
- REQ-UI-BLUEPRINT-CREATE: The "Create Blueprint" button is enabled only when at least one player-placeable building (i.e. a building with a button in the build button grid) is currently selected; non-player-placeable buildings (HQ, defence stations) in the selection do not count toward this condition. A selected player-placeable building may be either an operational building or a construction site (a building placed but not yet fully built, REQ-BLD-SITE-CONFIG); both count toward this condition and are captured identically (REQ-UI-BLUEPRINT-STORAGE). When clicked, a modal dialog appears prompting the player to enter a name. The dialog has Confirm and Cancel buttons. Clicking Cancel closes the dialog with no effect. Clicking Confirm with a non-empty name creates a blueprint from the current selection, silently excluding any non-player-placeable buildings, and appends its button to the blueprint list.
|
- REQ-UI-BLUEPRINT-CREATE: The "Create Blueprint" button is enabled only when at least one player-placeable building (i.e. a building with a button in the build button grid) is currently selected; non-player-placeable buildings (HQ, defence stations) in the selection do not count toward this condition. A selected player-placeable building may be either an operational building or a construction site (a building placed but not yet fully built, REQ-BLD-SITE-CONFIG); both count toward this condition and are captured identically (REQ-UI-BLUEPRINT-STORAGE). When clicked, a modal dialog appears prompting the player to enter a name. The dialog has Confirm and Cancel buttons. Clicking Cancel closes the dialog with no effect. Clicking Confirm with a non-empty name creates a blueprint from the current selection, silently excluding any non-player-placeable buildings, and appends its button to the blueprint list.
|
||||||
|
|
||||||
- REQ-UI-BLUEPRINT-TEMP: Pressing the **T** key (REQ-UI-HOTKEYS) creates a **temporary blueprint** from the current selection and immediately enters blueprint placement mode for it, without opening the naming dialog. It has effect only when at least one player-placeable building is currently selected — the same condition as REQ-UI-BLUEPRINT-CREATE; pressing T with an empty selection, or a selection containing only non-player-placeable buildings (HQ, defence stations), does nothing. Entering this mode replaces any currently active build, blueprint placement, or demolish mode. The temporary blueprint is captured exactly as a saved blueprint (REQ-UI-BLUEPRINT-STORAGE), silently excluding any non-player-placeable buildings from the selection, but it is never named, never shown in the blueprint panel (REQ-UI-BLUEPRINT-PANEL), and never persisted to `blueprints.toml` (REQ-UI-BLUEPRINT-SAVE). Placement behaves identically to a saved blueprint's placement mode (REQ-UI-BLUEPRINT-MODE, REQ-UI-BLUEPRINT-PLACE): a ghost is rendered per building, R / Shift+R rotate the entire constellation, placement follows the same per-building validity and total-cost rules, and after a successful placement the mode stays active so the blueprint can be placed again. Right-clicking in the game world exits placement mode, at which point the temporary blueprint is discarded.
|
- REQ-UI-BLUEPRINT-TEMP: Pressing the **T** key (REQ-UI-HOTKEYS) creates a **temporary blueprint** from the current selection and immediately enters blueprint placement mode for it, without opening the naming dialog. It has effect only when at least one player-placeable building is currently selected — the same condition as REQ-UI-BLUEPRINT-CREATE; pressing T with an empty selection, or a selection containing only non-player-placeable buildings (HQ, defence stations), does nothing. Entering this mode replaces any currently active build, blueprint placement, or deconstruct mode. The temporary blueprint is captured exactly as a saved blueprint (REQ-UI-BLUEPRINT-STORAGE), silently excluding any non-player-placeable buildings from the selection, but it is never named, never shown in the blueprint panel (REQ-UI-BLUEPRINT-PANEL), and never persisted to `blueprints.toml` (REQ-UI-BLUEPRINT-SAVE). Placement behaves identically to a saved blueprint's placement mode (REQ-UI-BLUEPRINT-MODE, REQ-UI-BLUEPRINT-PLACE): a ghost is rendered per building, R / Shift+R rotate the entire constellation, placement follows the same per-building validity and total-cost rules, and after a successful placement the mode stays active so the blueprint can be placed again. Right-clicking in the game world exits placement mode, at which point the temporary blueprint is discarded.
|
||||||
|
|
||||||
- REQ-UI-BLUEPRINT-STORAGE: A blueprint stores its name and, for each building in the selection, the building type, its rotation, its tile offset (integer dx, dy) from the center of the bounding box of all selected buildings' footprints, and — where applicable — the selected recipe ID (miners and assemblers) or schematic ID (shipyards), and for splitters the two output filters (each a list of item types; an empty list means accept-all), at the time of capture. A source building may be either an operational building or a construction site (REQ-BLD-SITE-CONFIG); a construction site is captured identically, storing whatever configuration it currently holds and never any buffer or construction-progress state. If no recipe or schematic was selected at capture time, none is stored; for a splitter with no filters set, no filter lists are stored. This structure maps directly to a TOML representation (e.g. one `[[building]]` array entry per constituent building, with the splitter filters as `filter_a`/`filter_b` arrays of item-type ids).
|
- REQ-UI-BLUEPRINT-STORAGE: A blueprint stores its name and, for each building in the selection, the building type, its rotation, its tile offset (integer dx, dy) from the center of the bounding box of all selected buildings' footprints, and — where applicable — the selected recipe ID (miners and assemblers) or schematic ID (shipyards), and for splitters the two output filters (each a list of item types; an empty list means accept-all), at the time of capture. A source building may be either an operational building or a construction site (REQ-BLD-SITE-CONFIG); a construction site is captured identically, storing whatever configuration it currently holds and never any buffer or construction-progress state. If no recipe or schematic was selected at capture time, none is stored; for a splitter with no filters set, no filter lists are stored. This structure maps directly to a TOML representation (e.g. one `[[building]]` array entry per constituent building, with the splitter filters as `filter_a`/`filter_b` arrays of item-type ids).
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ struct WorldScroll
|
|||||||
struct WorldConfig
|
struct WorldConfig
|
||||||
{
|
{
|
||||||
int heightTiles; // REQ-GW-HEIGHT
|
int heightTiles; // REQ-GW-HEIGHT
|
||||||
int refundPercentage; // REQ-BLD-DEMOLISH
|
int refundPercentage; // REQ-BLD-DECONSTRUCT
|
||||||
double deconstructionTimeSeconds; // REQ-BLD-DECON-QUEUE
|
double deconstructionTimeSeconds; // REQ-BLD-DECON-QUEUE
|
||||||
int startingBuildingBlocks; // REQ-HQ-STARTING-BLOCKS
|
int startingBuildingBlocks; // REQ-HQ-STARTING-BLOCKS
|
||||||
double scrapDespawnSeconds; // REQ-RES-SCRAP-DROP
|
double scrapDespawnSeconds; // REQ-RES-SCRAP-DROP
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ SET(HDRS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/BuilderModeExitedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/BuilderModeExitedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/BlueprintModeExitedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/BlueprintModeExitedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/EscapeMenuRequestedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/EscapeMenuRequestedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/DemolishModeChangedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/DeconstructModeChangedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildingTypeSelectedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/BuildingTypeSelectedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/BuildHotkeyPressedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/BuildHotkeyPressedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ExitBuilderModeRequestedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/ExitBuilderModeRequestedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/DemolishModeToggleRequestedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/DeconstructModeToggleRequestedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/BlueprintPlacementRequestedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/BlueprintPlacementRequestedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/ExitBlueprintModeRequestedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/ExitBlueprintModeRequestedEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/TemporaryBlueprintRequestedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/TemporaryBlueprintRequestedEvent.h
|
||||||
|
|||||||
10
src/lib/eventsystem/event/DeconstructModeChangedEvent.h
Normal file
10
src/lib/eventsystem/event/DeconstructModeChangedEvent.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Event.h"
|
||||||
|
|
||||||
|
class DeconstructModeChangedEvent : public Event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit DeconstructModeChangedEvent(bool active) : active(active) {}
|
||||||
|
const bool active;
|
||||||
|
};
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Event.h"
|
||||||
|
|
||||||
|
class DeconstructModeToggleRequestedEvent : public Event
|
||||||
|
{
|
||||||
|
};
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Event.h"
|
|
||||||
|
|
||||||
class DemolishModeChangedEvent : public Event
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit DemolishModeChangedEvent(bool active) : active(active) {}
|
|
||||||
const bool active;
|
|
||||||
};
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Event.h"
|
|
||||||
|
|
||||||
class DemolishModeToggleRequestedEvent : public Event
|
|
||||||
{
|
|
||||||
};
|
|
||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
// tile are held and routed to one of the two outputs.
|
// tile are held and routed to one of the two outputs.
|
||||||
void placeSplitter(QPoint tile, Rotation outputA, Rotation outputB);
|
void placeSplitter(QPoint tile, Rotation outputA, Rotation outputB);
|
||||||
|
|
||||||
// Remove a belt or splitter tile (on demolish). Items are discarded.
|
// Remove a belt or splitter tile (on deconstruct). Items are discarded.
|
||||||
void removeTile(QPoint tile);
|
void removeTile(QPoint tile);
|
||||||
|
|
||||||
// -- Splitter filter configuration (REQ-BLD-SPLITTER) -------------------
|
// -- Splitter filter configuration (REQ-BLD-SPLITTER) -------------------
|
||||||
|
|||||||
@@ -497,13 +497,13 @@ bool BuildingSystem::isPlacementValid(BuildingType type, QPoint anchor,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Demolish
|
// Deconstruct
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
int BuildingSystem::demolish(BuildingId id, Tick currentTick)
|
int BuildingSystem::deconstruct(BuildingId id, Tick currentTick)
|
||||||
{
|
{
|
||||||
// Construction site? Removed instantly with the full refund; never queued
|
// Construction site? Removed instantly with the full refund; never queued
|
||||||
// for deconstruction (REQ-BLD-DEMOLISH).
|
// for deconstruction (REQ-BLD-DECONSTRUCT).
|
||||||
for (std::deque<ConstructionSite>::iterator it = m_constructionQueue.begin();
|
for (std::deque<ConstructionSite>::iterator it = m_constructionQueue.begin();
|
||||||
it != m_constructionQueue.end();
|
it != m_constructionQueue.end();
|
||||||
++it)
|
++it)
|
||||||
@@ -887,9 +887,9 @@ void BuildingSystem::tickDeconstruction(Tick currentTick)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the building from the world and credit its refund (REQ-BLD-DEMOLISH).
|
// Remove the building from the world and credit its refund (REQ-BLD-DECONSTRUCT).
|
||||||
// Belt/tunnel/splitter tiles were already unregistered when the building was
|
// Belt/tunnel/splitter tiles were already unregistered when the building was
|
||||||
// queued (see demolish), so only tile occupancy and the record remain.
|
// queued (see deconstruct), so only tile occupancy and the record remain.
|
||||||
for (std::vector<Building>::iterator it = m_buildings.begin();
|
for (std::vector<Building>::iterator it = m_buildings.begin();
|
||||||
it != m_buildings.end();
|
it != m_buildings.end();
|
||||||
++it)
|
++it)
|
||||||
@@ -1632,7 +1632,7 @@ std::optional<BuildingId> BuildingSystem::findRotateInPlaceTarget(
|
|||||||
BuildingType type, QPoint anchor, Rotation rot) const
|
BuildingType type, QPoint anchor, Rotation rot) const
|
||||||
{
|
{
|
||||||
// Tunnel Entries and Tunnel Exits cannot be rotated in place; re-orienting a
|
// Tunnel Entries and Tunnel Exits cannot be rotated in place; re-orienting a
|
||||||
// tunnel requires demolishing and re-placing it (REQ-BLD-ROTATE-IN-PLACE).
|
// tunnel requires deconstructing and re-placing it (REQ-BLD-ROTATE-IN-PLACE).
|
||||||
if (type == BuildingType::TunnelEntry || type == BuildingType::TunnelExit)
|
if (type == BuildingType::TunnelEntry || type == BuildingType::TunnelExit)
|
||||||
{
|
{
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public:
|
|||||||
std::function<bool(const std::string&)> isItemUnlocked,
|
std::function<bool(const std::string&)> isItemUnlocked,
|
||||||
std::mt19937& rng);
|
std::mt19937& rng);
|
||||||
|
|
||||||
// -- Placement / demolish ------------------------------------------------
|
// -- Placement / deconstruct ------------------------------------------------
|
||||||
// Returns the new entity id, or nullopt if the placement falls outside the
|
// Returns the new entity id, or nullopt if the placement falls outside the
|
||||||
// world bounds (vertical extent and asteroid left edge). Belt and Splitter
|
// world bounds (vertical extent and asteroid left edge). Belt and Splitter
|
||||||
// register with BeltSystem directly; other types enter the construction
|
// register with BeltSystem directly; other types enter the construction
|
||||||
@@ -77,13 +77,13 @@ public:
|
|||||||
// Defaults to world.regions.asteroid_width_tiles at construction.
|
// Defaults to world.regions.asteroid_width_tiles at construction.
|
||||||
void setAsteroidWidth_tiles(int widthTiles) { m_asteroidWidth_tiles = widthTiles; }
|
void setAsteroidWidth_tiles(int widthTiles) { m_asteroidWidth_tiles = widthTiles; }
|
||||||
|
|
||||||
// Mark a building or construction site for demolition (REQ-BLD-DEMOLISH).
|
// Mark a building or construction site for demolition (REQ-BLD-DECONSTRUCT).
|
||||||
// A construction site is removed instantly and the full cost is returned.
|
// A construction site is removed instantly and the full cost is returned.
|
||||||
// A fully-built building is instead appended to the deconstruction queue
|
// A fully-built building is instead appended to the deconstruction queue
|
||||||
// (REQ-BLD-DECON-QUEUE) and stops operating at once; its (partial) refund is
|
// (REQ-BLD-DECON-QUEUE) and stops operating at once; its (partial) refund is
|
||||||
// credited later, on completion in tickDeconstruction, so this returns 0 for
|
// credited later, on completion in tickDeconstruction, so this returns 0 for
|
||||||
// it. Returns 0 for unknown ids and for a building already queued.
|
// it. Returns 0 for unknown ids and for a building already queued.
|
||||||
int demolish(BuildingId id, Tick currentTick);
|
int deconstruct(BuildingId id, Tick currentTick);
|
||||||
|
|
||||||
// Take a building back out of the deconstruction queue before it is removed
|
// Take a building back out of the deconstruction queue before it is removed
|
||||||
// (REQ-BLD-DECON-QUEUE). Clears its queued flag and resumes operation
|
// (REQ-BLD-DECON-QUEUE). Clears its queued flag and resumes operation
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class GameConfig;
|
|||||||
enum class CommandKind
|
enum class CommandKind
|
||||||
{
|
{
|
||||||
PlaceBuilding,
|
PlaceBuilding,
|
||||||
Demolish,
|
Deconstruct,
|
||||||
CancelDeconstruction,
|
CancelDeconstruction,
|
||||||
RotateInPlace,
|
RotateInPlace,
|
||||||
SetRecipe,
|
SetRecipe,
|
||||||
@@ -74,15 +74,15 @@ struct PlaceBuildingCommand : Command
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Marks a building for demolition: a construction site is removed instantly, a
|
// Marks a building for demolition: a construction site is removed instantly, a
|
||||||
// built building is queued for deconstruction (REQ-BLD-DEMOLISH, REQ-BLD-DECON-QUEUE).
|
// built building is queued for deconstruction (REQ-BLD-DECONSTRUCT, REQ-BLD-DECON-QUEUE).
|
||||||
struct DemolishCommand : Command
|
struct DeconstructCommand : Command
|
||||||
{
|
{
|
||||||
DemolishCommand() : Command(CommandKind::Demolish) {}
|
DeconstructCommand() : Command(CommandKind::Deconstruct) {}
|
||||||
std::optional<BuildingId> id;
|
std::optional<BuildingId> id;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Takes a building back out of the deconstruction queue (REQ-BLD-DEMOLISH-CLICK,
|
// Takes a building back out of the deconstruction queue (REQ-BLD-DECONSTRUCT-CLICK,
|
||||||
// REQ-BLD-DEMOLISH-BOX). No-op if the id is not currently queued.
|
// REQ-BLD-DECONSTRUCT-BOX). No-op if the id is not currently queued.
|
||||||
struct CancelDeconstructionCommand : Command
|
struct CancelDeconstructionCommand : Command
|
||||||
{
|
{
|
||||||
CancelDeconstructionCommand() : Command(CommandKind::CancelDeconstruction) {}
|
CancelDeconstructionCommand() : Command(CommandKind::CancelDeconstruction) {}
|
||||||
|
|||||||
@@ -128,8 +128,8 @@ std::string serializeCommand(const Command& command)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CommandKind::Demolish:
|
case CommandKind::Deconstruct:
|
||||||
out << "demolish " << static_cast<const DemolishCommand&>(command).id.value();
|
out << "deconstruct " << static_cast<const DeconstructCommand&>(command).id.value();
|
||||||
break;
|
break;
|
||||||
case CommandKind::CancelDeconstruction:
|
case CommandKind::CancelDeconstruction:
|
||||||
out << "cancel_deconstruct "
|
out << "cancel_deconstruct "
|
||||||
@@ -243,9 +243,9 @@ std::shared_ptr<Command> parseCommand(const std::string& tokens)
|
|||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
if (verb == "demolish")
|
if (verb == "deconstruct")
|
||||||
{
|
{
|
||||||
std::shared_ptr<DemolishCommand> c = std::make_shared<DemolishCommand>();
|
std::shared_ptr<DeconstructCommand> c = std::make_shared<DeconstructCommand>();
|
||||||
BuildingId id = 0;
|
BuildingId id = 0;
|
||||||
if (!(in >> id)) { return nullptr; }
|
if (!(in >> id)) { return nullptr; }
|
||||||
c->id = id;
|
c->id = id;
|
||||||
|
|||||||
@@ -231,8 +231,8 @@ void Simulation::apply(const Command& command)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CommandKind::Demolish:
|
case CommandKind::Deconstruct:
|
||||||
demolish(*static_cast<const DemolishCommand&>(command).id);
|
deconstruct(*static_cast<const DeconstructCommand&>(command).id);
|
||||||
break;
|
break;
|
||||||
case CommandKind::CancelDeconstruction:
|
case CommandKind::CancelDeconstruction:
|
||||||
cancelDeconstruction(*static_cast<const CancelDeconstructionCommand&>(command).id);
|
cancelDeconstruction(*static_cast<const CancelDeconstructionCommand&>(command).id);
|
||||||
@@ -1198,9 +1198,9 @@ std::optional<BuildingId> Simulation::tryPlaceBuilding(BuildingType type, QPoint
|
|||||||
return m_buildingSystem->place(type, anchor, rotation, m_currentTick);
|
return m_buildingSystem->place(type, anchor, rotation, m_currentTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Simulation::demolish(BuildingId id)
|
void Simulation::deconstruct(BuildingId id)
|
||||||
{
|
{
|
||||||
m_buildingBlocksStock += m_buildingSystem->demolish(id, m_currentTick);
|
m_buildingBlocksStock += m_buildingSystem->deconstruct(id, m_currentTick);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Simulation::cancelDeconstruction(BuildingId id)
|
void Simulation::cancelDeconstruction(BuildingId id)
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ private:
|
|||||||
// Marks the building with the given id for demolition: a construction site is
|
// Marks the building with the given id for demolition: a construction site is
|
||||||
// removed instantly (full refund), a built building is queued for timed
|
// removed instantly (full refund), a built building is queued for timed
|
||||||
// deconstruction (REQ-BLD-DECON-QUEUE), refunded on completion.
|
// deconstruction (REQ-BLD-DECON-QUEUE), refunded on completion.
|
||||||
void demolish(BuildingId id);
|
void deconstruct(BuildingId id);
|
||||||
|
|
||||||
// Takes a queued building back out of the deconstruction queue (REQ-BLD-DECON-QUEUE).
|
// Takes a queued building back out of the deconstruction queue (REQ-BLD-DECON-QUEUE).
|
||||||
void cancelDeconstruction(BuildingId id);
|
void cancelDeconstruction(BuildingId id);
|
||||||
|
|||||||
@@ -974,7 +974,7 @@ TEST_CASE("BeltSystem: unpaired entry blocks items at front", "[belt]")
|
|||||||
REQUIRE(bs.peekItem(Port{QPoint(3, 0), Rotation::East}).has_value());
|
REQUIRE(bs.peekItem(Port{QPoint(3, 0), Rotation::East}).has_value());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("BeltSystem: demolish entry discards transit items", "[belt]")
|
TEST_CASE("BeltSystem: deconstruct entry discards transit items", "[belt]")
|
||||||
{
|
{
|
||||||
BeltSystem bs(kFastBeltSpeed);
|
BeltSystem bs(kFastBeltSpeed);
|
||||||
|
|
||||||
|
|||||||
@@ -266,7 +266,7 @@ TEST_CASE("BuildingSystem: placed building enters construction queue", "[buildin
|
|||||||
REQUIRE(bs.findSite(id) != nullptr);
|
REQUIRE(bs.findSite(id) != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("BuildingSystem: demolishing a construction site removes it instantly with full refund",
|
TEST_CASE("BuildingSystem: deconstructing a construction site removes it instantly with full refund",
|
||||||
"[building]")
|
"[building]")
|
||||||
{
|
{
|
||||||
PlacementFixture f;
|
PlacementFixture f;
|
||||||
@@ -274,8 +274,8 @@ TEST_CASE("BuildingSystem: demolishing a construction site removes it instantly
|
|||||||
f.bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
f.bs.place(BuildingType::Miner, QPoint(0, 0), Rotation::East, 0).value();
|
||||||
|
|
||||||
// Still queued for construction (not yet built): instant removal, full cost
|
// Still queued for construction (not yet built): instant removal, full cost
|
||||||
// refunded immediately, never entering the deconstruction queue (REQ-BLD-DEMOLISH).
|
// refunded immediately, never entering the deconstruction queue (REQ-BLD-DECONSTRUCT).
|
||||||
const int refund = f.bs.demolish(id, 0);
|
const int refund = f.bs.deconstruct(id, 0);
|
||||||
|
|
||||||
REQUIRE(refund == 15); // Miner cost = 15
|
REQUIRE(refund == 15); // Miner cost = 15
|
||||||
REQUIRE_FALSE(f.bs.isTileOccupied(QPoint(0, 0)));
|
REQUIRE_FALSE(f.bs.isTileOccupied(QPoint(0, 0)));
|
||||||
@@ -366,7 +366,7 @@ static void runUntilBuilt(PlacementFixture& f, BuildingId id, Tick& tick)
|
|||||||
REQUIRE(f.bs.findBuilding(id) != nullptr);
|
REQUIRE(f.bs.findBuilding(id) != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("BuildingSystem: demolishing a built building queues it; refund credited on completion",
|
TEST_CASE("BuildingSystem: deconstructing a built building queues it; refund credited on completion",
|
||||||
"[building][decon]")
|
"[building][decon]")
|
||||||
{
|
{
|
||||||
PlacementFixture f;
|
PlacementFixture f;
|
||||||
@@ -376,9 +376,9 @@ TEST_CASE("BuildingSystem: demolishing a built building queues it; refund credit
|
|||||||
Tick tick = 0;
|
Tick tick = 0;
|
||||||
runUntilBuilt(f, id, tick);
|
runUntilBuilt(f, id, tick);
|
||||||
|
|
||||||
// Demolishing a built building returns nothing immediately and queues it,
|
// Deconstructing a built building returns nothing immediately and queues it,
|
||||||
// stopping it operating while its tiles stay occupied (REQ-BLD-DECON-QUEUE).
|
// stopping it operating while its tiles stay occupied (REQ-BLD-DECON-QUEUE).
|
||||||
const int refund = f.bs.demolish(id, tick);
|
const int refund = f.bs.deconstruct(id, tick);
|
||||||
REQUIRE(refund == 0);
|
REQUIRE(refund == 0);
|
||||||
REQUIRE(f.bs.isQueuedForDeconstruction(id));
|
REQUIRE(f.bs.isQueuedForDeconstruction(id));
|
||||||
REQUIRE(f.bs.isTileOccupied(QPoint(0, 0)));
|
REQUIRE(f.bs.isTileOccupied(QPoint(0, 0)));
|
||||||
@@ -403,8 +403,8 @@ TEST_CASE("BuildingSystem: deconstruction queue removes one building at a time",
|
|||||||
runUntilBuilt(f, b, tick);
|
runUntilBuilt(f, b, tick);
|
||||||
|
|
||||||
// Queue both in one tick; 'a' is at the front of the deconstruction queue.
|
// Queue both in one tick; 'a' is at the front of the deconstruction queue.
|
||||||
f.bs.demolish(a, tick);
|
f.bs.deconstruct(a, tick);
|
||||||
f.bs.demolish(b, tick);
|
f.bs.deconstruct(b, tick);
|
||||||
REQUIRE(f.bs.isQueuedForDeconstruction(a));
|
REQUIRE(f.bs.isQueuedForDeconstruction(a));
|
||||||
REQUIRE(f.bs.isQueuedForDeconstruction(b));
|
REQUIRE(f.bs.isQueuedForDeconstruction(b));
|
||||||
|
|
||||||
@@ -432,7 +432,7 @@ TEST_CASE("BuildingSystem: cancelling deconstruction resumes the building with n
|
|||||||
Tick tick = 0;
|
Tick tick = 0;
|
||||||
runUntilBuilt(f, id, tick);
|
runUntilBuilt(f, id, tick);
|
||||||
|
|
||||||
f.bs.demolish(id, tick);
|
f.bs.deconstruct(id, tick);
|
||||||
REQUIRE(f.bs.isQueuedForDeconstruction(id));
|
REQUIRE(f.bs.isQueuedForDeconstruction(id));
|
||||||
|
|
||||||
// Un-queue before it drains: it operates again, no refund, tiles still occupied.
|
// Un-queue before it drains: it operates again, no refund, tiles still occupied.
|
||||||
@@ -460,7 +460,7 @@ TEST_CASE("BuildingSystem: queued belt stops transporting; cancel restores it",
|
|||||||
|
|
||||||
// Queuing a belt unregisters its tile from the belt subsystem, so it no longer
|
// Queuing a belt unregisters its tile from the belt subsystem, so it no longer
|
||||||
// accepts or transports items, though the tile stays occupied (REQ-BLD-DECON-QUEUE).
|
// accepts or transports items, though the tile stays occupied (REQ-BLD-DECON-QUEUE).
|
||||||
f.bs.demolish(id, tick);
|
f.bs.deconstruct(id, tick);
|
||||||
REQUIRE_FALSE(f.belts.tryPutItem(QPoint(0, 0), makeItem("iron_ore"), Rotation::East));
|
REQUIRE_FALSE(f.belts.tryPutItem(QPoint(0, 0), makeItem("iron_ore"), Rotation::East));
|
||||||
REQUIRE(f.bs.isTileOccupied(QPoint(0, 0)));
|
REQUIRE(f.bs.isTileOccupied(QPoint(0, 0)));
|
||||||
|
|
||||||
@@ -482,7 +482,7 @@ TEST_CASE("BuildingSystem: splitter filters survive a queue/un-queue round-trip"
|
|||||||
|
|
||||||
// Queue: the belt subsystem tile (and its filters) are unregistered, but the
|
// Queue: the belt subsystem tile (and its filters) are unregistered, but the
|
||||||
// filters are captured so an un-queue can restore them.
|
// filters are captured so an un-queue can restore them.
|
||||||
f.bs.demolish(id, tick);
|
f.bs.deconstruct(id, tick);
|
||||||
REQUIRE_FALSE(f.belts.getSplitterInfo(QPoint(0, 0)).has_value());
|
REQUIRE_FALSE(f.belts.getSplitterInfo(QPoint(0, 0)).has_value());
|
||||||
|
|
||||||
f.bs.cancelDeconstruction(id);
|
f.bs.cancelDeconstruction(id);
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ TEST_CASE("apply(PlaceBuildingCommand) with recipe matches place-then-setRecipe"
|
|||||||
REQUIRE(viaCommand.computeStateChecksum() == viaDirect.computeStateChecksum());
|
REQUIRE(viaCommand.computeStateChecksum() == viaDirect.computeStateChecksum());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("apply(DemolishCommand) matches direct demolish", "[command]")
|
TEST_CASE("apply(DeconstructCommand) matches direct deconstruct", "[command]")
|
||||||
{
|
{
|
||||||
Simulation viaCommand(loadConfig(), 99);
|
Simulation viaCommand(loadConfig(), 99);
|
||||||
Simulation viaDirect(loadConfig(), 99);
|
Simulation viaDirect(loadConfig(), 99);
|
||||||
@@ -70,11 +70,11 @@ TEST_CASE("apply(DemolishCommand) matches direct demolish", "[command]")
|
|||||||
SimulationTestAccess::place(viaDirect, BuildingType::Miner, QPoint(-3, 0), Rotation::East).value();
|
SimulationTestAccess::place(viaDirect, BuildingType::Miner, QPoint(-3, 0), Rotation::East).value();
|
||||||
REQUIRE(idA == idB);
|
REQUIRE(idA == idB);
|
||||||
|
|
||||||
DemolishCommand command;
|
DeconstructCommand command;
|
||||||
command.id = idA;
|
command.id = idA;
|
||||||
viaCommand.apply(command);
|
viaCommand.apply(command);
|
||||||
|
|
||||||
SimulationTestAccess::demolish(viaDirect, idB);
|
SimulationTestAccess::deconstruct(viaDirect, idB);
|
||||||
|
|
||||||
REQUIRE(viaCommand.computeStateChecksum() == viaDirect.computeStateChecksum());
|
REQUIRE(viaCommand.computeStateChecksum() == viaDirect.computeStateChecksum());
|
||||||
}
|
}
|
||||||
@@ -96,8 +96,8 @@ TEST_CASE("apply(CancelDeconstructionCommand) matches direct cancelDeconstructio
|
|||||||
viaCommand.tick();
|
viaCommand.tick();
|
||||||
viaDirect.tick();
|
viaDirect.tick();
|
||||||
}
|
}
|
||||||
SimulationTestAccess::demolish(viaCommand, idA);
|
SimulationTestAccess::deconstruct(viaCommand, idA);
|
||||||
SimulationTestAccess::demolish(viaDirect, idB);
|
SimulationTestAccess::deconstruct(viaDirect, idB);
|
||||||
|
|
||||||
CancelDeconstructionCommand command;
|
CancelDeconstructionCommand command;
|
||||||
command.id = idA;
|
command.id = idA;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ GameConfig loadConfig()
|
|||||||
constexpr int kScriptTicks = 2000;
|
constexpr int kScriptTicks = 2000;
|
||||||
|
|
||||||
// Runs a fixed scripted session and returns the full-state checksum after every
|
// Runs a fixed scripted session and returns the full-state checksum after every
|
||||||
// tick. The script places a small factory, demolishes part of it mid-run, and
|
// tick. The script places a small factory, deconstructs part of it mid-run, and
|
||||||
// otherwise lets waves/combat run so the RNG stream and ECS state are exercised.
|
// otherwise lets waves/combat run so the RNG stream and ECS state are exercised.
|
||||||
std::vector<std::uint64_t> runScriptedSession(unsigned int seed)
|
std::vector<std::uint64_t> runScriptedSession(unsigned int seed)
|
||||||
{
|
{
|
||||||
@@ -40,7 +40,7 @@ std::vector<std::uint64_t> runScriptedSession(unsigned int seed)
|
|||||||
{
|
{
|
||||||
if (t == 500)
|
if (t == 500)
|
||||||
{
|
{
|
||||||
// Demolish the second belt mid-run to exercise the removal paths.
|
// Deconstruct the second belt mid-run to exercise the removal paths.
|
||||||
SimulationTestAccess::place(sim, BuildingType::Smelter, QPoint(-3, 3), Rotation::East);
|
SimulationTestAccess::place(sim, BuildingType::Smelter, QPoint(-3, 3), Rotation::East);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -77,12 +77,12 @@ TEST_CASE("parseCommand round-trips every command verb", "[replay]")
|
|||||||
ClearBeltTilesCommand clear;
|
ClearBeltTilesCommand clear;
|
||||||
clear.tiles = { QPoint(0, 0), QPoint(-1, 4) };
|
clear.tiles = { QPoint(0, 0), QPoint(-1, 4) };
|
||||||
|
|
||||||
DemolishCommand demolish;
|
DeconstructCommand deconstruct;
|
||||||
demolish.id = 5;
|
deconstruct.id = 5;
|
||||||
|
|
||||||
for (const Command* command : { static_cast<const Command*>(&filters),
|
for (const Command* command : { static_cast<const Command*>(&filters),
|
||||||
static_cast<const Command*>(&clear),
|
static_cast<const Command*>(&clear),
|
||||||
static_cast<const Command*>(&demolish) })
|
static_cast<const Command*>(&deconstruct) })
|
||||||
{
|
{
|
||||||
const std::string text = serializeCommand(*command);
|
const std::string text = serializeCommand(*command);
|
||||||
const std::shared_ptr<Command> parsed = parseCommand(text);
|
const std::shared_ptr<Command> parsed = parseCommand(text);
|
||||||
|
|||||||
@@ -83,11 +83,11 @@ TEST_CASE("serializeCommand: splitter filters are length-prefixed", "[replay]")
|
|||||||
== "splitterfilters 4 7 2 iron_ore copper_ore 1 coal");
|
== "splitterfilters 4 7 2 iron_ore copper_ore 1 coal");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("serializeCommand: demolish / rotate / schematic / clearbelt", "[replay]")
|
TEST_CASE("serializeCommand: deconstruct / rotate / schematic / clearbelt", "[replay]")
|
||||||
{
|
{
|
||||||
DemolishCommand demolish;
|
DeconstructCommand deconstruct;
|
||||||
demolish.id = 12;
|
deconstruct.id = 12;
|
||||||
REQUIRE(serializeCommand(demolish) == "demolish 12");
|
REQUIRE(serializeCommand(deconstruct) == "deconstruct 12");
|
||||||
|
|
||||||
RotateInPlaceCommand rotate;
|
RotateInPlaceCommand rotate;
|
||||||
rotate.id = 7;
|
rotate.id = 7;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ struct SimulationTestAccess
|
|||||||
return sim.tryPlaceBuilding(type, anchor, rotation);
|
return sim.tryPlaceBuilding(type, anchor, rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void demolish(Simulation& sim, BuildingId id) { sim.demolish(id); }
|
static void deconstruct(Simulation& sim, BuildingId id) { sim.deconstruct(id); }
|
||||||
|
|
||||||
static void cancelDeconstruction(Simulation& sim, BuildingId id)
|
static void cancelDeconstruction(Simulation& sim, BuildingId id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "BuildingTypeSelectedEvent.h"
|
#include "BuildingTypeSelectedEvent.h"
|
||||||
#include "DemolishModeToggleRequestedEvent.h"
|
#include "DeconstructModeToggleRequestedEvent.h"
|
||||||
#include "DisplayName.h"
|
#include "DisplayName.h"
|
||||||
#include "EventManager.h"
|
#include "EventManager.h"
|
||||||
#include "ExitBuilderModeRequestedEvent.h"
|
#include "ExitBuilderModeRequestedEvent.h"
|
||||||
@@ -73,13 +73,13 @@ BuildButtonGrid::BuildButtonGrid(Simulation* sim, const GameConfig* config, QWid
|
|||||||
}
|
}
|
||||||
connect(mapper, qOverload<int>(&QSignalMapper::mapped), this, &BuildButtonGrid::onBuildButton);
|
connect(mapper, qOverload<int>(&QSignalMapper::mapped), this, &BuildButtonGrid::onBuildButton);
|
||||||
|
|
||||||
m_demolishButton = new QPushButton(tr("Demolish"), this);
|
m_deconstructButton = new QPushButton(tr("Deconstruct"), this);
|
||||||
m_demolishButton->setCheckable(true);
|
m_deconstructButton->setCheckable(true);
|
||||||
m_demolishButton->setFixedHeight(48);
|
m_deconstructButton->setFixedHeight(48);
|
||||||
layout->addWidget(m_demolishButton, row, col);
|
layout->addWidget(m_deconstructButton, row, col);
|
||||||
connect(m_demolishButton, &QPushButton::clicked, this, [this]() {
|
connect(m_deconstructButton, &QPushButton::clicked, this, [this]() {
|
||||||
EventManager::getInstance()->sendEventImmediately(
|
EventManager::getInstance()->sendEventImmediately(
|
||||||
std::make_shared<DemolishModeToggleRequestedEvent>());
|
std::make_shared<DeconstructModeToggleRequestedEvent>());
|
||||||
});
|
});
|
||||||
|
|
||||||
updateVisibility();
|
updateVisibility();
|
||||||
@@ -183,9 +183,9 @@ void BuildButtonGrid::handleEvent(std::shared_ptr<const UnlockedBuildingsChanged
|
|||||||
updateAffordability();
|
updateAffordability();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildButtonGrid::handleEvent(std::shared_ptr<const DemolishModeChangedEvent> event)
|
void BuildButtonGrid::handleEvent(std::shared_ptr<const DeconstructModeChangedEvent> event)
|
||||||
{
|
{
|
||||||
m_demolishButton->setChecked(event->active);
|
m_deconstructButton->setChecked(event->active);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BuildButtonGrid::handleEvent(std::shared_ptr<const BuildHotkeyPressedEvent> event)
|
void BuildButtonGrid::handleEvent(std::shared_ptr<const BuildHotkeyPressedEvent> event)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "BuildHotkeyPressedEvent.h"
|
#include "BuildHotkeyPressedEvent.h"
|
||||||
#include "BuildingBlocksChangedEvent.h"
|
#include "BuildingBlocksChangedEvent.h"
|
||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "DemolishModeChangedEvent.h"
|
#include "DeconstructModeChangedEvent.h"
|
||||||
#include "EventHandler.h"
|
#include "EventHandler.h"
|
||||||
#include "GameConfig.h"
|
#include "GameConfig.h"
|
||||||
#include "UnlockedBuildingsChangedEvent.h"
|
#include "UnlockedBuildingsChangedEvent.h"
|
||||||
@@ -20,7 +20,7 @@ class Simulation;
|
|||||||
|
|
||||||
class BuildButtonGrid : public QWidget,
|
class BuildButtonGrid : public QWidget,
|
||||||
public CombinedEventHandler<BuilderModeExitedEvent,
|
public CombinedEventHandler<BuilderModeExitedEvent,
|
||||||
DemolishModeChangedEvent,
|
DeconstructModeChangedEvent,
|
||||||
BuildHotkeyPressedEvent,
|
BuildHotkeyPressedEvent,
|
||||||
BuildingBlocksChangedEvent,
|
BuildingBlocksChangedEvent,
|
||||||
UnlockedBuildingsChangedEvent>
|
UnlockedBuildingsChangedEvent>
|
||||||
@@ -44,7 +44,7 @@ private:
|
|||||||
void updateVisibility();
|
void updateVisibility();
|
||||||
|
|
||||||
void handleEvent(std::shared_ptr<const BuilderModeExitedEvent> event) override;
|
void handleEvent(std::shared_ptr<const BuilderModeExitedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const DemolishModeChangedEvent> event) override;
|
void handleEvent(std::shared_ptr<const DeconstructModeChangedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const BuildHotkeyPressedEvent> event) override;
|
void handleEvent(std::shared_ptr<const BuildHotkeyPressedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
|
void handleEvent(std::shared_ptr<const BuildingBlocksChangedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const UnlockedBuildingsChangedEvent> event) override;
|
void handleEvent(std::shared_ptr<const UnlockedBuildingsChangedEvent> event) override;
|
||||||
@@ -59,5 +59,5 @@ private:
|
|||||||
std::vector<QPushButton*> m_buttons;
|
std::vector<QPushButton*> m_buttons;
|
||||||
std::map<BuildingType, int> m_costs;
|
std::map<BuildingType, int> m_costs;
|
||||||
std::optional<std::size_t> m_activeIndex;
|
std::optional<std::size_t> m_activeIndex;
|
||||||
QPushButton* m_demolishButton;
|
QPushButton* m_deconstructButton;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
#include "ReplayPlayer.h"
|
#include "ReplayPlayer.h"
|
||||||
#include "ReplayReader.h"
|
#include "ReplayReader.h"
|
||||||
#include "ReplayRecorder.h"
|
#include "ReplayRecorder.h"
|
||||||
#include "DemolishModeChangedEvent.h"
|
#include "DeconstructModeChangedEvent.h"
|
||||||
#include "EntityHitTest.h"
|
#include "EntityHitTest.h"
|
||||||
#include "EntitySelectionChangedEvent.h"
|
#include "EntitySelectionChangedEvent.h"
|
||||||
#include "EventManager.h"
|
#include "EventManager.h"
|
||||||
@@ -157,7 +157,7 @@ GameWorldView::GameWorldView(Simulation* sim, const GameConfig* config,
|
|||||||
, m_ghostRotation(Rotation::East)
|
, m_ghostRotation(Rotation::East)
|
||||||
, m_ghostValid(false)
|
, m_ghostValid(false)
|
||||||
, m_dragging(false)
|
, m_dragging(false)
|
||||||
, m_demolishMode(false)
|
, m_deconstructMode(false)
|
||||||
, m_debugDraw(false)
|
, m_debugDraw(false)
|
||||||
, m_rng(std::random_device{}())
|
, m_rng(std::random_device{}())
|
||||||
, m_boxSelecting(false)
|
, m_boxSelecting(false)
|
||||||
@@ -463,7 +463,7 @@ void GameWorldView::paintGL()
|
|||||||
drawOverlays(painter);
|
drawOverlays(painter);
|
||||||
drawScreenSpace(painter);
|
drawScreenSpace(painter);
|
||||||
drawPauseBorder(painter);
|
drawPauseBorder(painter);
|
||||||
drawDemolishBorder(painter);
|
drawDeconstructBorder(painter);
|
||||||
drawReplayOverlay(painter);
|
drawReplayOverlay(painter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1984,13 +1984,13 @@ void GameWorldView::drawOverlays(QPainter& painter)
|
|||||||
if (!b.queuedForDeconstruction) { continue; }
|
if (!b.queuedForDeconstruction) { continue; }
|
||||||
for (const QPoint& cell : b.bodyCells)
|
for (const QPoint& cell : b.bodyCells)
|
||||||
{
|
{
|
||||||
painter.fillRect(tileRect(cell), m_visuals->overlays.demolishTint);
|
painter.fillRect(tileRect(cell), m_visuals->overlays.deconstructTint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Demolish tint: while dragging a demolish box, tint every covered
|
// Deconstruct tint: while dragging a deconstruct box, tint every covered
|
||||||
// building/site (REQ-BLD-DEMOLISH-BOX); otherwise tint the hovered one.
|
// building/site (REQ-BLD-DECONSTRUCT-BOX); otherwise tint the hovered one.
|
||||||
if (m_demolishMode && m_boxSelecting)
|
if (m_deconstructMode && m_boxSelecting)
|
||||||
{
|
{
|
||||||
for (BuildingId id : buildingsInBox(m_boxStartTile, m_boxCurrentTile))
|
for (BuildingId id : buildingsInBox(m_boxStartTile, m_boxCurrentTile))
|
||||||
{
|
{
|
||||||
@@ -2004,19 +2004,19 @@ void GameWorldView::drawOverlays(QPainter& painter)
|
|||||||
{
|
{
|
||||||
for (const QPoint& cell : *cells)
|
for (const QPoint& cell : *cells)
|
||||||
{
|
{
|
||||||
painter.fillRect(tileRect(cell), m_visuals->overlays.demolishTint);
|
painter.fillRect(tileRect(cell), m_visuals->overlays.deconstructTint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_demolishMode && m_demolishHoverBuildingId.has_value())
|
else if (m_deconstructMode && m_deconstructHoverBuildingId.has_value())
|
||||||
{
|
{
|
||||||
const Building* b = m_sim->getBuildings().findBuilding(*m_demolishHoverBuildingId);
|
const Building* b = m_sim->getBuildings().findBuilding(*m_deconstructHoverBuildingId);
|
||||||
if (b)
|
if (b)
|
||||||
{
|
{
|
||||||
for (const QPoint& cell : b->bodyCells)
|
for (const QPoint& cell : b->bodyCells)
|
||||||
{
|
{
|
||||||
painter.fillRect(tileRect(cell), m_visuals->overlays.demolishTint);
|
painter.fillRect(tileRect(cell), m_visuals->overlays.deconstructTint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2124,11 +2124,11 @@ void GameWorldView::drawPauseBorder(QPainter& painter)
|
|||||||
drawVignetteBorder(painter, QColor(0, 0, 0, 128)); // 50% black at the edge
|
drawVignetteBorder(painter, QColor(0, 0, 0, 128)); // 50% black at the edge
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameWorldView::drawDemolishBorder(QPainter& painter)
|
void GameWorldView::drawDeconstructBorder(QPainter& painter)
|
||||||
{
|
{
|
||||||
if (!m_demolishMode) { return; }
|
if (!m_deconstructMode) { return; }
|
||||||
// Reuse the demolish overlay color (with its configured alpha) as the edge color.
|
// Reuse the deconstruct overlay color (with its configured alpha) as the edge color.
|
||||||
drawVignetteBorder(painter, m_visuals->overlays.demolishTint);
|
drawVignetteBorder(painter, m_visuals->overlays.deconstructTint);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameWorldView::drawVignetteBorder(QPainter& painter, const QColor& edgeColor)
|
void GameWorldView::drawVignetteBorder(QPainter& painter, const QColor& edgeColor)
|
||||||
@@ -2325,7 +2325,7 @@ void GameWorldView::keyPressEvent(QKeyEvent* event)
|
|||||||
case Qt::Key_Q:
|
case Qt::Key_Q:
|
||||||
if (m_builderType.has_value()) { exitBuilderMode(); }
|
if (m_builderType.has_value()) { exitBuilderMode(); }
|
||||||
else if (m_blueprintMode.has_value()) { exitBlueprintMode(); }
|
else if (m_blueprintMode.has_value()) { exitBlueprintMode(); }
|
||||||
else { toggleDemolishMode(); }
|
else { toggleDeconstructMode(); }
|
||||||
break;
|
break;
|
||||||
case Qt::Key_T:
|
case Qt::Key_T:
|
||||||
// Request a temporary blueprint from the current selection (REQ-UI-BLUEPRINT-TEMP).
|
// Request a temporary blueprint from the current selection (REQ-UI-BLUEPRINT-TEMP).
|
||||||
@@ -2387,7 +2387,7 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (m_blueprintMode.has_value()) { exitBlueprintMode(); }
|
else if (m_blueprintMode.has_value()) { exitBlueprintMode(); }
|
||||||
else if (m_demolishMode) { toggleDemolishMode(); }
|
else if (m_deconstructMode) { toggleDeconstructMode(); }
|
||||||
else if (event->modifiers() & Qt::ShiftModifier)
|
else if (event->modifiers() & Qt::ShiftModifier)
|
||||||
{
|
{
|
||||||
// Shift + right-click copies a building's settings, but only in the
|
// Shift + right-click copies a building's settings, but only in the
|
||||||
@@ -2424,10 +2424,10 @@ void GameWorldView::mousePressEvent(QMouseEvent* event)
|
|||||||
{
|
{
|
||||||
placeBlueprintAtTile(tile);
|
placeBlueprintAtTile(tile);
|
||||||
}
|
}
|
||||||
else if (m_demolishMode)
|
else if (m_deconstructMode)
|
||||||
{
|
{
|
||||||
// Start a demolish box drag; a plain click resolves as a 1x1 box on
|
// Start a deconstruct box drag; a plain click resolves as a 1x1 box on
|
||||||
// release (REQ-BLD-DEMOLISH-CLICK, REQ-BLD-DEMOLISH-BOX).
|
// release (REQ-BLD-DECONSTRUCT-CLICK, REQ-BLD-DECONSTRUCT-BOX).
|
||||||
m_boxSelecting = true;
|
m_boxSelecting = true;
|
||||||
m_boxStartTile = tile;
|
m_boxStartTile = tile;
|
||||||
m_boxCurrentTile = tile;
|
m_boxCurrentTile = tile;
|
||||||
@@ -2601,9 +2601,9 @@ void GameWorldView::mouseMoveEvent(QMouseEvent* event)
|
|||||||
{
|
{
|
||||||
m_blueprintGhostTile = tile;
|
m_blueprintGhostTile = tile;
|
||||||
}
|
}
|
||||||
else if (m_demolishMode)
|
else if (m_deconstructMode)
|
||||||
{
|
{
|
||||||
m_demolishHoverBuildingId = buildingAtTile(tile);
|
m_deconstructHoverBuildingId = buildingAtTile(tile);
|
||||||
if (m_boxSelecting) { m_boxCurrentTile = tile; }
|
if (m_boxSelecting) { m_boxCurrentTile = tile; }
|
||||||
}
|
}
|
||||||
else if (m_boxSelecting)
|
else if (m_boxSelecting)
|
||||||
@@ -2632,12 +2632,12 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
|
|||||||
const std::vector<BuildingId> boxIds =
|
const std::vector<BuildingId> boxIds =
|
||||||
buildingsInBox(m_boxStartTile, m_boxCurrentTile);
|
buildingsInBox(m_boxStartTile, m_boxCurrentTile);
|
||||||
|
|
||||||
if (m_demolishMode)
|
if (m_deconstructMode)
|
||||||
{
|
{
|
||||||
const BuildingSystem& buildings = m_sim->getBuildings();
|
const BuildingSystem& buildings = m_sim->getBuildings();
|
||||||
|
|
||||||
// Split covered ids into construction sites (removed instantly) and
|
// Split covered ids into construction sites (removed instantly) and
|
||||||
// operational demolishable buildings (the HQ is protected; player
|
// operational deconstructible buildings (the HQ is protected; player
|
||||||
// defence stations are not Buildings and never appear in the box).
|
// defence stations are not Buildings and never appear in the box).
|
||||||
std::vector<BuildingId> sites;
|
std::vector<BuildingId> sites;
|
||||||
std::vector<BuildingId> operational;
|
std::vector<BuildingId> operational;
|
||||||
@@ -2654,11 +2654,11 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sites: instant demolition with the full refund (REQ-BLD-DEMOLISH).
|
// Sites: instant demolition with the full refund (REQ-BLD-DECONSTRUCT).
|
||||||
for (BuildingId id : sites)
|
for (BuildingId id : sites)
|
||||||
{
|
{
|
||||||
std::shared_ptr<DemolishCommand> command =
|
std::shared_ptr<DeconstructCommand> command =
|
||||||
std::make_shared<DemolishCommand>();
|
std::make_shared<DeconstructCommand>();
|
||||||
command->id = id;
|
command->id = id;
|
||||||
enqueueCommand(command);
|
enqueueCommand(command);
|
||||||
}
|
}
|
||||||
@@ -2666,7 +2666,7 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
|
|||||||
// Operational buildings: if every covered one is already queued,
|
// Operational buildings: if every covered one is already queued,
|
||||||
// un-queue them all; otherwise queue each one not yet queued. A plain
|
// un-queue them all; otherwise queue each one not yet queued. A plain
|
||||||
// click is the one-element case, giving the queue/un-queue toggle
|
// click is the one-element case, giving the queue/un-queue toggle
|
||||||
// (REQ-BLD-DEMOLISH-BOX, REQ-BLD-DEMOLISH-CLICK).
|
// (REQ-BLD-DECONSTRUCT-BOX, REQ-BLD-DECONSTRUCT-CLICK).
|
||||||
bool allQueued = !operational.empty();
|
bool allQueued = !operational.empty();
|
||||||
for (BuildingId id : operational)
|
for (BuildingId id : operational)
|
||||||
{
|
{
|
||||||
@@ -2683,14 +2683,14 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
|
|||||||
}
|
}
|
||||||
else if (!buildings.isQueuedForDeconstruction(id))
|
else if (!buildings.isQueuedForDeconstruction(id))
|
||||||
{
|
{
|
||||||
std::shared_ptr<DemolishCommand> command =
|
std::shared_ptr<DeconstructCommand> command =
|
||||||
std::make_shared<DemolishCommand>();
|
std::make_shared<DeconstructCommand>();
|
||||||
command->id = id;
|
command->id = id;
|
||||||
enqueueCommand(command);
|
enqueueCommand(command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_demolishHoverBuildingId = std::nullopt;
|
m_deconstructHoverBuildingId = std::nullopt;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2786,21 +2786,21 @@ void GameWorldView::mouseReleaseEvent(QMouseEvent* event)
|
|||||||
// Methods (formerly slots)
|
// Methods (formerly slots)
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
void GameWorldView::toggleDemolishMode()
|
void GameWorldView::toggleDeconstructMode()
|
||||||
{
|
{
|
||||||
if (m_demolishMode)
|
if (m_deconstructMode)
|
||||||
{
|
{
|
||||||
m_demolishMode = false;
|
m_deconstructMode = false;
|
||||||
m_demolishHoverBuildingId = std::nullopt;
|
m_deconstructHoverBuildingId = std::nullopt;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_builderType.has_value()) { exitBuilderMode(); }
|
if (m_builderType.has_value()) { exitBuilderMode(); }
|
||||||
if (m_blueprintMode.has_value()) { exitBlueprintMode(); }
|
if (m_blueprintMode.has_value()) { exitBlueprintMode(); }
|
||||||
m_demolishMode = true;
|
m_deconstructMode = true;
|
||||||
}
|
}
|
||||||
EventManager::getInstance()->sendEventImmediately(
|
EventManager::getInstance()->sendEventImmediately(
|
||||||
std::make_shared<DemolishModeChangedEvent>(m_demolishMode));
|
std::make_shared<DeconstructModeChangedEvent>(m_deconstructMode));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameWorldView::rotateGhost(bool clockwise)
|
void GameWorldView::rotateGhost(bool clockwise)
|
||||||
@@ -2931,18 +2931,18 @@ void GameWorldView::enterBuilderMode(BuildingType type)
|
|||||||
m_ghostValid = false;
|
m_ghostValid = false;
|
||||||
m_tunnelGhostType = BuildingType::TunnelEntry;
|
m_tunnelGhostType = BuildingType::TunnelEntry;
|
||||||
m_tunnelPartnerTile.reset();
|
m_tunnelPartnerTile.reset();
|
||||||
m_demolishMode = false;
|
m_deconstructMode = false;
|
||||||
m_blueprintMode.reset();
|
m_blueprintMode.reset();
|
||||||
EventManager::getInstance()->sendEventImmediately(
|
EventManager::getInstance()->sendEventImmediately(
|
||||||
std::make_shared<DemolishModeChangedEvent>(false));
|
std::make_shared<DeconstructModeChangedEvent>(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameWorldView::enterBlueprintMode(Blueprint blueprint)
|
void GameWorldView::enterBlueprintMode(Blueprint blueprint)
|
||||||
{
|
{
|
||||||
if (m_builderType.has_value()) { exitBuilderMode(); }
|
if (m_builderType.has_value()) { exitBuilderMode(); }
|
||||||
m_demolishMode = false;
|
m_deconstructMode = false;
|
||||||
EventManager::getInstance()->sendEventImmediately(
|
EventManager::getInstance()->sendEventImmediately(
|
||||||
std::make_shared<DemolishModeChangedEvent>(false));
|
std::make_shared<DeconstructModeChangedEvent>(false));
|
||||||
m_blueprintGhostTile = m_ghostTile;
|
m_blueprintGhostTile = m_ghostTile;
|
||||||
m_blueprintMode = std::move(blueprint);
|
m_blueprintMode = std::move(blueprint);
|
||||||
}
|
}
|
||||||
@@ -2993,10 +2993,10 @@ void GameWorldView::resetForNewGame()
|
|||||||
m_schematicChoiceShown = false;
|
m_schematicChoiceShown = false;
|
||||||
m_ghostRotation = Rotation::East;
|
m_ghostRotation = Rotation::East;
|
||||||
m_ghostValid = false;
|
m_ghostValid = false;
|
||||||
m_demolishMode = false;
|
m_deconstructMode = false;
|
||||||
m_demolishHoverBuildingId = std::nullopt;
|
m_deconstructHoverBuildingId = std::nullopt;
|
||||||
EventManager::getInstance()->sendEventImmediately(
|
EventManager::getInstance()->sendEventImmediately(
|
||||||
std::make_shared<DemolishModeChangedEvent>(false));
|
std::make_shared<DeconstructModeChangedEvent>(false));
|
||||||
m_selectedBuildingIds.clear();
|
m_selectedBuildingIds.clear();
|
||||||
clearEntitySelection();
|
clearEntitySelection();
|
||||||
clearScrapSelection();
|
clearScrapSelection();
|
||||||
@@ -3072,9 +3072,9 @@ void GameWorldView::handleEvent(std::shared_ptr<const ExitBuilderModeRequestedEv
|
|||||||
exitBuilderMode();
|
exitBuilderMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameWorldView::handleEvent(std::shared_ptr<const DemolishModeToggleRequestedEvent> /*event*/)
|
void GameWorldView::handleEvent(std::shared_ptr<const DeconstructModeToggleRequestedEvent> /*event*/)
|
||||||
{
|
{
|
||||||
toggleDemolishMode();
|
toggleDeconstructMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameWorldView::handleEvent(std::shared_ptr<const BlueprintPlacementRequestedEvent> event)
|
void GameWorldView::handleEvent(std::shared_ptr<const BlueprintPlacementRequestedEvent> event)
|
||||||
|
|||||||
@@ -23,8 +23,8 @@
|
|||||||
#include "BuildingType.h"
|
#include "BuildingType.h"
|
||||||
#include "BuildingTypeSelectedEvent.h"
|
#include "BuildingTypeSelectedEvent.h"
|
||||||
#include "BuildingId.h"
|
#include "BuildingId.h"
|
||||||
#include "DemolishModeChangedEvent.h"
|
#include "DeconstructModeChangedEvent.h"
|
||||||
#include "DemolishModeToggleRequestedEvent.h"
|
#include "DeconstructModeToggleRequestedEvent.h"
|
||||||
#include "EventHandler.h"
|
#include "EventHandler.h"
|
||||||
#include "ExitBlueprintModeRequestedEvent.h"
|
#include "ExitBlueprintModeRequestedEvent.h"
|
||||||
#include "ExitBuilderModeRequestedEvent.h"
|
#include "ExitBuilderModeRequestedEvent.h"
|
||||||
@@ -66,7 +66,7 @@ class GameWorldView : public QOpenGLWidget,
|
|||||||
public CombinedEventHandler<BeamFiredEvent,
|
public CombinedEventHandler<BeamFiredEvent,
|
||||||
BuildingTypeSelectedEvent,
|
BuildingTypeSelectedEvent,
|
||||||
ExitBuilderModeRequestedEvent,
|
ExitBuilderModeRequestedEvent,
|
||||||
DemolishModeToggleRequestedEvent,
|
DeconstructModeToggleRequestedEvent,
|
||||||
BlueprintPlacementRequestedEvent,
|
BlueprintPlacementRequestedEvent,
|
||||||
ExitBlueprintModeRequestedEvent,
|
ExitBlueprintModeRequestedEvent,
|
||||||
SpeedChangeRequestedEvent,
|
SpeedChangeRequestedEvent,
|
||||||
@@ -102,7 +102,7 @@ private:
|
|||||||
void handleEvent(std::shared_ptr<const BeamFiredEvent> event) override;
|
void handleEvent(std::shared_ptr<const BeamFiredEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const BuildingTypeSelectedEvent> event) override;
|
void handleEvent(std::shared_ptr<const BuildingTypeSelectedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const ExitBuilderModeRequestedEvent> event) override;
|
void handleEvent(std::shared_ptr<const ExitBuilderModeRequestedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const DemolishModeToggleRequestedEvent> event) override;
|
void handleEvent(std::shared_ptr<const DeconstructModeToggleRequestedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const BlueprintPlacementRequestedEvent> event) override;
|
void handleEvent(std::shared_ptr<const BlueprintPlacementRequestedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const ExitBlueprintModeRequestedEvent> event) override;
|
void handleEvent(std::shared_ptr<const ExitBlueprintModeRequestedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const SpeedChangeRequestedEvent> event) override;
|
void handleEvent(std::shared_ptr<const SpeedChangeRequestedEvent> event) override;
|
||||||
@@ -139,11 +139,11 @@ private:
|
|||||||
// to make the paused state hard to miss: a black frame whose alpha fades from 50% at
|
// to make the paused state hard to miss: a black frame whose alpha fades from 50% at
|
||||||
// the viewport edges to 0% toward the center.
|
// the viewport edges to 0% toward the center.
|
||||||
void drawPauseBorder(QPainter& painter);
|
void drawPauseBorder(QPainter& painter);
|
||||||
// Vignette-style border shown while demolish mode is active (REQ-UI-DEMOLISH-BORDER),
|
// Vignette-style border shown while deconstruct mode is active (REQ-UI-DECONSTRUCT-BORDER),
|
||||||
// tinted with the demolish overlay color (including its configured alpha) from
|
// tinted with the deconstruct overlay color (including its configured alpha) from
|
||||||
// visuals.toml instead of black.
|
// visuals.toml instead of black.
|
||||||
void drawDemolishBorder(QPainter& painter);
|
void drawDeconstructBorder(QPainter& painter);
|
||||||
// Shared drawing for the pause/demolish vignettes: a mitred picture-frame border
|
// Shared drawing for the pause/deconstruct vignettes: a mitred picture-frame border
|
||||||
// whose alpha fades from `edgeColor` (with its own alpha) at the viewport edge to
|
// whose alpha fades from `edgeColor` (with its own alpha) at the viewport edge to
|
||||||
// fully transparent toward the center.
|
// fully transparent toward the center.
|
||||||
void drawVignetteBorder(QPainter& painter, const QColor& edgeColor);
|
void drawVignetteBorder(QPainter& painter, const QColor& edgeColor);
|
||||||
@@ -252,7 +252,7 @@ private:
|
|||||||
void exitBuilderMode();
|
void exitBuilderMode();
|
||||||
void enterBlueprintMode(Blueprint blueprint);
|
void enterBlueprintMode(Blueprint blueprint);
|
||||||
void exitBlueprintMode();
|
void exitBlueprintMode();
|
||||||
void toggleDemolishMode();
|
void toggleDeconstructMode();
|
||||||
void rotateGhost(bool clockwise);
|
void rotateGhost(bool clockwise);
|
||||||
|
|
||||||
struct ActiveBeam
|
struct ActiveBeam
|
||||||
@@ -328,8 +328,8 @@ private:
|
|||||||
std::vector<CopyConfigFlash> m_copyConfigFlashes;
|
std::vector<CopyConfigFlash> m_copyConfigFlashes;
|
||||||
static constexpr qint64 kCopyFlashDurationMs = 300;
|
static constexpr qint64 kCopyFlashDurationMs = 300;
|
||||||
|
|
||||||
bool m_demolishMode;
|
bool m_deconstructMode;
|
||||||
std::optional<BuildingId> m_demolishHoverBuildingId;
|
std::optional<BuildingId> m_deconstructHoverBuildingId;
|
||||||
bool m_debugDraw;
|
bool m_debugDraw;
|
||||||
|
|
||||||
std::vector<BuildingId> m_selectedBuildingIds;
|
std::vector<BuildingId> m_selectedBuildingIds;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ struct OverlayVisuals
|
|||||||
{
|
{
|
||||||
QColor ghostValid;
|
QColor ghostValid;
|
||||||
QColor ghostInvalid;
|
QColor ghostInvalid;
|
||||||
QColor demolishTint;
|
QColor deconstructTint;
|
||||||
QColor selectionRect;
|
QColor selectionRect;
|
||||||
QColor tileHighlight;
|
QColor tileHighlight;
|
||||||
QColor selectedOutline;
|
QColor selectedOutline;
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ VisualsConfig VisualsLoader::load(const std::string& path)
|
|||||||
toml::table& ov = requireSubtable(tbl, "overlays", "root");
|
toml::table& ov = requireSubtable(tbl, "overlays", "root");
|
||||||
cfg.overlays.ghostValid = parseColor(requireString(ov, "ghost_valid", "overlays"), "overlays.ghost_valid");
|
cfg.overlays.ghostValid = parseColor(requireString(ov, "ghost_valid", "overlays"), "overlays.ghost_valid");
|
||||||
cfg.overlays.ghostInvalid = parseColor(requireString(ov, "ghost_invalid", "overlays"), "overlays.ghost_invalid");
|
cfg.overlays.ghostInvalid = parseColor(requireString(ov, "ghost_invalid", "overlays"), "overlays.ghost_invalid");
|
||||||
cfg.overlays.demolishTint = parseColor(requireString(ov, "demolish_tint", "overlays"), "overlays.demolish_tint");
|
cfg.overlays.deconstructTint = parseColor(requireString(ov, "deconstruct_tint", "overlays"), "overlays.deconstruct_tint");
|
||||||
cfg.overlays.selectionRect = parseColor(requireString(ov, "selection_rect", "overlays"), "overlays.selection_rect");
|
cfg.overlays.selectionRect = parseColor(requireString(ov, "selection_rect", "overlays"), "overlays.selection_rect");
|
||||||
cfg.overlays.tileHighlight = parseColor(requireString(ov, "tile_highlight", "overlays"), "overlays.tile_highlight");
|
cfg.overlays.tileHighlight = parseColor(requireString(ov, "tile_highlight", "overlays"), "overlays.tile_highlight");
|
||||||
cfg.overlays.selectedOutline = parseColor(requireString(ov, "selected_outline", "overlays"), "overlays.selected_outline");
|
cfg.overlays.selectedOutline = parseColor(requireString(ov, "selected_outline", "overlays"), "overlays.selected_outline");
|
||||||
|
|||||||
Reference in New Issue
Block a user