Skip to content

Reveal cells the party sees by torchlight in the player view (release 1.2.1)#28

Merged
mmacy merged 4 commits into
mainfrom
fix-torchlight-viewport-reveal
Jul 21, 2026
Merged

Reveal cells the party sees by torchlight in the player view (release 1.2.1)#28
mmacy merged 4 commits into
mainfrom
fix-torchlight-viewport-reveal

Conversation

@mmacy

@mmacy mmacy commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Problem

The dungeon viewport (and automap) render only the cells carried by the player-view projection, and that projection equated visible with explored — the cells the party had physically stepped on. A lit torch therefore changed nothing on screen: every open square around the party stayed a black "void" until a footstep marked it explored. The client can't fix this itself — the projection deliberately withholds unexplored geometry, so it never receives the walls/doors of the surrounding room to draw.

Reported against the osr-web front end as: "Light doesn't reveal open grid squares in the viewport; party must move to the open square to 'uncover' it even with a lit torch."

Fix

Compute what the party actually sees by its own light at view-build time and fold those cells into the current level's projection (src/osrlib/crawl/views.py):

  • _light_reveal floods outward from the party's cell through open passages (and open, non-secret doors), bounded by the light's radius in cells (30 ft = 3 cells at the classic 10-ft square), and includes the whole keyed room the party stands in. Walls and shut/undiscovered doors stop it.
  • _explored_levels unions the seen cells into the current level, so the client draws the lit room and corridors with no client change.

This is sight, not exploration: revealed cells never enter the persisted explored set, so movement cost (30 for a new cell, 10 for a walked one) and map persistence are untouched. Visibility recomputes on every view, so lighting a torch while standing still reveals the room immediately.

Tests

Adds TestLightReveal in tests/test_exploration.py:

  • reveals the open cells ahead without moving (and asserts they stay unexplored)
  • an unlit party sees only where it has walked
  • torchlight stops at a closed door
  • torchlight reveals the whole room it stands in

Full suite: 1539 passed, 58 skipped (goldens unaffected — this is projection-only). Verified end-to-end against the osr-web app: same seed and entrance, no movement — dark before lighting, full room after.

https://claude.ai/code/session_016qNYjfiRqHJFxHYbwFEEX9

mmacy added 2 commits July 20, 2026 17:14
The dungeon viewport and automap render only the cells carried by the
player-view projection, which equated "visible" with "explored" — the
cells the party had physically stepped on. A lit torch therefore changed
nothing: every open square around the party stayed a black void until a
footstep marked it explored. The client cannot fix this itself; the
projection deliberately withholds unexplored geometry, so it never has
the walls or doors of the surrounding room to draw.

Compute what the party actually sees by its own light at view-build time
and fold those cells into the current level's projection:

- `_light_reveal` floods outward from the party's cell through open
  passages (and open, non-secret doors), bounded by the light's radius in
  cells, and includes the whole keyed room the party stands in. Walls and
  shut or undiscovered doors stop it.
- `_explored_levels` unions the seen cells into the current level so the
  client draws the room and lit corridors with no client change.

This is sight, not exploration: seen cells never enter the persisted
explored set, so movement cost (30 for a new cell, 10 for a walked one)
and map persistence are untouched. Visibility recomputes every view, so
lighting a torch while standing still reveals the room immediately.

Adds TestLightReveal: reveal-ahead-without-moving, unlit-shows-only-
footprints, light-stops-at-a-closed-door, and whole-room reveal.

Claude-Session: https://claude.ai/code/session_016qNYjfiRqHJFxHYbwFEEX9
Two findings from an adversarial review of the torchlight reveal:

- The *light* spell family stores its radius under `radius_feet`, while
  equipment and magic items use `light_radius_feet`. `_light_reveal` read
  only the latter, so a party lit by a 15-foot *light* spell fell back to
  the 30-foot default and over-revealed corridor geometry. Add
  `_light_radius_feet`, which reads whichever key the source carries.

