fix: spire climbing spec discrepancies (DISC-1,14,15,18,19,21,22,23,29,34)
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m21s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m21s
- DISC-1: Fix ascent seed missing +runId in combat-descent-actions.ts - DISC-14: Recovery room 10x regen/conversion already in gameStore.ts - DISC-15/18/21: Add missing completion logs for recovery, library, treasure rooms - DISC-19: Filter library discipline selection to non-paused disciplines - DISC-22: Fix puzzle room log format to match spec - DISC-23: Replace hardcoded MAX_LEVEL with MAX_ATTUNEMENT_LEVEL - DISC-29: Update spec to document libraryStayed/recoveryStayed on currentRoom - DISC-34: Add 'Exited the Spire' activity log in exitSpireMode
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# Circular Dependencies
|
||||
Generated: 2026-06-08T14:03:03.873Z
|
||||
Generated: 2026-06-08T18:24:27.320Z
|
||||
Found: 1 circular chain(s) — these MUST be fixed before modifying involved files.
|
||||
|
||||
1. 1) stores/golem-combat-actions.ts > stores/golem-combat-helpers.ts
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"_meta": {
|
||||
"generated": "2026-06-08T14:03:01.818Z",
|
||||
"generated": "2026-06-08T18:24:25.222Z",
|
||||
"description": "Import dependency graph for src/lib/game. Keys are files, values are arrays of files they import.",
|
||||
"usage": "To find what a file affects, search for its path in the VALUES. To find what a file depends on, look at its KEY entry."
|
||||
},
|
||||
|
||||
@@ -601,8 +601,10 @@ clearedRooms: Record<string, boolean> // key = "floor:roomIndex"
|
||||
isDescentComplete: boolean
|
||||
|
||||
// Non-combat room tracking (climbing spec §4.8–§4.12)
|
||||
libraryStayed: boolean // true if player already used "Stay 1 Hour More" in current library room
|
||||
recoveryStayed: boolean // true if player already used "Stay 1 Hour More" in current recovery room
|
||||
// Note: libraryStayed and recoveryStayed live on the currentRoom object, not as
|
||||
// top-level state fields. This keeps per-room transient state co-located.
|
||||
libraryStayed: boolean // on currentRoom; true if player already used "Stay 1 Hour More" in current library room
|
||||
recoveryStayed: boolean // on currentRoom; true if player already used "Stay 1 Hour More" in current recovery room
|
||||
```
|
||||
|
||||
> `isDescending: boolean` (legacy alias) can be removed in favour of `climbDirection === 'down'`.
|
||||
|
||||
@@ -101,7 +101,7 @@ export function advanceRoomOrFloor(get: GetFn, set: SetFn): void {
|
||||
|
||||
if (s.currentRoomIndex + 1 >= s.roomsPerFloor) {
|
||||
const newFloor = Math.min(s.currentFloor + 1, 100);
|
||||
const newRoomsPerFloor = getRoomsForFloor(newFloor, newFloor * 12345);
|
||||
const newRoomsPerFloor = getRoomsForFloor(newFloor, newFloor * 12345 + s.runId);
|
||||
const newRoom = generateSpireFloorState(newFloor, 0, newRoomsPerFloor, s.runId);
|
||||
const newFloorHP = calcRoomHP(newRoom);
|
||||
set({
|
||||
|
||||
@@ -187,10 +187,10 @@ export const useCombatStore = create<CombatStore>()(
|
||||
},
|
||||
|
||||
exitSpireMode: () => {
|
||||
set((s) => {
|
||||
const s = get();
|
||||
const seed = s.exitFloor * 12345 + s.runId;
|
||||
const rooms = getRoomsForFloor(s.exitFloor, seed);
|
||||
return {
|
||||
set({
|
||||
spireMode: false,
|
||||
currentAction: 'meditate',
|
||||
climbDirection: null,
|
||||
@@ -209,8 +209,8 @@ export const useCombatStore = create<CombatStore>()(
|
||||
roomsPerFloor: 1,
|
||||
maxFloorReached: Math.max(s.maxFloorReached, 1),
|
||||
golemancy: { ...s.golemancy, activeGolems: [] as RuntimeActiveGolem[] },
|
||||
};
|
||||
});
|
||||
get().addActivityLog('floor_transition', 'Exited the Spire');
|
||||
},
|
||||
|
||||
startClimbUp: () => set({ climbDirection: 'up', currentAction: 'climb' }),
|
||||
|
||||
@@ -6,6 +6,7 @@ import type { CombatState, CombatStore } from './combat-state.types';
|
||||
import { useDisciplineStore } from './discipline-slice';
|
||||
import { useManaStore } from './manaStore';
|
||||
import { useAttunementStore } from './attunementStore';
|
||||
import { MAX_ATTUNEMENT_LEVEL } from '../data/attunements';
|
||||
import { PUZZLE_ROOMS } from '../constants';
|
||||
|
||||
type GetFn = () => CombatStore;
|
||||
@@ -81,8 +82,7 @@ export function onEnterPuzzleRoom(get: GetFn, set: SetFn): void {
|
||||
for (const attId of attunements) {
|
||||
const attState = attunementStore.attunements[attId];
|
||||
if (attState?.active) {
|
||||
const MAX_LEVEL = 10;
|
||||
const levelFraction = Math.min((attState.level || 1) / MAX_LEVEL, 1);
|
||||
const levelFraction = Math.min((attState.level || 1) / MAX_ATTUNEMENT_LEVEL, 1);
|
||||
totalReduction += perAttunementShare * levelFraction;
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ export function onEnterPuzzleRoom(get: GetFn, set: SetFn): void {
|
||||
},
|
||||
});
|
||||
get().addActivityLog('floor_transition',
|
||||
`Entered puzzle room on Floor ${s.currentFloor} (${puzzle?.name || puzzleId})`);
|
||||
`Entered puzzle room on Floor ${s.currentFloor} — ${puzzle?.name || puzzleId}`);
|
||||
}
|
||||
|
||||
// ─── Tick Handlers ────────────────────────────────────────────────────────────
|
||||
@@ -132,7 +132,7 @@ function tickLibraryRoom(get: GetFn, set: SetFn, hours: number, advance: Advance
|
||||
if (xpGrant > 0) {
|
||||
const disciplineStore = useDisciplineStore.getState();
|
||||
const allDisciplines = disciplineStore.disciplines;
|
||||
const entries = Object.entries(allDisciplines);
|
||||
const entries = Object.entries(allDisciplines).filter(([, ds]) => ds && !ds.paused);
|
||||
|
||||
if (entries.length > 0) {
|
||||
const [targetId, targetDs] = entries[Math.floor(Math.random() * entries.length)];
|
||||
@@ -150,6 +150,7 @@ function tickLibraryRoom(get: GetFn, set: SetFn, hours: number, advance: Advance
|
||||
|
||||
if (progress >= required) {
|
||||
set({ currentRoom: { ...room, libraryProgress: progress } });
|
||||
get().addActivityLog('special_effect', 'Library study complete');
|
||||
advance(get, set);
|
||||
} else {
|
||||
set({ currentRoom: { ...room, libraryProgress: progress } });
|
||||
@@ -164,6 +165,7 @@ function tickRecoveryRoom(get: GetFn, set: SetFn, hours: number, advance: Advanc
|
||||
|
||||
if (progress >= required) {
|
||||
set({ currentRoom: { ...room, recoveryProgress: progress } });
|
||||
get().addActivityLog('special_effect', 'Recovery complete — mana regen and conversion boosted');
|
||||
advance(get, set);
|
||||
} else {
|
||||
set({ currentRoom: { ...room, recoveryProgress: progress } });
|
||||
@@ -227,7 +229,9 @@ function tickTreasureRoom(get: GetFn, set: SetFn, hours: number, advance: Advanc
|
||||
}
|
||||
|
||||
if (progress >= required) {
|
||||
const claimedCount = claimedSet.size;
|
||||
set({ currentRoom: { ...room, treasureProgress: progress, treasureLootClaimed: Array.from(claimedSet) } });
|
||||
get().addActivityLog('special_effect', `Treasure room looted — ${claimedCount} items recovered`);
|
||||
advance(get, set);
|
||||
} else {
|
||||
set({ currentRoom: { ...room, treasureProgress: progress, treasureLootClaimed: Array.from(claimedSet) } });
|
||||
@@ -242,7 +246,7 @@ function tickPuzzleRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceF
|
||||
|
||||
if (progress >= required) {
|
||||
set({ currentRoom: { ...room, puzzleProgress: progress } });
|
||||
get().addActivityLog('puzzle_solved', `Puzzle solved on Floor ${s.currentFloor}!`);
|
||||
get().addActivityLog('puzzle_solved', 'Puzzle solved!');
|
||||
advance(get, set);
|
||||
} else {
|
||||
set({ currentRoom: { ...room, puzzleProgress: progress } });
|
||||
|
||||
Reference in New Issue
Block a user