[priority: highest] Entering the Spire with "Climb the Spire" crashes the game #175

Closed
opened 2026-05-28 11:39:12 +02:00 by Anexim · 2 comments
Owner

Description

When the player clicks "Climb the Spire" (in LeftPanel.tsx or SpireSummaryTab.tsx), the game crashes/returns to the main view immediately instead of entering Spire Mode.

Root Cause

The enterSpireMode() action in src/lib/game/stores/combatStore.ts (lines 200–211) sets spireMode: true but does NOT set currentAction: 'climb'. The SpireCombatPage useEffect sets it asynchronously, creating a render window where child components (SpireHeader, RoomDisplay, SpireCombatControls, etc.) may access uninitialized state. The ErrorBoundary in page.tsx (lines 188–194) catches the resulting render error and calls exitSpireMode(), which snaps the player back to the main game view — appearing as a "crash".

Additionally, enterSpireMode() calls generateFloorState(1) which may return a legacy FloorState shape incompatible with the spire-specific state expected by SpireCombatPage components.

Affected Files

  • src/lib/game/stores/combatStore.ts lines 200–211 — enterSpireMode() missing currentAction: 'climb'
  • src/components/game/tabs/SpireCombatPage/SpireCombatPage.tsx lines 109–113 — useEffect sets action async
  • src/app/page.tsx lines 188–194 — ErrorBoundary catches render error and resets

Reproduction

  1. Start a new game
  2. Click "Climb the Spire"
  3. Game immediately bounces back to the main view

Expected Behavior

Player enters Spire Mode and sees the combat interface.

## Description When the player clicks "Climb the Spire" (in `LeftPanel.tsx` or `SpireSummaryTab.tsx`), the game crashes/returns to the main view immediately instead of entering Spire Mode. ## Root Cause The `enterSpireMode()` action in `src/lib/game/stores/combatStore.ts` (lines 200–211) sets `spireMode: true` but does **NOT** set `currentAction: 'climb'`. The `SpireCombatPage` `useEffect` sets it asynchronously, creating a render window where child components (SpireHeader, RoomDisplay, SpireCombatControls, etc.) may access uninitialized state. The `ErrorBoundary` in `page.tsx` (lines 188–194) catches the resulting render error and calls `exitSpireMode()`, which snaps the player back to the main game view — appearing as a "crash". Additionally, `enterSpireMode()` calls `generateFloorState(1)` which may return a legacy `FloorState` shape incompatible with the spire-specific state expected by `SpireCombatPage` components. ## Affected Files - `src/lib/game/stores/combatStore.ts` lines 200–211 — `enterSpireMode()` missing `currentAction: 'climb'` - `src/components/game/tabs/SpireCombatPage/SpireCombatPage.tsx` lines 109–113 — `useEffect` sets action async - `src/app/page.tsx` lines 188–194 — `ErrorBoundary` catches render error and resets ## Reproduction 1. Start a new game 2. Click "Climb the Spire" 3. Game immediately bounces back to the main view ## Expected Behavior Player enters Spire Mode and sees the combat interface.
Anexim added the ai:todo label 2026-05-28 11:39:12 +02:00
n8n-gitea was assigned by Anexim 2026-05-28 11:39:12 +02:00
Author
Owner

Starting work on this issue. The root cause is clear: enterSpireMode() doesn't set currentAction: 'climb', and generateFloorState is used instead of generateSpireFloorState. The useEffect in SpireCombatPage tries to async set the action, but during the render window before the effect fires, child components access uninitialized state (currentAction is 'meditate' instead of 'climb'), causing a render error that the ErrorBoundary catches, calling exitSpireMode() which snaps the player back to the main view.

Starting work on this issue. The root cause is clear: `enterSpireMode()` doesn't set `currentAction: 'climb'`, and `generateFloorState` is used instead of `generateSpireFloorState`. The useEffect in SpireCombatPage tries to async set the action, but during the render window before the effect fires, child components access uninitialized state (currentAction is 'meditate' instead of 'climb'), causing a render error that the ErrorBoundary catches, calling `exitSpireMode()` which snaps the player back to the main view.
Author
Owner

Fixed. Two changes made to src/lib/game/stores/combatStore.ts:

  1. Added import { generateSpireFloorState } from ../utils/spire-utilsenterSpireMode() was using generateFloorState() which returns a generic floor state incompatible with the spire-specific components. Now uses generateSpireFloorState(1, 0, 1).

  2. Added currentAction: 'climb' to the enterSpireMode() set() call — Previously currentAction was left as 'meditate' (the default). The SpireCombatPage useEffect tried to set it async with setAction('climb'), but during the render window before the effect fired, child components accessed uninitialized/inconsistent state, causing a render error that the ErrorBoundary caught, calling exitSpireMode() and snapping the player back to the main view.

Both changes ensure that by the time React renders SpireCombatPage, the store is already in a fully consistent spire-climbing state.

All 52 combat/spire tests pass. No new TypeScript errors introduced.

Fixed. Two changes made to `src/lib/game/stores/combatStore.ts`: 1. **Added `import { generateSpireFloorState }` from `../utils/spire-utils`** — `enterSpireMode()` was using `generateFloorState()` which returns a generic floor state incompatible with the spire-specific components. Now uses `generateSpireFloorState(1, 0, 1)`. 2. **Added `currentAction: 'climb'` to the `enterSpireMode()` set() call** — Previously `currentAction` was left as `'meditate'` (the default). The `SpireCombatPage` useEffect tried to set it async with `setAction('climb')`, but during the render window before the effect fired, child components accessed uninitialized/inconsistent state, causing a render error that the ErrorBoundary caught, calling `exitSpireMode()` and snapping the player back to the main view. Both changes ensure that by the time React renders `SpireCombatPage`, the store is already in a fully consistent spire-climbing state. All 52 combat/spire tests pass. No new TypeScript errors introduced.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Anexim/Mana-Loop#175