Spaces:
Running
Running
| /** | |
| * Adaptive Tactics - Game State Management | |
| * Handles run state and memory ledger with localStorage persistence | |
| */ | |
| import { save, load } from './persistence.js'; | |
| const RUN_STATE_KEY = 'at_run_state'; | |
| const MEMORY_KEY = 'at_memory_ledger'; | |
| /** | |
| * Creates a fresh run state | |
| */ | |
| function createFreshRunState() { | |
| return { | |
| cycle: 1, | |
| player_name: '', | |
| active_ephraim_form: 'defiant_king', | |
| major_package: null, | |
| minor_modifier: null, | |
| current_map_id: 'fortress_map_01', | |
| win_count: 0, | |
| loss: false, | |
| last_transition: null | |
| }; | |
| } | |
| /** | |
| * Creates a fresh memory ledger | |
| */ | |
| function createFreshMemory() { | |
| return { | |
| primary_lane_history: [], | |
| eilisia_kill_leads: 0, | |
| mirella_high_heal_cycles: 0, | |
| fast_clear_count: 0, | |
| fracture_line_cycles: 0, | |
| bait_pull_cycles: 0, | |
| throne_rush_count: 0, | |
| last_carry_unit: null, | |
| turns_to_clear_history: [] | |
| }; | |
| } | |
| export class GameState { | |
| constructor() { | |
| this.runState = createFreshRunState(); | |
| this.memory = createFreshMemory(); | |
| this.battleState = null; | |
| this.load(); | |
| } | |
| /** | |
| * Load state from localStorage | |
| */ | |
| load() { | |
| const savedRun = load(RUN_STATE_KEY); | |
| const savedMemory = load(MEMORY_KEY); | |
| if (savedRun) { | |
| this.runState = { ...createFreshRunState(), ...savedRun }; | |
| } | |
| if (savedMemory) { | |
| this.memory = { ...createFreshMemory(), ...savedMemory }; | |
| } | |
| } | |
| /** | |
| * Save state to localStorage | |
| */ | |
| save() { | |
| save(RUN_STATE_KEY, this.runState); | |
| save(MEMORY_KEY, this.memory); | |
| } | |
| /** | |
| * Reset to fresh state | |
| */ | |
| reset() { | |
| this.runState = createFreshRunState(); | |
| this.memory = createFreshMemory(); | |
| this.battleState = null; | |
| this.save(); | |
| } | |
| /** | |
| * Set the player's name | |
| */ | |
| setPlayerName(name) { | |
| this.runState.player_name = name; | |
| this.save(); | |
| } | |
| /** | |
| * Get the current Ephraim form based on cycle | |
| */ | |
| getEphraimForm() { | |
| const cycle = this.runState.cycle; | |
| if (cycle <= 2) return 'defiant_king'; | |
| if (cycle <= 4) return 'dark_king'; | |
| if (cycle <= 6) return 'fallen_king'; | |
| if (cycle === 7) return 'corrupted_king'; | |
| return 'promised_death'; | |
| } | |
| /** | |
| * Get the scaling band for enemy stats | |
| */ | |
| getScalingBand() { | |
| const cycle = this.runState.cycle; | |
| if (cycle <= 2) return 'cycles_1_2'; | |
| if (cycle <= 4) return 'cycles_3_4'; | |
| if (cycle <= 6) return 'cycles_5_6'; | |
| return 'cycles_7_plus'; | |
| } | |
| /** | |
| * Initialize a new battle cycle | |
| */ | |
| initCycle(content) { | |
| this.runState.active_ephraim_form = this.getEphraimForm(); | |
| this.battleState = { | |
| turn: 1, | |
| phase: 'player', | |
| playerUnits: [], | |
| enemyUnits: [], | |
| tiles: [], | |
| selectedUnit: null, | |
| actedUnits: new Set(), | |
| turnLog: [], | |
| cycleMetrics: { | |
| playerLaneMovement: { west: 0, center: 0, east: 0 }, | |
| eilisiaKills: 0, | |
| mirellaHealCount: 0, | |
| turnsElapsed: 0, | |
| ephraimDamagedThisTurn: false, | |
| enemyActivations: [] | |
| } | |
| }; | |
| this.save(); | |
| } | |
| /** | |
| * Record a cycle win and update memory ledger | |
| */ | |
| recordCycleWin() { | |
| const metrics = this.battleState?.cycleMetrics; | |
| if (!metrics) return; | |
| // Determine primary lane | |
| const lanes = metrics.playerLaneMovement; | |
| let primaryLane = 'center'; | |
| if (lanes.west > lanes.center && lanes.west > lanes.east) { | |
| primaryLane = 'west'; | |
| } else if (lanes.east > lanes.center && lanes.east > lanes.west) { | |
| primaryLane = 'east'; | |
| } | |
| this.memory.primary_lane_history.push(primaryLane); | |
| // Track Eilisia kills | |
| if (metrics.eilisiaKills > 0) { | |
| // Check if Eilisia led in kills (simplified check) | |
| this.memory.eilisia_kill_leads++; | |
| } | |
| // Track Mirella healing | |
| if (metrics.mirellaHealCount >= 3) { | |
| this.memory.mirella_high_heal_cycles++; | |
| } | |
| // Track turn count | |
| this.memory.turns_to_clear_history.push(metrics.turnsElapsed); | |
| if (metrics.turnsElapsed <= 8) { | |
| this.memory.fast_clear_count++; | |
| } | |
| // Increment cycle and win count | |
| this.runState.cycle++; | |
| this.runState.win_count++; | |
| this.runState.active_ephraim_form = this.getEphraimForm(); | |
| this.save(); | |
| } | |
| /** | |
| * Record a loss | |
| */ | |
| recordLoss() { | |
| this.runState.loss = true; | |
| this.save(); | |
| } | |
| /** | |
| * Add entry to turn log | |
| */ | |
| addLogEntry(entry) { | |
| if (this.battleState) { | |
| this.battleState.turnLog.push(entry); | |
| // Keep last 10 entries | |
| if (this.battleState.turnLog.length > 10) { | |
| this.battleState.turnLog.shift(); | |
| } | |
| } | |
| } | |
| /** | |
| * Mark a unit as having acted this turn | |
| */ | |
| markUnitActed(unitId) { | |
| if (this.battleState) { | |
| this.battleState.actedUnits.add(unitId); | |
| } | |
| } | |
| /** | |
| * Check if a unit has acted this turn | |
| */ | |
| hasUnitActed(unitId) { | |
| return this.battleState?.actedUnits.has(unitId) ?? false; | |
| } | |
| /** | |
| * Reset acted units for new turn | |
| */ | |
| resetActedUnits() { | |
| if (this.battleState) { | |
| this.battleState.actedUnits.clear(); | |
| } | |
| } | |
| /** | |
| * Advance to next turn | |
| */ | |
| advanceTurn() { | |
| if (this.battleState) { | |
| this.battleState.turn++; | |
| if (this.battleState.cycleMetrics) { | |
| this.battleState.cycleMetrics.turnsElapsed++; | |
| } | |
| this.resetActedUnits(); | |
| } | |
| } | |
| /** | |
| * Switch phase between player and enemy | |
| */ | |
| switchPhase() { | |
| if (this.battleState) { | |
| this.battleState.phase = this.battleState.phase === 'player' ? 'enemy' : 'player'; | |
| } | |
| } | |
| } | |