diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index 01df1f4..c74e599 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,4 +1,11 @@ # Circular Dependencies -Generated: 2026-06-04T16:54:47.153Z +Generated: 2026-06-04T17:28:40.127Z +Found: 1 circular chain(s) — these MUST be fixed before modifying involved files. -No circular dependencies found. ✅ +1. 1) stores/combat-descent-actions.ts > stores/non-combat-room-actions.ts + +## How to fix +1. Identify which import in the chain can be extracted to a shared types/utils file. +2. Move the shared type or function there. +3. Both files import from the new shared module instead of each other. +4. Run: bunx madge --circular src/lib/game (should return clean) \ No newline at end of file diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index b8b9cfa..207e4a4 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-06-04T16:54:45.269Z", + "generated": "2026-06-04T17:28:38.180Z", "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." }, @@ -550,9 +550,9 @@ "stores/combat-descent-actions.ts": [ "data/guardian-encounters.ts", "stores/combat-state.types.ts", - "stores/discipline-slice.ts", "stores/golem-combat-actions.ts", "stores/manaStore.ts", + "stores/non-combat-room-actions.ts", "stores/prestigeStore.ts", "utils/spire-utils.ts" ], @@ -564,6 +564,7 @@ "stores/combat-actions.ts", "stores/combat-descent-actions.ts", "stores/combat-state.types.ts", + "stores/non-combat-room-actions.ts", "types.ts", "utils/activity-log.ts", "utils/index.ts", @@ -729,6 +730,14 @@ "utils/result.ts", "utils/safe-persist.ts" ], + "stores/non-combat-room-actions.ts": [ + "constants.ts", + "stores/attunementStore.ts", + "stores/combat-descent-actions.ts", + "stores/combat-state.types.ts", + "stores/discipline-slice.ts", + "stores/manaStore.ts" + ], "stores/pipelines/combat-tick.ts": [ "constants.ts", "data/guardian-encounters.ts", @@ -887,7 +896,9 @@ "utils/spire-utils.ts": [ "constants.ts", "data/guardian-encounters.ts", + "data/loot-drops.ts", "types.ts", + "types/game.ts", "utils/enemy-utils.ts", "utils/floor-utils.ts" ] diff --git a/src/lib/game/stores/combat-state.types.ts b/src/lib/game/stores/combat-state.types.ts index 045f3ec..a07de75 100644 --- a/src/lib/game/stores/combat-state.types.ts +++ b/src/lib/game/stores/combat-state.types.ts @@ -3,6 +3,9 @@ import type { GameAction, SpellState, FloorState, GolemancyState, ActivityLogEntry, AchievementState, EquipmentSpellState, ActivityEventType, ActiveGolem, EnemyState, EquipmentInstance } from '../types'; +/** Signature for the advanceRoomOrFloor callback to break circular dependency */ +export type AdvanceRoomFn = (get: () => CombatStore, set: (s: Partial) => void) => void; + // ─── Combat State (data only) ───────────────────────────────────────────────── export interface CombatState { @@ -118,9 +121,9 @@ export interface CombatActions { /** Grant discipline XP scaled by floor, then advance */ onEnterLibraryRoom: () => void; /** Tick non-combat room progress (called from game tick pipeline) */ - tickNonCombatRoom: (hours: number) => void; + tickNonCombatRoom: (hours: number, advance: AdvanceRoomFn) => void; /** Skip current non-combat room (library, recovery, treasure) */ - skipNonCombatRoom: () => void; + skipNonCombatRoom: (advance: AdvanceRoomFn) => void; /** Stay 1 hour longer in library or recovery room */ stayLongerInRoom: () => void; diff --git a/src/lib/game/stores/combatStore.ts b/src/lib/game/stores/combatStore.ts index e318d80..ff336f3 100644 --- a/src/lib/game/stores/combatStore.ts +++ b/src/lib/game/stores/combatStore.ts @@ -220,8 +220,8 @@ export const useCombatStore = create()( advanceRoomOrFloor: () => advanceRoomOrFloor(get, set), onEnterRoomDescend: () => onEnterRoomDescend(get, set), onEnterLibraryRoom: () => onEnterLibraryRoom(get, set), - tickNonCombatRoom: (hours: number) => tickNonCombatRoom(get, set, hours), - skipNonCombatRoom: () => skipNonCombatRoom(get, set), + tickNonCombatRoom: (hours: number) => tickNonCombatRoom(get, set, hours, advanceRoomOrFloor), + skipNonCombatRoom: () => skipNonCombatRoom(get, set, advanceRoomOrFloor), stayLongerInRoom: () => stayLongerInRoom(get, set), // Golemancy diff --git a/src/lib/game/stores/non-combat-room-actions.ts b/src/lib/game/stores/non-combat-room-actions.ts index 2dfecd5..1b72007 100644 --- a/src/lib/game/stores/non-combat-room-actions.ts +++ b/src/lib/game/stores/non-combat-room-actions.ts @@ -7,10 +7,10 @@ import { useDisciplineStore } from './discipline-slice'; import { useManaStore } from './manaStore'; import { useAttunementStore } from './attunementStore'; import { PUZZLE_ROOMS } from '../constants'; -import { advanceRoomOrFloor } from './combat-descent-actions'; type GetFn = () => CombatStore; type SetFn = (state: Partial) => void; +type AdvanceFn = (get: GetFn, set: SetFn) => void; // ─── Room Entry Handlers ────────────────────────────────────────────────────── @@ -105,22 +105,22 @@ export function onEnterPuzzleRoom(get: GetFn, set: SetFn): void { // ─── Tick Handlers ──────────────────────────────────────────────────────────── -export function tickNonCombatRoom(get: GetFn, set: SetFn, hours: number): void { +export function tickNonCombatRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void { const s = get(); const rt = s.currentRoom.roomType as string; if (rt === 'library') { - tickLibraryRoom(get, set, hours); + tickLibraryRoom(get, set, hours, advance); } else if (rt === 'recovery') { - tickRecoveryRoom(get, set, hours); + tickRecoveryRoom(get, set, hours, advance); } else if (rt === 'treasure') { - tickTreasureRoom(get, set, hours); + tickTreasureRoom(get, set, hours, advance); } else if (rt === 'puzzle') { - tickPuzzleRoom(get, set, hours); + tickPuzzleRoom(get, set, hours, advance); } } -function tickLibraryRoom(get: GetFn, set: SetFn, hours: number): void { +function tickLibraryRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void { const s = get(); const room = s.currentRoom; const progress = (room.libraryProgress || 0) + hours; @@ -150,13 +150,13 @@ function tickLibraryRoom(get: GetFn, set: SetFn, hours: number): void { if (progress >= required) { set({ currentRoom: { ...room, libraryProgress: progress } }); - advanceRoomOrFloor(get, set); + advance(get, set); } else { set({ currentRoom: { ...room, libraryProgress: progress } }); } } -function tickRecoveryRoom(get: GetFn, set: SetFn, hours: number): void { +function tickRecoveryRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void { const s = get(); const room = s.currentRoom; const progress = (room.recoveryProgress || 0) + hours; @@ -164,13 +164,13 @@ function tickRecoveryRoom(get: GetFn, set: SetFn, hours: number): void { if (progress >= required) { set({ currentRoom: { ...room, recoveryProgress: progress } }); - advanceRoomOrFloor(get, set); + advance(get, set); } else { set({ currentRoom: { ...room, recoveryProgress: progress } }); } } -function tickTreasureRoom(get: GetFn, set: SetFn, hours: number): void { +function tickTreasureRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void { const s = get(); const room = s.currentRoom; const progress = (room.treasureProgress || 0) + hours; @@ -228,13 +228,13 @@ function tickTreasureRoom(get: GetFn, set: SetFn, hours: number): void { if (progress >= required) { set({ currentRoom: { ...room, treasureProgress: progress, treasureLootClaimed: Array.from(claimedSet) } }); - advanceRoomOrFloor(get, set); + advance(get, set); } else { set({ currentRoom: { ...room, treasureProgress: progress, treasureLootClaimed: Array.from(claimedSet) } }); } } -function tickPuzzleRoom(get: GetFn, set: SetFn, hours: number): void { +function tickPuzzleRoom(get: GetFn, set: SetFn, hours: number, advance: AdvanceFn): void { const s = get(); const room = s.currentRoom; const progress = (room.puzzleProgress || 0) + hours; @@ -243,7 +243,7 @@ function tickPuzzleRoom(get: GetFn, set: SetFn, hours: number): void { if (progress >= required) { set({ currentRoom: { ...room, puzzleProgress: progress } }); get().addActivityLog('puzzle_solved', `Puzzle solved on Floor ${s.currentFloor}!`); - advanceRoomOrFloor(get, set); + advance(get, set); } else { set({ currentRoom: { ...room, puzzleProgress: progress } }); } @@ -251,12 +251,12 @@ function tickPuzzleRoom(get: GetFn, set: SetFn, hours: number): void { // ─── Player Actions ─────────────────────────────────────────────────────────── -export function skipNonCombatRoom(get: GetFn, set: SetFn): void { +export function skipNonCombatRoom(get: GetFn, set: SetFn, advance: AdvanceFn): void { const s = get(); const rt = s.currentRoom.roomType as string; if (rt === 'library' || rt === 'recovery' || rt === 'treasure') { get().addActivityLog('floor_transition', `Skipped ${rt} room on Floor ${s.currentFloor}`); - advanceRoomOrFloor(get, set); + advance(get, set); } }