// ─── Combat Store ───────────────────────────────────────────────────────────── // Handles floors, spells, guardians, combat, and casting import { create } from 'zustand'; import { persist } from 'zustand/middleware'; import { createSafeStorage } from '../utils/safe-persist'; import type { GameAction, SpellState, FloorState, GolemancyState, ActivityLogEntry, AchievementState, EquipmentSpellState, ActivityEventType } from '../types'; import { getFloorMaxHP } from '../utils'; import { usePrestigeStore } from './prestigeStore'; import { generateFloorState } from '../utils/room-utils'; import { addActivityLogEntry } from '../utils/activity-log'; import { processCombatTick, makeInitialSpells } from './combat-actions'; import type { CombatStore } from './combat-state.types'; export const useCombatStore = create()( persist( (set, get) => ({ currentFloor: 1, floorHP: getFloorMaxHP(1), floorMaxHP: getFloorMaxHP(1), maxFloorReached: 1, activeSpell: 'manaBolt', currentAction: 'meditate', castProgress: 0, spireMode: false, // Room system currentRoom: generateFloorState(1), // Spire climbing state clearedFloors: {}, climbDirection: null, isDescending: false, // Golemancy golemancy: { enabledGolems: [], summonedGolems: [], lastSummonFloor: 0, }, // Equipment spell states equipmentSpellStates: [], // Combat tracking comboHitCount: 0, floorHitCount: 0, // Spells spells: { manaBolt: { learned: true, level: 1, studyProgress: 0 }, }, // Activity Log activityLog: [], // Achievements achievements: { unlocked: [], progress: {}, }, // Stats tracking totalSpellsCast: 0, totalDamageDealt: 0, totalCraftsCompleted: 0, setCurrentFloor: (floor: number) => { set({ currentFloor: floor, floorHP: getFloorMaxHP(floor), floorMaxHP: getFloorMaxHP(floor), }); }, advanceFloor: () => { set((state) => { const newFloor = Math.min(state.currentFloor + 1, 100); return { currentFloor: newFloor, floorHP: getFloorMaxHP(newFloor), floorMaxHP: getFloorMaxHP(newFloor), maxFloorReached: Math.max(state.maxFloorReached, newFloor), castProgress: 0, }; }); }, setFloorHP: (hp: number) => { set({ floorHP: Math.max(0, hp) }); }, setMaxFloorReached: (floor: number) => { set((state) => ({ maxFloorReached: Math.max(state.maxFloorReached, floor), })); }, setAction: (action: GameAction) => { set({ currentAction: action }); }, setSpell: (spellId: string) => { const state = get(); if (state.spells[spellId]?.learned) { set({ activeSpell: spellId }); } }, setCastProgress: (progress: number) => { set({ castProgress: progress }); }, // Room state setCurrentRoom: (room: FloorState) => { set({ currentRoom: room }); }, // Spire climbing setClimbDirection: (direction: 'up' | 'down' | null) => { set({ climbDirection: direction }); }, setClearedFloor: (floor: number, cleared: boolean) => { set((state) => ({ clearedFloors: { ...state.clearedFloors, [floor]: cleared }, })); }, setIsDescending: (descending: boolean) => { set({ isDescending: descending }); }, climbDownFloor: () => { set((s) => { if (s.currentFloor <= 1) return s; const newFloor = s.currentFloor - 1; return { currentFloor: newFloor, currentRoom: generateFloorState(newFloor), floorMaxHP: getFloorMaxHP(newFloor), floorHP: getFloorMaxHP(newFloor), castProgress: 0, }; }); }, exitSpireMode: () => { set({ spireMode: false, currentAction: 'meditate', climbDirection: null, isDescending: false, currentFloor: 1, floorHP: getFloorMaxHP(1), floorMaxHP: getFloorMaxHP(1), currentRoom: generateFloorState(1), castProgress: 0, clearedFloors: {}, }); }, startClimbUp: () => set({ climbDirection: 'up', currentAction: 'climb' }), startClimbDown: () => set({ climbDirection: 'down', currentAction: 'climb' }), // Golemancy toggleGolem: (golemId: string) => { set((s) => { const enabledGolems = s.golemancy?.enabledGolems || []; const isEnabled = enabledGolems.includes(golemId); return { golemancy: { ...s.golemancy, enabledGolems: isEnabled ? enabledGolems.filter(id => id !== golemId) : [...enabledGolems, golemId] }, }; }); }, setEnabledGolems: (golemIds: string[]) => { set((s) => ({ golemancy: { ...s.golemancy, enabledGolems: golemIds }, })); }, enterSpireMode: () => { const freshRoom = generateFloorState(1); set({ spireMode: true, currentFloor: 1, floorHP: getFloorMaxHP(1), floorMaxHP: getFloorMaxHP(1), currentRoom: freshRoom, castProgress: 0, climbDirection: null, isDescending: false, clearedFloors: {}, }); }, learnSpell: (spellId: string) => { set((state) => ({ spells: { ...state.spells, [spellId]: { learned: true, level: 1, studyProgress: 0 }, }, })); }, setSpellState: (spellId: string, spellState: Partial) => { set((state) => ({ spells: { ...state.spells, [spellId]: { ...(state.spells[spellId] || { learned: false, level: 0, studyProgress: 0 }), ...spellState }, }, })); }, // Activity Log addActivityLog: (eventType: ActivityEventType, message: string, details?: ActivityLogEntry['details']) => { set((state) => ({ activityLog: addActivityLogEntry(state, eventType, message, details), })); }, // Stats incrementSpellsCast: () => { set((state) => ({ totalSpellsCast: state.totalSpellsCast + 1 })); }, addDamageDealt: (damage: number) => { set((state) => ({ totalDamageDealt: state.totalDamageDealt + damage })); }, incrementCraftsCompleted: () => { set((state) => ({ totalCraftsCompleted: state.totalCraftsCompleted + 1 })); }, processCombatTick: ( rawMana: number, elements: Record, maxMana: number, attackSpeedMult: number, onFloorCleared: (floor: number, wasGuardian: boolean) => void, onDamageDealt: (damage: number) => { rawMana: number; elements: Record }, signedPacts: number[], ) => { return processCombatTick( get, set, rawMana, elements, maxMana, attackSpeedMult, onFloorCleared, onDamageDealt, signedPacts, ); }, resetCombat: (startFloor: number, spellsToKeep: string[] = []) => { const startSpells = makeInitialSpells(spellsToKeep); set({ currentFloor: startFloor, floorHP: getFloorMaxHP(startFloor), floorMaxHP: getFloorMaxHP(startFloor), maxFloorReached: startFloor, activeSpell: 'manaBolt', currentAction: 'meditate', castProgress: 0, spells: startSpells, }); }, // Debug helpers debugSetFloor: (floor: number) => { set({ currentFloor: floor, floorHP: getFloorMaxHP(floor), floorMaxHP: getFloorMaxHP(floor), }); }, resetFloorHP: () => { set((state) => ({ floorHP: state.floorMaxHP, })); }, }), { storage: createSafeStorage(), name: 'mana-loop-combat', partialize: (state) => ({ currentFloor: state.currentFloor, maxFloorReached: state.maxFloorReached, spells: state.spells, activeSpell: state.activeSpell, floorHP: state.floorHP, floorMaxHP: state.floorMaxHP, castProgress: state.castProgress, spireMode: state.spireMode, clearedFloors: state.clearedFloors, golemancy: state.golemancy, equipmentSpellStates: state.equipmentSpellStates, activityLog: state.activityLog, achievements: state.achievements, }), } ) ); // makeInitialSpells is now in combat-actions.ts // Re-export for backward compatibility export { makeInitialSpells } from './combat-actions';