From cba42e01ffe96a9c5005b5e38914726831db9e6a Mon Sep 17 00:00:00 2001 From: n8n-gitea Date: Wed, 20 May 2026 12:36:00 +0200 Subject: [PATCH] refactor: remove legacy store.ts and crafting-slice.ts, complete modular store migration - Delete store.ts (355 LOC monolithic store, zero imports) - Delete crafting-slice.ts (379 LOC legacy crafting module) - Inline createStartingEquipment() into craftingStore.ts - Remove legacy equipment/inventory fields from GameState - Remove EquipmentDef from game.ts imports (unused) - Fix duplicate EquipmentSpellState export in types.ts - Fix bluePrintId typo in craftingStore.ts - Update stores/index.ts to import CraftingState/CraftingActions from craftingStore.types - Update EquipmentTab.test.ts to test store state instead of deleted module - Clean up stale comments referencing crafting-slice.ts - Reduce TS errors from 83 to 72 by removing conflicting legacy types --- docs/circular-deps.txt | 8 +- docs/dependency-graph.json | 27 +- docs/project-structure.txt | 2 - src/components/game/tabs/EquipmentTab.test.ts | 28 +- src/lib/game/crafting-apply.ts | 2 +- src/lib/game/crafting-attunements.ts | 2 +- src/lib/game/crafting-equipment.ts | 2 +- src/lib/game/crafting-loot.ts | 2 +- src/lib/game/crafting-prep.ts | 2 +- src/lib/game/crafting-slice.ts | 379 ------------------ src/lib/game/crafting-utils.ts | 2 +- src/lib/game/store.ts | 355 ---------------- src/lib/game/stores/craftingStore.ts | 62 ++- src/lib/game/stores/index.ts | 2 +- src/lib/game/types.ts | 1 - src/lib/game/types/game.ts | 5 +- src/lib/game/utils/mana-utils.ts | 4 +- 17 files changed, 104 insertions(+), 781 deletions(-) delete mode 100755 src/lib/game/crafting-slice.ts delete mode 100755 src/lib/game/store.ts diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index 9de8b60..2f22e59 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,10 +1,8 @@ # Circular Dependencies -Generated: 2026-05-20T07:28:09.937Z -Found: 3 circular chain(s) — these MUST be fixed before modifying involved files. +Generated: 2026-05-20T10:00:51.281Z +Found: 1 circular chain(s) — these MUST be fixed before modifying involved files. -1. Processed 125 files (1.3s) (4 warnings) -2. 1) data/equipment/index.ts > data/equipment/utils.ts -3. 2) data/golems/index.ts > data/golems/utils.ts +1. Processed 127 files (1.4s) (4 warnings) ## How to fix 1. Identify which import in the chain can be extracted to a shared types/utils file. diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index 4c445d8..b66a0c0 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-05-20T07:28:08.406Z", + "generated": "2026-05-20T10:00:49.725Z", "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." }, @@ -299,6 +299,17 @@ "data/equipment/catalysts.ts": [ "data/equipment/types.ts" ], + "data/equipment/equipment-types-data.ts": [ + "data/equipment/accessories.ts", + "data/equipment/body.ts", + "data/equipment/casters.ts", + "data/equipment/catalysts.ts", + "data/equipment/feet.ts", + "data/equipment/hands.ts", + "data/equipment/head.ts", + "data/equipment/shields.ts", + "data/equipment/swords.ts" + ], "data/equipment/feet.ts": [ "data/equipment/types.ts" ], @@ -313,6 +324,7 @@ "data/equipment/body.ts", "data/equipment/casters.ts", "data/equipment/catalysts.ts", + "data/equipment/equipment-types-data.ts", "data/equipment/feet.ts", "data/equipment/hands.ts", "data/equipment/head.ts", @@ -331,7 +343,7 @@ "types/equipmentSlot.ts" ], "data/equipment/utils.ts": [ - "data/equipment/index.ts", + "data/equipment/equipment-types-data.ts", "data/equipment/types.ts" ], "data/fabricator-recipes.ts": [ @@ -343,19 +355,22 @@ "data/golems/elemental-golems.ts": [ "data/golems/types.ts" ], + "data/golems/golems-data.ts": [ + "data/golems/base-golems.ts", + "data/golems/elemental-golems.ts", + "data/golems/hybrid-golems.ts" + ], "data/golems/hybrid-golems.ts": [ "data/golems/types.ts" ], "data/golems/index.ts": [ - "data/golems/base-golems.ts", - "data/golems/elemental-golems.ts", - "data/golems/hybrid-golems.ts", + "data/golems/golems-data.ts", "data/golems/types.ts", "data/golems/utils.ts" ], "data/golems/types.ts": [], "data/golems/utils.ts": [ - "data/golems/index.ts", + "data/golems/golems-data.ts", "data/golems/types.ts" ], "data/guardian-encounters.ts": [ diff --git a/docs/project-structure.txt b/docs/project-structure.txt index 9a2b38a..3ec4f18 100644 --- a/docs/project-structure.txt +++ b/docs/project-structure.txt @@ -330,10 +330,8 @@ Mana-Loop/ │ │ ├── crafting-equipment.ts │ │ ├── crafting-loot.ts │ │ ├── crafting-prep.ts -│ │ ├── crafting-slice.ts │ │ ├── crafting-utils.ts │ │ ├── effects.ts -│ │ ├── store.ts │ │ └── types.ts │ └── utils.ts ├── test-results/ diff --git a/src/components/game/tabs/EquipmentTab.test.ts b/src/components/game/tabs/EquipmentTab.test.ts index c35dca9..795c7d5 100644 --- a/src/components/game/tabs/EquipmentTab.test.ts +++ b/src/components/game/tabs/EquipmentTab.test.ts @@ -83,25 +83,25 @@ describe('Equipment type definitions', () => { // ─── Test: Starting equipment ────────────────────────────────────────────────── describe('Starting equipment', () => { - it('createStartingEquipment returns valid equippedInstances', async () => { - const { createStartingEquipment } = await import('@/lib/game/crafting-slice'); - const { equippedInstances, equipmentInstances } = createStartingEquipment(); + it('crafting store initial state has valid equippedInstances', async () => { + const { useCraftingStore } = await import('@/lib/game/stores/craftingStore'); + const state = useCraftingStore.getState(); - expect(equippedInstances.mainHand).toBeTruthy(); - expect(equippedInstances.body).toBeTruthy(); - expect(equippedInstances.feet).toBeTruthy(); - expect(equippedInstances.offHand).toBeNull(); - expect(equippedInstances.head).toBeNull(); - expect(equippedInstances.hands).toBeNull(); - expect(equippedInstances.accessory1).toBeNull(); - expect(equippedInstances.accessory2).toBeNull(); + expect(state.equippedInstances.mainHand).toBeTruthy(); + expect(state.equippedInstances.body).toBeTruthy(); + expect(state.equippedInstances.feet).toBeTruthy(); + expect(state.equippedInstances.offHand).toBeNull(); + expect(state.equippedInstances.head).toBeNull(); + expect(state.equippedInstances.hands).toBeNull(); + expect(state.equippedInstances.accessory1).toBeNull(); + expect(state.equippedInstances.accessory2).toBeNull(); - expect(Object.keys(equipmentInstances).length).toBe(3); + expect(Object.keys(state.equipmentInstances).length).toBe(3); }); it('starting equipment instances have valid fields', async () => { - const { createStartingEquipment } = await import('@/lib/game/crafting-slice'); - const { equipmentInstances } = createStartingEquipment(); + const { useCraftingStore } = await import('@/lib/game/stores/craftingStore'); + const { equipmentInstances } = useCraftingStore.getState(); for (const instance of Object.values(equipmentInstances)) { expect(instance.instanceId).toBeTruthy(); diff --git a/src/lib/game/crafting-apply.ts b/src/lib/game/crafting-apply.ts index e9ac0c9..f811f36 100644 --- a/src/lib/game/crafting-apply.ts +++ b/src/lib/game/crafting-apply.ts @@ -1,5 +1,5 @@ // ─── Crafting Application System ──────────────────────────────────────────── -// Application system functions extracted from crafting-slice.ts +// Application system functions import type { EquipmentInstance, AppliedEnchantment, EnchantmentDesign, ApplicationProgress } from './types'; import { calculateApplicationTime, calculateApplicationManaPerHour } from './crafting-utils'; diff --git a/src/lib/game/crafting-attunements.ts b/src/lib/game/crafting-attunements.ts index 52838c3..50026d2 100644 --- a/src/lib/game/crafting-attunements.ts +++ b/src/lib/game/crafting-attunements.ts @@ -1,5 +1,5 @@ // ─── Attunement System ────────────────────────────────────────────────────── -// Attunement system functions extracted from crafting-slice.ts +// Attunement system functions import type { AttunementState } from './types'; import { calculateEnchantingXP, getAttunementXPForLevel, MAX_ATTUNEMENT_LEVEL } from './data/attunements'; diff --git a/src/lib/game/crafting-equipment.ts b/src/lib/game/crafting-equipment.ts index a8f0966..2269d10 100644 --- a/src/lib/game/crafting-equipment.ts +++ b/src/lib/game/crafting-equipment.ts @@ -1,5 +1,5 @@ // ─── Equipment Crafting System ────────────────────────────────────────────── -// Equipment crafting functions extracted from crafting-slice.ts +// Equipment crafting functions import type { EquipmentInstance, EquipmentCraftingProgress } from './types'; import { CRAFTING_RECIPES, canCraftRecipe, type CraftingRecipe } from './data/crafting-recipes'; diff --git a/src/lib/game/crafting-loot.ts b/src/lib/game/crafting-loot.ts index 67e5e81..ebbe026 100644 --- a/src/lib/game/crafting-loot.ts +++ b/src/lib/game/crafting-loot.ts @@ -1,5 +1,5 @@ // ─── Crafting Loot Inventory System ──────────────────────────────────────────── -// Loot inventory functions extracted from crafting-slice.ts +// Loot inventory functions import type { LootInventory } from './types'; import type { CraftingRecipe } from './data/crafting-recipes'; diff --git a/src/lib/game/crafting-prep.ts b/src/lib/game/crafting-prep.ts index 06c1acd..46f0db6 100644 --- a/src/lib/game/crafting-prep.ts +++ b/src/lib/game/crafting-prep.ts @@ -1,5 +1,5 @@ // ─── Crafting Preparation System ──────────────────────────────────────────── -// Preparation system functions extracted from crafting-slice.ts +// Preparation system functions import type { EquipmentInstance, PreparationProgress } from './types'; import { calculatePrepTime, calculatePrepManaCost, calculateManaPerHourForPrep } from './crafting-utils'; diff --git a/src/lib/game/crafting-slice.ts b/src/lib/game/crafting-slice.ts deleted file mode 100755 index 631e957..0000000 --- a/src/lib/game/crafting-slice.ts +++ /dev/null @@ -1,379 +0,0 @@ -// ─── Crafting Store Slice ───────────────────────────────────────────────────── -// Core slice logic for equipment and enchantment system. Extracted logic lives -// in focused modules: crafting-utils, crafting-design, crafting-prep, -// crafting-apply, crafting-equipment, crafting-loot, crafting-attunements. - -import type { GameState, EquipmentInstance, AppliedEnchantment, EnchantmentDesign, DesignEffect, EquipmentCraftingProgress, LootInventory, AttunementState } from './types'; -import { EQUIPMENT_TYPES } from './data/equipment'; -import type { EquipmentSlot } from './data/equipment'; -import { ENCHANTMENT_EFFECTS, calculateEffectCapacityCost } from './data/enchantment-effects'; -import { CRAFTING_RECIPES, canCraftRecipe, type CraftingRecipe } from './data/crafting-recipes'; -import { SPELLS_DEF } from './constants'; -import { calculateEnchantingXP, getAttunementXPForLevel, MAX_ATTUNEMENT_LEVEL } from './data/attunements'; -import { computeEffects } from './effects/upgrade-effects'; -import { hasSpecial, SPECIAL_EFFECTS } from './effects/special-effects'; -import type { ComputedEffects } from './effects/upgrade-effects.types'; - -// ─── Crafting Modules ─────────────────────────────────────────────────────── - -import * as CraftingUtils from './crafting-utils'; -import * as CraftingDesign from './crafting-design'; -import * as CraftingPrep from './crafting-prep'; -import * as CraftingApply from './crafting-apply'; -import * as CraftingEquipment from './crafting-equipment'; -import * as CraftingLoot from './crafting-loot'; -import * as CraftingAttunements from './crafting-attunements'; -import * as CraftingActions from './crafting-actions'; - -// ─── Initial Equipment Setup ───────────────────────────────────────────────── - -export function createStartingEquipment() { - const staffId = CraftingUtils.generateInstanceId(); - const staffInstance: EquipmentInstance = { - instanceId: staffId, - typeId: 'basicStaff', - name: 'Basic Staff', - enchantments: [{ effectId: 'spell_manaBolt', stacks: 1, actualCost: 50 }], - usedCapacity: 50, - totalCapacity: 50, - rarity: 'common', - quality: 100, - tags: [], - }; - - const shirtId = CraftingUtils.generateInstanceId(); - const shirtInstance: EquipmentInstance = { - instanceId: shirtId, - typeId: 'civilianShirt', - name: 'Civilian Shirt', - enchantments: [], - usedCapacity: 0, - totalCapacity: 30, - rarity: 'common', - quality: 100, - tags: [], - }; - - const shoesId = CraftingUtils.generateInstanceId(); - const shoesInstance: EquipmentInstance = { - instanceId: shoesId, - typeId: 'civilianShoes', - name: 'Civilian Shoes', - enchantments: [], - usedCapacity: 0, - totalCapacity: 15, - rarity: 'common', - quality: 100, - tags: [], - }; - - return { - equippedInstances: { - mainHand: staffId, - offHand: null, - head: null, - body: shirtId, - hands: null, - feet: shoesId, - accessory1: null, - accessory2: null, - }, - equipmentInstances: { - [staffId]: staffInstance, - [shirtId]: shirtInstance, - [shoesId]: shoesInstance, - }, - }; -} - -// ─── Crafting Actions Interface ───────────────────────────────────────────── - -export type CraftingActions = { - createEquipmentInstance: (typeId: string) => string | null; - equipItem: (instanceId: string, slot: EquipmentSlot) => boolean; - unequipItem: (slot: EquipmentSlot) => void; - deleteEquipmentInstance: (instanceId: string) => void; - startDesigningEnchantment: (name: string, equipmentTypeId: string, effects: DesignEffect[]) => boolean; - cancelDesign: () => void; - saveDesign: (design: EnchantmentDesign) => void; - deleteDesign: (designId: string) => void; - startPreparing: (equipmentInstanceId: string) => boolean; - cancelPreparation: () => void; - startApplying: (equipmentInstanceId: string, designId: string) => boolean; - pauseApplication: () => void; - resumeApplication: () => void; - cancelApplication: () => void; - disenchantEquipment: (instanceId: string) => void; - startCraftingEquipment: (blueprintId: string) => boolean; - cancelEquipmentCrafting: () => void; - deleteMaterial: (materialId: string, amount: number) => void; - getEquipmentSpells: () => string[]; - getEquipmentEffects: () => Record; - getAvailableCapacity: (instanceId: string) => number; -}; - -// ─── Crafting Store Slice ─────────────────────────────────────────────────── - -export function createCraftingSlice( - set: (fn: (state: GameState) => Partial) => void, - get: () => GameState & CraftingActions -): CraftingActions { - return { - createEquipmentInstance: (typeId) => CraftingActions.createEquipmentInstance(typeId, set), - equipItem: (instanceId, slot) => CraftingActions.equipItem(instanceId, slot, get, set), - unequipItem: (slot) => CraftingActions.unequipItem(slot, set), - deleteEquipmentInstance: (instanceId) => CraftingActions.deleteEquipmentInstance(instanceId, get, set), - startDesigningEnchantment: (name, equipmentTypeId, effects) => - CraftingActions.startDesigningEnchantment(name, equipmentTypeId, effects, get, set), - cancelDesign: () => CraftingActions.cancelDesign(get, set), - saveDesign: (design) => CraftingActions.saveDesign(design, get, set), - deleteDesign: (designId) => CraftingActions.deleteDesign(designId, set), - startPreparing: (equipmentInstanceId) => CraftingActions.startPreparing(equipmentInstanceId, get, set), - cancelPreparation: () => CraftingActions.cancelPreparation(set), - startApplying: (equipmentInstanceId, designId) => - CraftingActions.startApplying(equipmentInstanceId, designId, get, set), - pauseApplication: () => CraftingActions.pauseApplication(get, set), - resumeApplication: () => CraftingActions.resumeApplication(get, set), - cancelApplication: () => CraftingActions.cancelApplication(set), - disenchantEquipment: (instanceId) => CraftingActions.disenchantEquipment(instanceId, get, set), - startCraftingEquipment: (blueprintId) => CraftingActions.startCraftingEquipment(blueprintId, get, set), - cancelEquipmentCrafting: () => CraftingActions.cancelEquipmentCrafting(get, set), - deleteMaterial: (materialId, amount) => CraftingActions.deleteMaterial(materialId, amount, get, set), - getEquipmentSpells: () => CraftingActions.getEquipmentSpells(get), - getEquipmentEffects: () => CraftingActions.getEquipmentEffects(get), - getAvailableCapacity: (instanceId) => CraftingActions.getAvailableCapacity(instanceId, get), - }; -} - -// ─── Tick Processing for Crafting ──────────────────────────────────────────── - -export function processCraftingTick( - state: GameState, - effects: { rawMana: number; log: string[] } -): Partial { - const { rawMana, log } = effects; - let updates: Partial = {}; - - const computedEffects = computeEffects(state.skillUpgrades || {}, state.skillTiers || {}); - - // Process design progress (slot 1) - if (state.currentAction === 'design' && state.designProgress) { - const designResult = CraftingDesign.calculateDesignProgress( - state.designProgress.progress, - state.designProgress.required, - computedEffects, - false - ); - - if (designResult.isComplete) { - const completedDesign = CraftingDesign.createCompletedDesignFromProgress( - { - designId: state.designProgress.designId, - name: state.designProgress.name, - equipmentType: state.designProgress.equipmentType, - effects: state.designProgress.effects, - required: state.designProgress.required, - }, - ((state.skillUpgrades || {})['efficientEnchant'] || []).length * 0.05 - ); - updates = { - ...updates, - designProgress: null, - currentAction: 'meditate' as const, - enchantmentDesigns: [...state.enchantmentDesigns, completedDesign], - log: [`✅ Enchantment design "${completedDesign.name}" complete!`, ...log], - }; - } else { - updates = { - ...updates, - designProgress: { ...state.designProgress, progress: designResult.progress }, - }; - } - } - - // Process second design progress (slot 2) - if (state.designProgress2) { - const designResult2 = CraftingDesign.calculateSecondDesignProgress( - state.designProgress2.progress, - state.designProgress2.required, - computedEffects, - false - ); - if (designResult2.isComplete) { - const completedDesign = CraftingDesign.createCompletedDesignFromProgress( - { - designId: state.designProgress2.designId, - name: state.designProgress2.name, - equipmentType: state.designProgress2.equipmentType, - effects: state.designProgress2.effects, - required: state.designProgress2.required, - }, - ((state.skillUpgrades || {})['efficientEnchant'] || []).length * 0.05 - ); - const shouldTransitionToMeditate = !state.designProgress; - updates = { - ...updates, - designProgress2: null, - currentAction: shouldTransitionToMeditate ? 'meditate' as const : state.currentAction, - enchantmentDesigns: [...state.enchantmentDesigns, completedDesign], - log: [`✅ Enchantment design "${completedDesign.name}" complete! (2nd slot)`, ...log], - }; - } else { - updates = { - ...updates, - designProgress2: { ...state.designProgress2, progress: designResult2.progress }, - }; - } - } - - // Process preparation progress - if (state.currentAction === 'prepare' && state.preparationProgress) { - const instance = state.equipmentInstances[state.preparationProgress.equipmentInstanceId]; - const manaPerTick = instance ? CraftingPrep.getPreparationManaCostForTick(instance) : 0; - - if (rawMana >= manaPerTick) { - const tickResult = CraftingPrep.calculatePreparationTick( - state.preparationProgress.progress, - state.preparationProgress.required, - manaPerTick - ); - - if (tickResult.isComplete) { - if (instance) { - const completeResult = CraftingPrep.completePreparation(instance, state.preparationProgress.manaCostPaid); - updates = { - ...updates, - rawMana: rawMana - tickResult.manaConsumed + completeResult.manaRecovered, - preparationProgress: null, - currentAction: 'meditate' as const, - equipmentInstances: { - ...state.equipmentInstances, - [instance.instanceId]: completeResult.updatedInstance, - }, - log: [completeResult.logMessage, ...log], - }; - } else { - updates = { - ...updates, - preparationProgress: null, - currentAction: 'meditate' as const, - rawMana: rawMana - tickResult.manaConsumed, - log: ['✅ Preparation complete!', ...log], - }; - } - } else { - updates = { - ...updates, - rawMana: rawMana - tickResult.manaConsumed, - preparationProgress: { - ...state.preparationProgress, - progress: tickResult.progress, - manaCostPaid: tickResult.manaCostPaid, - }, - }; - } - } - } - - // Process application progress - if (state.currentAction === 'enchant' && state.applicationProgress && !state.applicationProgress.paused) { - const app = state.applicationProgress; - const manaPerTick = CraftingApply.getApplicationManaCostForTick(app.manaPerHour); - - if (rawMana >= manaPerTick) { - const tickResult = CraftingApply.calculateApplicationTick( - app.progress, - app.required, - app.manaSpent, - manaPerTick, - computedEffects - ); - - if (tickResult.isComplete) { - const instance = state.equipmentInstances[app.equipmentInstanceId]; - const design = state.enchantmentDesigns.find(d => d.id === app.designId); - if (instance && design) { - const applyResult = CraftingApply.applyEnchantments(instance, design, computedEffects); - const xpGain = CraftingAttunements.gainEnchantingXP(state.attunements, applyResult.xpGained); - updates = { - ...updates, - rawMana: rawMana - tickResult.manaConsumed, - applicationProgress: null, - currentAction: 'meditate' as const, - attunements: { - ...state.attunements, - enchanter: xpGain.attunements.enchanter, - }, - equipmentInstances: { - ...state.equipmentInstances, - [instance.instanceId]: applyResult.updatedInstance, - }, - log: [applyResult.logMessage, ...log], - }; - } - } else { - updates = { - ...updates, - rawMana: rawMana - tickResult.manaConsumed, - applicationProgress: { ...app, progress: tickResult.progress, manaSpent: tickResult.manaSpent }, - }; - } - } - } - - // Process equipment crafting progress - if (state.currentAction === 'craft' && state.equipmentCraftingProgress) { - const craft = state.equipmentCraftingProgress; - const tickResult = CraftingEquipment.calculateCraftingTick(craft.progress, craft.required); - - if (tickResult.isComplete) { - const recipe = CraftingEquipment.getRecipe(craft.blueprintId); - if (recipe) { - const craftResult = CraftingEquipment.completeEquipmentCrafting(craft.blueprintId, recipe); - updates = { - ...updates, - equipmentCraftingProgress: null, - currentAction: 'meditate' as const, - equipmentInstances: { - ...state.equipmentInstances, - [craftResult.instanceId]: craftResult.instance, - }, - totalCraftsCompleted: (state.totalCraftsCompleted || 0) + 1, - log: [craftResult.logMessage, ...log], - }; - } else { - updates = { - ...updates, - equipmentCraftingProgress: null, - currentAction: 'meditate' as const, - log: ['⚠️ Crafting failed - invalid recipe!', ...log], - }; - } - } else { - updates = { - ...updates, - equipmentCraftingProgress: { ...craft, progress: tickResult.progress }, - }; - } - } - - return updates; -} - -// ─── Export helper to get equipment instance spells ───────────────────────── - -export function getSpellsFromEquipment(instances: Record, equippedIds: (string | null)[]): string[] { - const spells: string[] = []; - for (const id of equippedIds) { - if (!id) continue; - const instance = instances[id]; - if (!instance) continue; - for (const ench of instance.enchantments) { - const effectDef = ENCHANTMENT_EFFECTS[ench.effectId]; - if (effectDef?.effect.type === 'spell' && effectDef.effect.spellId) { - spells.push(effectDef.effect.spellId); - } - } - } - return [...new Set(spells)]; -} diff --git a/src/lib/game/crafting-utils.ts b/src/lib/game/crafting-utils.ts index 4f0cf54..a1b76c9 100644 --- a/src/lib/game/crafting-utils.ts +++ b/src/lib/game/crafting-utils.ts @@ -1,5 +1,5 @@ // ─── Crafting Helper Utilities ───────────────────────────────────────────────── -// Instance/ID generation and helper functions extracted from crafting-slice.ts +// Instance/ID generation and helper functions import type { EquipmentInstance, EnchantmentDesign, DesignEffect } from './types'; import { EQUIPMENT_TYPES, type EquipmentCategory, type EquipmentSlot } from './data/equipment'; diff --git a/src/lib/game/store.ts b/src/lib/game/store.ts deleted file mode 100755 index 44bea0b..0000000 --- a/src/lib/game/store.ts +++ /dev/null @@ -1,355 +0,0 @@ -// ─── Game Store (Refactored) ────────────────────────────────────────────── -// Main entry point - imports from modular store components - -import { create } from 'zustand'; -import { persist } from 'zustand/middleware'; -import type { GameState, GameAction, ActivityLogEntry } from './types'; - -import { addActivityLogEntry } from './utils/activity-log'; -import { - computeMaxMana, computeRegen, computeClickMana, - getMeditationBonus, -} from './utils/mana-utils'; -import { - calcDamage, calcInsight, getIncursionStrength, canAffordSpellCost, deductSpellCost, -} from './utils/combat-utils'; -import { generateFloorState } from './utils/room-utils'; - -// Re-export formatting functions for backward compatibility -export { fmt, fmtDec } from './utils/formatting'; -export { getFloorMaxHP, getFloorElement } from './utils/floor-utils'; - -// Re-export computed stats functions for backward compatibility and tests -export { - computeMaxMana, computeRegen, computeClickMana, - getMeditationBonus, -} from './utils/mana-utils'; -export { - calcDamage, calcInsight, getIncursionStrength, canAffordSpellCost, deductSpellCost, -} from './utils/combat-utils'; - -// ─── Initial State ─────────────────────────────────────────────────────── - -interface MakeInitialOptions { - loopCount?: number; - totalInsight?: number; - insight?: number; - prestigeUpgrades?: Record; -} - -export function makeInitial(opts?: MakeInitialOptions): GameState { - return { - day: 1, - hour: 0, - rawMana: 100, - maxMana: 100, - elements: {}, - skills: {}, - skillUpgrades: {}, - skillTiers: {}, - spells: {}, - currentAction: 'meditate' as GameAction, - currentStudyTarget: null, - parallelStudyTarget: null, - activeSpell: null, - currentFloor: 100, - floorHP: 1000, - floorMaxHP: 1000, - currentRoom: generateFloorState(100), - maxFloorReached: 100, - paused: false, - gameOver: false, - victory: false, - loopCount: opts?.loopCount ?? 0, - totalInsight: opts?.totalInsight ?? 0, - insight: opts?.insight ?? 0, - loopInsight: 0, - prestigeUpgrades: opts?.prestigeUpgrades ?? {}, - signedPacts: [], - attunements: {}, - golemancy: { enabledGolems: [] }, - memories: [], - memorySlots: 0, - log: [], - activityLog: [], - meditateTicks: 0, - totalManaGathered: 0, - equippedInstances: {}, - equipmentInstances: {}, - lootInventory: {}, - blueprints: {}, - spireMode: false, - }; -} - -// ─── Game Store Interface ───────────────────────────────────────────────── - -export interface GameStore extends GameState { - tick: () => void; - gatherMana: () => void; - setAction: (action: GameAction) => void; - addActivityLog: (eventType: string, message: string, details?: ActivityLogEntry['details']) => void; - setSpell: (spellId: string) => void; - cancelStudy: () => void; - convertMana: (element: string, amount: number) => void; - unlockElement: (element: string) => void; - doPrestige: (id: string, selectedManaType?: string) => void; - startNewLoop: () => void; - togglePause: () => void; - resetGame: () => void; - addLog: (message: string) => void; - addAttunementXP: (attunementId: string, amount: number) => void; - toggleGolem: (golemId: string) => void; - setEnabledGolems: (golemIds: string[]) => void; - debugUnlockAttunement: (attunementId: string) => void; - debugAddElementalMana: (element: string, amount: number) => void; - debugSetTime: (day: number, hour: number) => void; - debugAddAttunementXP: (attunementId: string, amount: number) => void; - debugSetFloor: (floor: number) => void; - resetFloorHP: () => void; - getMaxMana: () => number; - getRegen: () => number; - getClickMana: () => number; - getDamage: (spellId: string) => number; - getMeditationMultiplier: () => number; - canCastSpell: (spellId: string) => boolean; - enterSpireMode: () => void; - climbDownFloor: () => void; - exitSpireMode: () => void; -} - -// ─── Store Implementation ──────────────────────────────────────────────── - -export const useGameStore = create()( - persist( - (set, get) => ({ - ...makeInitial(), - - getMaxMana: () => computeMaxMana(get()), - getRegen: () => computeRegen(get()), - getClickMana: () => computeClickMana(get()), - getDamage: (spellId: string) => calcDamage(get(), spellId), - getMeditationMultiplier: () => getMeditationBonus(get().meditateTicks, {}), - - canCastSpell: (spellId: string) => { - const state = get(); - const spell = state.spells?.[spellId]; - if (!spell) return false; - return true; - }, - - addLog: (message: string) => { - set((state) => ({ - log: [message, ...(state.log || []).slice(0, 49)], - })); - }, - - addActivityLog: (eventType: string, message: string, details?: ActivityLogEntry['details']) => { - set((state) => ({ - activityLog: addActivityLogEntry(state, eventType, message, details), - })); - }, - - tick: () => { - const state = get(); - if (state.gameOver || state.paused) return; - - const maxMana = computeMaxMana(state); - const baseRegen = computeRegen(state); - - let hour = state.hour + 1; - let day = state.day; - if (hour >= 24) { hour -= 24; day += 1; } - - if (day > 100) { - const insightGained = calcInsight(state); - set({ - day, hour, gameOver: true, victory: false, loopInsight: insightGained, - log: [`⏰ The loop ends. Gained ${insightGained} Insight.`, ...state.log.slice(0, 49)], - }); - return; - } - - let rawMana = state.rawMana + baseRegen; - rawMana = Math.min(rawMana, maxMana); - - set({ - day, hour, rawMana, - meditateTicks: state.currentAction === 'meditate' ? state.meditateTicks + 1 : 0, - }); - }, - - gatherMana: () => { - const state = get(); - const clickMana = computeClickMana(state); - const maxMana = computeMaxMana(state); - set((s) => ({ - rawMana: Math.min(s.rawMana + clickMana, maxMana), - totalManaGathered: s.totalManaGathered + clickMana, - })); - }, - - setAction: (action: GameAction) => { - set({ currentAction: action }); - }, - - setSpell: (spellId: string) => { - set({ activeSpell: spellId }); - }, - - cancelStudy: () => { - set({ currentStudyTarget: null, currentAction: 'meditate' }); - }, - - convertMana: (element: string, amount: number) => { - set((s) => { - const elem = s.elements?.[element]; - if (!elem || !elem.unlocked) return s; - const canConvert = Math.min(amount, Math.floor(s.rawMana / 10), elem.max - elem.current); - if (canConvert > 0) { - return { - rawMana: s.rawMana - canConvert * 10, - elements: { ...s.elements, [element]: { ...elem, current: elem.current + canConvert } }, - }; - } - return s; - }); - }, - - unlockElement: (element: string) => { - set((s) => ({ - elements: { ...s.elements, [element]: { ...s.elements[element], unlocked: true } }, - })); - }, - - doPrestige: (id: string, selectedManaType?: string) => { - set((s) => ({ - prestigeUpgrades: { ...s.prestigeUpgrades, [id]: (s.prestigeUpgrades[id] || 0) + 1 }, - })); - }, - - startNewLoop: () => { - const state = get(); - const insightGained = state.loopInsight || 0; - set({ - ...makeInitial({ - loopCount: state.loopCount + 1, - totalInsight: (state.totalInsight || 0) + insightGained, - insight: (state.insight || 0) + insightGained, - prestigeUpgrades: state.prestigeUpgrades, - }), - }); - }, - - togglePause: () => { - set((s) => ({ paused: !s.paused })); - }, - - resetGame: () => { - set(makeInitial()); - }, - - addAttunementXP: (attunementId: string, amount: number) => { - set((s) => { - const attState = s.attunements?.[attunementId]; - if (!attState) return s; - return { - attunements: { ...s.attunements, [attunementId]: { ...attState, experience: attState.experience + amount } }, - }; - }); - }, - - 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 }, - })); - }, - - debugUnlockAttunement: (attunementId: string) => { - set((s) => ({ - attunements: { ...s.attunements, [attunementId]: { id: attunementId, active: true, level: 1, experience: 0 } }, - })); - }, - - debugAddElementalMana: (element: string, amount: number) => { - set((s) => { - const elem = s.elements?.[element]; - if (!elem) return s; - return { - elements: { ...s.elements, [element]: { ...elem, current: Math.min(elem.current + amount, elem.max) } }, - }; - }); - }, - - debugSetTime: (day: number, hour: number) => { - set({ day, hour }); - }, - - debugAddAttunementXP: (attunementId: string, amount: number) => { - get().addAttunementXP(attunementId, amount); - }, - - debugSetFloor: (floor: number) => { - set((s) => ({ - currentFloor: floor, - currentRoom: generateFloorState(floor), - floorMaxHP: 100 + floor * 50, - floorHP: 100 + floor * 50, - })); - }, - - resetFloorHP: () => { - set((s) => ({ - floorHP: s.floorMaxHP, - currentRoom: generateFloorState(s.currentFloor), - })); - }, - - enterSpireMode: () => { - set({ spireMode: true }); - }, - - climbDownFloor: () => { - set((s) => { - if (s.currentFloor <= 1) return s; - const newFloor = s.currentFloor - 1; - return { - currentFloor: newFloor, - currentRoom: generateFloorState(newFloor), - floorMaxHP: 100 + newFloor * 50, - floorHP: 100 + newFloor * 50, - }; - }); - }, - - exitSpireMode: () => { - set({ spireMode: false }); - }, - }), - { - name: 'mana-loop-game-store', - } - ) -); - -// ─── Game Loop Hook ─────────────────────────────────────────────────────────── - -export function useGameLoop() { - const tick = useGameStore((s) => s.tick); - return { - start: () => { - const interval = setInterval(tick, 1000); - return () => clearInterval(interval); - }, - }; -} diff --git a/src/lib/game/stores/craftingStore.ts b/src/lib/game/stores/craftingStore.ts index 5fafd9a..5d60ad8 100644 --- a/src/lib/game/stores/craftingStore.ts +++ b/src/lib/game/stores/craftingStore.ts @@ -7,7 +7,7 @@ import * as CraftingUtils from '../crafting-utils'; import * as CraftingDesign from '../crafting-design'; import { useManaStore } from './manaStore'; import { useCombatStore } from './combatStore'; -import { createStartingEquipment } from '../crafting-slice'; + import { useUIStore } from './uiStore'; import * as ApplicationActions from '../crafting-actions/application-actions'; import * as PreparationActions from '../crafting-actions/preparation-actions'; @@ -16,7 +16,45 @@ import * as CraftingEquipment from '../crafting-equipment'; export const useCraftingStore = create()( persist( (set, get) => { - const startingEquipment = createStartingEquipment(); + const staffId = CraftingUtils.generateInstanceId(); + const staffInstance = { + instanceId: staffId, + typeId: 'basicStaff', + name: 'Basic Staff', + enchantments: [{ effectId: 'spell_manaBolt', stacks: 1, actualCost: 50 }], + usedCapacity: 50, + totalCapacity: 50, + rarity: 'common', + quality: 100, + tags: [], + }; + + const shirtId = CraftingUtils.generateInstanceId(); + const shirtInstance = { + instanceId: shirtId, + typeId: 'civilianShirt', + name: 'Civilian Shirt', + enchantments: [], + usedCapacity: 0, + totalCapacity: 30, + rarity: 'common', + quality: 100, + tags: [], + }; + + const shoesId = CraftingUtils.generateInstanceId(); + const shoesInstance = { + instanceId: shoesId, + typeId: 'civilianShoes', + name: 'Civilian Shoes', + enchantments: [], + usedCapacity: 0, + totalCapacity: 15, + rarity: 'common', + quality: 100, + tags: [], + }; + return { // Initial state designProgress: null, @@ -26,7 +64,21 @@ export const useCraftingStore = create()( equipmentCraftingProgress: null, enchantmentDesigns: [], unlockedEffects: [], - ...startingEquipment, + equippedInstances: { + mainHand: staffId, + offHand: null, + head: null, + body: shirtId, + hands: null, + feet: shoesId, + accessory1: null, + accessory2: null, + }, + equipmentInstances: { + [staffId]: staffInstance, + [shirtId]: shirtInstance, + [shoesId]: shoesInstance, + }, lootInventory: { materials: {}, blueprints: [], @@ -177,7 +229,7 @@ export const useCraftingStore = create()( // Check if we can start crafting const check = CraftingEquipment.canStartEquipmentCrafting( - bluePrintId, + blueprintId, state.lootInventory.blueprints.includes(blueprintId), state.lootInventory.materials, rawMana, @@ -188,7 +240,7 @@ export const useCraftingStore = create()( // Initialize crafting const result = CraftingEquipment.initializeEquipmentCrafting( - bluePrintId, + blueprintId, state.lootInventory.materials, rawMana ); diff --git a/src/lib/game/stores/index.ts b/src/lib/game/stores/index.ts index 73b3f20..9ecf8ff 100755 --- a/src/lib/game/stores/index.ts +++ b/src/lib/game/stores/index.ts @@ -15,7 +15,7 @@ export { useCombatStore, makeInitialSpells } from './combatStore'; export type { CombatState } from './combat-state.types'; export { useCraftingStore } from './craftingStore'; -export type { CraftingState, CraftingActions } from './craftingStore'; +export type { CraftingState, CraftingActions } from './craftingStore.types'; export { useAttunementStore } from './attunementStore'; export type { AttunementStoreState } from './attunementStore'; diff --git a/src/lib/game/types.ts b/src/lib/game/types.ts index 8a3d092..2bf7a3d 100755 --- a/src/lib/game/types.ts +++ b/src/lib/game/types.ts @@ -55,7 +55,6 @@ export type { GameActionType, ActivityEventType, ActivityLogEntry, - EquipmentSpellState, } from './types/game'; // ─── New: Memory Type Definition ───────────────────────────────────────────── diff --git a/src/lib/game/types/game.ts b/src/lib/game/types/game.ts index 94c6572..4b85500 100644 --- a/src/lib/game/types/game.ts +++ b/src/lib/game/types/game.ts @@ -3,7 +3,7 @@ import type { AttunementState } from './attunements'; import type { ElementState } from './elements'; import type { SpellState } from './spells'; -import type { EquipmentInstance, EnchantmentDesign, DesignProgress, PreparationProgress, ApplicationProgress, EquipmentCraftingProgress, EquipmentDef, BlueprintDef, LootInventory, EquipmentSpellState } from './equipment'; +import type { EquipmentInstance, EnchantmentDesign, DesignProgress, PreparationProgress, ApplicationProgress, EquipmentCraftingProgress, BlueprintDef, LootInventory, EquipmentSpellState } from './equipment'; // ─── Activity Log Types ───────────────────────────────────────────────── export type ActivityEventType = @@ -182,9 +182,6 @@ export interface GameState { // Equipment spell states for multi-casting equipmentSpellStates: EquipmentSpellState[]; - // Legacy Equipment (for backward compatibility) - equipment: Record; - inventory: EquipmentDef[]; // Blueprints blueprints: Record; diff --git a/src/lib/game/utils/mana-utils.ts b/src/lib/game/utils/mana-utils.ts index 9dd5621..03b8798 100644 --- a/src/lib/game/utils/mana-utils.ts +++ b/src/lib/game/utils/mana-utils.ts @@ -29,9 +29,7 @@ export function computeMaxMana( return base; } -// computeElementMax is now in ../store.ts with support for unlockedManaTypeUpgrades -// This file no longer exports computeElementMax to avoid duplicate export issues -// Import computeElementMax from '../store' instead +// computeElementMax has been removed — element max is computed in manaStore.ts export function computeRegen( state: Pick,