Spire descent system is broken: needs multi-room floors, proper descent traversal, and floor reset mechanics #254
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Spire Descent System — Design Spec & Current Gaps
Overview
The spire climbing/descending system has significant gaps between the intended design and the current implementation. This issue documents the expected behavior, what exists today, and what needs to be built.
Expected Behavior
Entering the Spire
getRoomsForFloor()inspire-utils.ts).Room Types
swarm,speed,guardian(every 10th floor),puzzle(every 7th floor),recovery,library,treasure.generateSpireRoomType()inspire-utils.ts.Combat in Rooms
Advancing Through Rooms
Exiting the Spire (Descent)
Floor Reset on Descent
What Currently Exists
✅ What Works
getRoomsForFloor(floor)inspire-utils.ts— returns variable room counts (5–15, scaling with floor). Guardian floors always have 1 room.generateSpireFloorState(floor, roomIndex, totalRooms)inspire-utils.ts— generates a room with proper type and enemies.generateSpireRoomType()— room type selection with proper weights (combat, swarm, speed, guardian, puzzle, recovery, library, treasure).combat-actions.ts— handles spell casting, mana cost, damage application, elemental bonuses, armor, barrier, shield.enterSpireMode()incombatStore.ts— initializes spire state.exitSpireMode()incombatStore.ts— exits spire, resets to floor 1.clearedFloors: Record<number, boolean>— tracks which floors have been cleared (already persisted).climbDirection: 'up' | 'down' | null— state field exists but is never read by combat logic.isDescending: boolean— anti-spam flag exists.SpireCombatPage.tsx— localroomsClearedstate tracks rooms cleared on current floor.combat-utils.tsviagetElementalBonus().❌ What's Broken / Missing
No multi-room traversal in the store: The store only tracks
currentRoom: FloorState(one room per floor). There is nocurrentRoomIndexorroomsPerFloorin the store state. The multi-room infrastructure inspire-utils.tsexists but is not wired into the store tick loop.Combat always advances up:
processCombatTick()incombat-actions.tsalways doescurrentFloor + 1when floor HP reaches 0. It never checksclimbDirection. There is no concept of "room cleared → next room on same floor."climbDownFloor()is broken: It callsgenerateFloorState()(non-spire room generator fromroom-utils.ts) instead ofgenerateSpireFloorState(). It also decrements by exactly 1 floor with no room-by-room descent.No descent traversal logic: There is no system to reverse-traverse all floors/rooms back to Floor 1, Room 0. The
startClimbDown()setsclimbDirection: 'down'but nothing reads it.No floor reset mechanic: The 50% floor reset chance on descent is not implemented anywhere.
handleRoomClearedexists but is never called: InSpireCombatPage.tsx,_handleRoomClearedis defined but has no UI trigger and is not wired to the combat tick. Room clearing must happen through the store tick, but the store doesn't support multi-room floors.SpireHeader.tsx"Exit Spire" button only shows atcurrentFloor === 1, but with broken descent logic, the player can never properly return to Floor 1 Room 0 after climbing.Descended floors use non-spire room generation:
climbDownFloor()→generateFloorState()produces normal rooms without recovery/library/treasure types, which is inconsistent with the spire experience.clearedFloorsis tracked but never used for descent: The field exists and is persisted, but no code reads it to determine whether a descending floor should have enemies or be empty.Files That Need Changes
stores/combatStore.tscurrentRoomIndexandroomsPerFloorstate; fixclimbDownFloor()to use spire generation; add descent traversal actionsstores/combat-state.types.tsstores/combat-actions.tsclimbDirectionbefore advancing floor vs. roomstores/pipelines/combat-tick.tsutils/spire-utils.tsutils/room-utils.tscomponents/game/tabs/SpireCombatPage/SpireCombatPage.tsxhandleRoomClearedto combat tick; track room index in local or store state; handle descent UIcomponents/game/tabs/SpireCombatPage/SpireHeader.tsxKey Formulas (for reference)
5 + min(10, floor/20) + random(0-2)100 + floor × 50 + floor^1.7(non-guardian)min(0.5, (floor-10)*0.01); value =5%–30%10%–30%Related Files (for context)
src/lib/game/utils/spire-utils.ts— multi-room generation infrastructuresrc/lib/game/utils/floor-utils.ts— floor HP, floor elementsrc/lib/game/utils/enemy-utils.ts— enemy namingsrc/lib/game/utils/enemy-generator.ts— modifier-based enemy systemsrc/lib/game/utils/room-utils.ts— legacy single-room generationsrc/lib/game/constants/rooms.ts— room type constantssrc/lib/game/constants/elements.ts— element definitions and oppositessrc/lib/game/utils/combat-utils.ts— damage calculation, elemental bonusessrc/lib/game/stores/combat-actions.ts— combat tick processingsrc/lib/game/stores/pipelines/combat-tick.ts— combat callbackssrc/lib/game/data/guardian-encounters.ts— guardian definitionsContext gathering complete. 6 parallel sub-agents analyzed:\n- All 4 combat store files (combatStore.ts, gameLoopActions.ts, combat-actions.ts, combat-state.types.ts)\n- All 6 spire utility files (spire-utils.ts, room-utils.ts, floor-utils.ts, enemy-utils.ts, enemy-generator.ts, constants/rooms.ts)\n- All 4 combat pipeline files (combat-tick.ts, combat-utils.ts, core.ts, elements.ts)\n- All 7 SpireCombatPage UI components\n- 10 test files covering spire utilities, rooms, floors, enemies, combat actions, barriers\n- SpireSummaryTab.tsx and game type definitions\n\nFindings confirmed: multi-room infrastructure exists in spire-utils.ts but is NOT wired into the store. The field
clearedFloorsexists but is never read during descent.climbDirectionstate exists but is never checked by combat ticks. No floor-reset mechanic exists. Full details and file-by-file breakdown are in the issue body.Closed in favor of issue #255, which supersedes this one with the full spec docs as the authoritative source of truth.