Building footprints need an entrance #62

Merged
liamjd merged 4 commits from 55-footprint-entrance into main 2026-09-05 08:58:17 +01:00
Owner

Adds a mandatory entrance to BuildingFootprint, authored as an ASCII arrow in the shape string.

The grammar

On top of X / . / @, a shape now carries exactly one of < > ^ v (case-insensitive, so V works). The arrow's own tile is the doorstep — the unoccupied tile a pawn stands on — and the direction it faces must land on an occupied tile.

XX@XX      >@x      XvX
XX^XX               X@X

Two new accessors, both anchor-relative offsets like cells():

  • doorstep(steps) — the arrow's tile, rotated. Never in cells().
  • entrance_direction(steps) — the unit vector the arrow points in, rotated.
  • doorstep(s) + entrance_direction(s) is always a cell in rotated(s).

Decisions

  • The entrance is mandatory. A shape with no arrow is rejected exactly as one with no @ is. A lone "@" was the smallest legal footprint under #36 and no longer parses — pinned by a test so the contract change is deliberate.
  • Direction is a Vector2i, not an N/E/S/W enum, and turns through the same rotate_offset() the cells use. rotate_offset() is now a static, so there is one rotation implementation rather than two that have to agree — and a test asserts rotated() is that static mapped over every cell.
  • Rejected at parse time with a single push_error and cells() left empty: no arrow, more than one arrow, arrow pointing at an empty tile, arrow pointing off the grid. Each rejection has its own message.
  • Rows are padded at the end only, so an arrow at the start of a row shifts that row right. All authored shapes account for this.

Changes

  • BuildingFootprint.gd — parse, validate, rotate and expose the entrance.
  • All seven authored footprint .tres files gain an arrow.
  • test_building_footprint_entrance.gd — new, 40-odd tests: parsing per shape and per arrow character, the doorstep-outside/entrance-inside properties held across all four rotations, rotate_offset semantics (zero, wrap, negative), the five rejection cases, a save/load round trip, and a catalogue test asserting every authored .tres has a usable entrance.
  • Existing footprint/site/mesh/placement tests updated for shapes that now need an arrow.

Verification

Full GUT suite green: 173/173, 1046 asserts, no orphans.

Not covered: nothing visual. The doorstep is data only at this point — rendering it is #61, and gl_compatibility draws nothing headless anyway.

Follow-ups

  • #61 — rendering the entrance.
  • test_building_footprint_entrance.gd is deliberately a separate file (a call to a not-yet-existing method is a parse error in GDScript, which would have taken every #36 test down with it). Now that the API exists it could be merged into test_building_footprint.gd; left as-is here to keep the diff readable.

Closes #55

🤖 Generated with Claude Code

https://claude.ai/code/session_01DtdF9mqzKi95DHBn9Et1pz

Adds a mandatory entrance to `BuildingFootprint`, authored as an ASCII arrow in the shape string. ## The grammar On top of `X` / `.` / `@`, a shape now carries exactly one of `< > ^ v` (case-insensitive, so `V` works). The arrow's own tile is the **doorstep** — the unoccupied tile a pawn stands on — and the direction it faces must land on an occupied tile. ``` XX@XX >@x XvX XX^XX X@X ``` Two new accessors, both anchor-relative offsets like `cells()`: - `doorstep(steps)` — the arrow's tile, rotated. Never in `cells()`. - `entrance_direction(steps)` — the unit vector the arrow points in, rotated. - `doorstep(s) + entrance_direction(s)` is always a cell in `rotated(s)`. ## Decisions - **The entrance is mandatory.** A shape with no arrow is rejected exactly as one with no `@` is. A lone `"@"` was the smallest legal footprint under #36 and no longer parses — pinned by a test so the contract change is deliberate. - **Direction is a `Vector2i`, not an N/E/S/W enum**, and turns through the same `rotate_offset()` the cells use. `rotate_offset()` is now a static, so there is one rotation implementation rather than two that have to agree — and a test asserts `rotated()` *is* that static mapped over every cell. - **Rejected at parse time** with a single `push_error` and `cells()` left empty: no arrow, more than one arrow, arrow pointing at an empty tile, arrow pointing off the grid. Each rejection has its own message. - Rows are padded at the end only, so an arrow at the start of a row shifts that row right. All authored shapes account for this. ## Changes - `BuildingFootprint.gd` — parse, validate, rotate and expose the entrance. - All seven authored footprint `.tres` files gain an arrow. - `test_building_footprint_entrance.gd` — new, 40-odd tests: parsing per shape and per arrow character, the doorstep-outside/entrance-inside properties held across all four rotations, `rotate_offset` semantics (zero, wrap, negative), the five rejection cases, a save/load round trip, and a catalogue test asserting every authored `.tres` has a usable entrance. - Existing footprint/site/mesh/placement tests updated for shapes that now need an arrow. ## Verification Full GUT suite green: **173/173, 1046 asserts**, no orphans. Not covered: nothing visual. The doorstep is data only at this point — rendering it is #61, and `gl_compatibility` draws nothing headless anyway. ## Follow-ups - #61 — rendering the entrance. - `test_building_footprint_entrance.gd` is deliberately a separate file (a call to a not-yet-existing method is a *parse* error in GDScript, which would have taken every #36 test down with it). Now that the API exists it could be merged into `test_building_footprint.gd`; left as-is here to keep the diff readable. Closes #55 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01DtdF9mqzKi95DHBn9Et1pz
- Correct `_find_entrance_cell` to return `Vector2i.MIN` for no doorstep and `Vector2i.MAX` for multiples.
- Refine doorstep rejection checks with improved error messages.
- Simplify entrance direction calculation and ensure proper resetting of `_entrance_direction` on failures.
- Optimize `_find_rotate_point` and `_parse_shape_vertices` with cleaner iteration.
- Remove redundant debug prints.
liamjd merged commit 7c89580412 into main 2026-09-05 08:58:17 +01:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
liamjd/UntitledColonyBuilder!62
No description provided.