Skip to content

Open every bunker you have already beaten: raids - #200

Merged
0xward merged 1 commit into
mainfrom
claude/nullstate-onchain-text-q6g2a3
Jul 30, 2026
Merged

Open every bunker you have already beaten: raids#200
0xward merged 1 commit into
mainfrom
claude/nullstate-onchain-text-q6g2a3

Conversation

@0xward

@0xward 0xward commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Build-order item #2 from GAME-DESIGN.md. No contract changes — engine, shell and localStorage only.

What this is

The world map has been drawing a ✓ on cleared bunkers and then refusing to let anyone back in. WorldMapHub.tsx said so in its own comment: re-entering "would need an engine entry point that doesn't exist yet."

This is that entry point. With it the map stops being a progress bar and starts being the game — which is what §2 committed to.

A raid is a fresh descent into a bunker you have beaten:

  • Costs 1 energy, same as a first descent
  • No story replay, no tutorial, no campaign advance
  • Loot, Glitch Shards, XP, kills and Vault Fragments all count exactly as the first time

Entry routes through the existing outdoor strip, which is why the energy cost needed no new code: onOutdoorReachedDoor already owns the spend, the retreat-from-the-door when a wallet is out of runs, and the refill modal.

Three ways this could have wrecked a player's campaign

All found while building it, all closed.

1. Progress regression. The map read currentAct straight off the saved session's campaignActIndex — fine while those were the same number. A raid breaks that: the in-run autosave persists the raided act, so a player who had cleared all five and went to farm the first would have come back to a map with bunkers 3–5 locked.

Progress is now its own monotonic high-water mark (lib/campaignProgress.ts), seeded from the existing save on first read so nobody loses anything.

2. Save deletion. DungeonGame's Continue branch consumes the session it loads. A raid entered with isNewRun: false would have gone down that branch and silently deleted the campaign the player was midway through. Raids now touch neither load nor clear.

3. Lost floor position. A raid shares the same session document, so farming Bunker 1 would have reset a Bunker 3 run to floor 1 — every item and level kept, three floors to walk again, which reads as the game losing your place. The campaign's act and depth are stashed on the way in and restored on the way out, in localStorage rather than a React ref so it survives a save-and-exit mid-raid.

Plus: a raid saved mid-run carries raid: true and resumes as a raid. Without it the resumed run would clear as a campaign bunker and advance the act off the raid's index, quietly moving the resume point to a bunker already beaten.

Verification

Progress record checked against a stubbed localStorage — all passed:

✓ seeds from the session on first read     ✓ a raid on bunker 1 cannot lower it
✓ recordHighestAct never lowers            ✓ clamped to maxAct
✓ another wallet is independent            ✓ address casing does not split the record
✓ resume returns the exact floor the raid interrupted
✓ resume is consumed — a second raid cannot replay it

Plus: tsc --noEmit clean · next build passes · lint 34 errors, unchanged from main · engine parses and minifies · check:market, audit, check:copy all pass.

Not verified — this is the part that wants a real play-through: the raid entry itself end-to-end (map → outdoor → energy → bunker → clear → back to map), and specifically that a mid-campaign player's floor position really does come back after a raid. I can reason about it from the code but I cannot play it from here.


Generated by Claude Code

The world map has been drawing a ✓ on cleared bunkers and then refusing to
let anyone back in. WorldMapHub said so in its own comment — re-entering
"would need an engine entry point that doesn't exist yet". This is that
entry point, and with it the map stops being a progress bar and starts
being the game, which is what GAME-DESIGN.md §2 committed to.

A raid is a fresh descent into a bunker you have beaten. It costs one
energy, it does not replay the story, it does not show the tutorial, and
it does not advance the campaign. Everything it earns — loot, shards, XP,
kills, vault fragments — counts exactly as it would the first time.

Entry goes through the outdoor strip rather than dropping straight into
the bunker, which is the whole reason the energy cost needed no new code:
onOutdoorReachedDoor already owns the spend, the retreat-from-the-door
when a wallet is out of runs, and the refill modal.

Three ways this could have wrecked a player's campaign, found while
building it and all closed:

Progress regression. The map read currentAct straight off the saved
session's campaignActIndex, which used to be the same number as "furthest
bunker reached". A raid breaks that equality: the in-run autosave persists
the raided act, so a player who had cleared all five and went to farm the
first would have come back to a map with bunkers 3-5 locked. Progress is
now its own monotonic record, seeded from the save on first read so
existing players lose nothing.

Save deletion. DungeonGame's Continue branch CONSUMES the session it
loads. A raid entered with isNewRun false would have gone down that
branch and silently deleted the campaign the player was midway through.
Raids now touch neither load nor clear.

Lost floor position. A raid shares the same session document, so farming
Bunker 1 would have reset a Bunker 3 run to floor 1 — every item and level
kept, three floors to walk again, which reads as the game losing your
place. The campaign's act and depth are stashed on the way in and put back
on the way out, in localStorage rather than a React ref so it survives a
save-and-exit mid-raid.

A raid saved mid-run carries raid:true and resumes as a raid. Without it
the resumed run would clear as a campaign bunker and advance the act off
the raid's index, quietly moving the resume point to a bunker already
beaten.

Verified the progress record against a stubbed localStorage: seeded from
an existing save, never lowered by a raid, clamped, wallet-isolated,
case-insensitive, and the resume stash consumed exactly once.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
nullstate Ready Ready Preview Jul 30, 2026 5:01pm

@0xward
0xward merged commit 8af60c3 into main Jul 30, 2026
5 checks passed
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