- The whole-room reveal unioned every cell of the party's keyed area
  unconditionally, bypassing the `_sight_passes` gate. No shipped content
  authors a room split by an internal door, but an alcove behind a closed
  or secret door would have leaked. Fold the room reveal into the
  sight-gated flood (admit a neighbour within the light's reach *or* in the
  party's own room, but only across an edge sight actually crosses), so a
  sealed-off alcove stays dark while the open room still lights whole.

Adds regression tests: undiscovered secret door stays a wall under light,
the *light*-spell radius reveals less than a torch, seeing a cell by light
doesn't change its movement cost, the reveal doesn't bleed into another
level, and it never enters the referee view.

Claude-Session: https://claude.ai/code/session_016qNYjfiRqHJFxHYbwFEEX9
@mmacy

mmacy commented Jul 21, 2026

Copy link
Copy Markdown
Owner Author

Adversarial review round

Ran a rubber-duck (adversarial) review of the change. Two substantive findings, both now fixed in c8433b3:

  • Radius param mismatch (major). _light_reveal read the light radius only from light_radius_feet, but the light spell family stores it under radius_feet (equipment/magic-items use light_radius_feet). A party lit by the 15-ft light spell fell back to the 30-ft default and over-revealed corridor geometry. Fixed with _light_radius_feet, which reads whichever key the source carries.
  • Whole-room reveal bypassed the sight gate (minor/latent). The reveal unioned the party's keyed-area cells unconditionally, skipping _sight_passes. No shipped content authors a room split by an internal door, but an alcove behind a closed/secret door would have leaked. Folded the room reveal into the sight-gated flood — a sealed-off alcove now stays dark while the open room still lights whole.

Things the review tried and failed to break (verified safe): secret doors never leak and never render as anything but wall; movement economy is untouched (a light-revealed cell still costs the full 30 to enter); multi-level/multi-dungeon isolation holds; and the reveal never reaches the referee view, saves, or events.

New regression tests cover all of the above. Full suite: 1544 passed, 58 skipped.

mmacy added 2 commits July 20, 2026 17:45
Per the release process, a PR that changes user-visible behavior records
its bullet under [Unreleased] in the same PR.

Claude-Session: https://claude.ai/code/session_016qNYjfiRqHJFxHYbwFEEX9
Bump the version and cut the [1.2.1] changelog section (the torchlight
reveal fix). Patch release: backward-compatible bug fix, public API
surface and schema_version unchanged.

Local dry run green: full gate, uv build, check_dist, and a fresh-venv
install_smoke all pass for 1.2.1; goldens keep their engine stamp (no
regeneration).

Claude-Session: https://claude.ai/code/session_016qNYjfiRqHJFxHYbwFEEX9
@mmacy mmacy changed the title Reveal cells the party sees by torchlight in the player view Reveal cells the party sees by torchlight in the player view (release 1.2.1) Jul 21, 2026
@mmacy

mmacy commented Jul 21, 2026

Copy link
Copy Markdown
Owner Author

Cut as release 1.2.1

Made this the release PR (patch — backward-compatible bug fix; public API surface and schema_version unchanged):

  • pyproject.toml1.2.1, uv lock re-run.
  • CHANGELOG.md: [Unreleased] renamed to [1.2.1] - 2026-07-20, fresh empty [Unreleased] kept on top, compare links updated.

Local release dry run — all green for 1.2.1:

  • full test gate: 1544 passed, 58 skipped (goldens keep their engine stamp — no regeneration)
  • uv build → clean wheel + sdist
  • tools/release/check_dist.py dist 1.2.1 → passed
  • fresh-venv install + tools/release/install_smoke.py 1.2.1 → passed

Remaining (post-merge, per AGENTS.md): after this merges, an annotated v1.2.1 tag on the merge commit triggers release.yml → PyPI publish. That step is intentionally not done here.

@mmacy
mmacy merged commit 7115b17 into main Jul 21, 2026
5 checks passed
@mmacy
mmacy deleted the fix-torchlight-viewport-reveal branch July 21, 2026 00:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant