diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index 5517506..597847a 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,5 +1,5 @@ # Circular Dependencies -Generated: 2026-06-14T21:49:16.203Z +Generated: 2026-06-15T08:59:04.077Z Found: 7 circular chain(s) — these MUST be fixed before modifying involved files. 1. 1) data/guardian-encounters.ts > data/guardian-procedural.ts diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index 6706809..0e1b766 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-06-14T21:49:13.932Z", + "generated": "2026-06-15T08:59:01.387Z", "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." }, @@ -542,6 +542,7 @@ "stores/attunementStore.ts", "stores/combatStore.ts", "stores/craftingStore.ts", + "stores/discipline-slice.ts", "stores/gameStore.ts", "stores/manaStore.ts", "stores/prestigeStore.ts", diff --git a/docs/project-structure.txt b/docs/project-structure.txt index 05a1818..61febab 100644 --- a/docs/project-structure.txt +++ b/docs/project-structure.txt @@ -293,7 +293,6 @@ Mana-Loop/ │ │ │ │ ├── crafting-equipment-actions.ts │ │ │ │ ├── crafting-material-actions.ts │ │ │ │ ├── design-actions.ts -│ │ │ │ ├── disenchant-actions.ts │ │ │ │ ├── equipment-actions.ts │ │ │ │ ├── index.ts │ │ │ │ └── preparation-actions.ts diff --git a/src/lib/game/__tests__/regression-fixes.test.ts b/src/lib/game/__tests__/regression-fixes.test.ts index f8c5b16..00f7d10 100644 --- a/src/lib/game/__tests__/regression-fixes.test.ts +++ b/src/lib/game/__tests__/regression-fixes.test.ts @@ -292,14 +292,15 @@ describe('Issue 79 — startDesigningEnchantment slot 2', () => { expect(useCraftingStore.getState().designProgress2).not.toBeNull(); }); - it('store code has else-if branch for designProgress2', () => { + it('design-actions has else-if branch for designProgress2', () => { // Verify the source code contains the fix for issue 79 + // (design logic was moved to design-actions.ts during refactor) const source = readFileSync( - '/home/user/repos/Mana-Loop/src/lib/game/stores/craftingStore.ts', + '/home/user/repos/Mana-Loop/src/lib/game/crafting-actions/design-actions.ts', 'utf-8' ); // The fix adds an else-if branch for designProgress2 - expect(source).toContain('else if (!state.designProgress2)'); + expect(source).toContain('else if (hasEnchantMastery && !state.designProgress2)'); }); it('should return false when both slots are occupied', async () => { diff --git a/src/lib/game/crafting-actions/disenchant-actions.ts b/src/lib/game/crafting-actions/disenchant-actions.ts deleted file mode 100644 index f0fc437..0000000 --- a/src/lib/game/crafting-actions/disenchant-actions.ts +++ /dev/null @@ -1,41 +0,0 @@ -// ─── Disenchanting Actions ───────────────────────────────────────────────── - -import type { CraftingState } from '../stores/craftingStore.types'; -import { useManaStore } from '../stores/manaStore'; - -export function disenchantEquipment( - instanceId: string, - get: () => CraftingState, - set: (fn: (state: CraftingState) => Partial) => void -) { - const state = get(); - const instance = state.equipmentInstances[instanceId]; - if (!instance || instance.enchantments.length === 0) return; - - const disenchantLevel = 0; - const recoveryRate = 0.1 + disenchantLevel * 0.2; - - let totalRecovered = 0; - for (const ench of instance.enchantments) { - totalRecovered += Math.floor(ench.actualCost * recoveryRate); - } - - // Credit recovered mana to raw mana pool - if (totalRecovered > 0) { - useManaStore.setState((s) => ({ rawMana: s.rawMana + totalRecovered })); - } - - set((s) => ({ - equipmentInstances: { - ...s.equipmentInstances, - [instanceId]: { - ...instance, - enchantments: [], - usedCapacity: 0, - rarity: 'common', - tags: [...(instance.tags || []), 'Ready for Enchantment'], - }, - }, - log: [`✨ Disenchanted ${instance.name}, recovered ${totalRecovered} mana.`], - })); -} diff --git a/src/lib/game/crafting-actions/index.ts b/src/lib/game/crafting-actions/index.ts index dd98706..7b5babf 100644 --- a/src/lib/game/crafting-actions/index.ts +++ b/src/lib/game/crafting-actions/index.ts @@ -6,6 +6,5 @@ export { createEquipmentInstance, equipItem, unequipItem, deleteEquipmentInstanc export { startDesigningEnchantment, cancelDesign, saveDesign, deleteDesign } from './design-actions'; export { startPreparing, cancelPreparation } from './preparation-actions'; export { startApplying, pauseApplication, resumeApplication, cancelApplication } from './application-actions'; -export { disenchantEquipment } from './disenchant-actions'; export { startCraftingEquipment, cancelEquipmentCrafting, deleteMaterial } from './crafting-equipment-actions'; export { getEquipmentSpells, getEquipmentEffects, getAvailableCapacity } from './computed-getters'; diff --git a/src/lib/game/stores/craftingStore.ts b/src/lib/game/stores/craftingStore.ts index 620c4b9..cc40122 100644 --- a/src/lib/game/stores/craftingStore.ts +++ b/src/lib/game/stores/craftingStore.ts @@ -3,24 +3,21 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; import type { EquipmentSlot } from '../types/equipmentSlot'; import type { CraftingStore, CraftingState } from './craftingStore.types'; -import * as CraftingUtils from '../crafting-utils'; -import * as CraftingDesign from '../crafting-design'; + import { useManaStore } from './manaStore'; import { useCombatStore } from './combatStore'; -import { useUIStore } from './uiStore'; -import { getEnchantingEfficiencyBonus } from '../effects/discipline-effects'; -import { hasSpecial, SPECIAL_EFFECTS } from '../effects/special-effects'; import * as ApplicationActions from '../crafting-actions/application-actions'; import * as PreparationActions from '../crafting-actions/preparation-actions'; import { equipItem as equipItemAction, unequipItem as unequipItemAction } from '../crafting-actions/equipment-actions'; +import { startDesigningEnchantment as startDesignAction, cancelDesign as cancelDesignAction, saveDesign as saveDesignAction, deleteDesign as deleteDesignAction } from '../crafting-actions/design-actions'; +import { useAttunementStore } from './attunementStore'; import { ErrorCode } from '../utils/result'; import { createSafeStorage } from '../utils/safe-persist'; import { createDefaultCraftingState } from './crafting-initial-state'; import { craftMaterial as craftMaterialAction } from '../crafting-actions/crafting-material-actions'; import { processEquipmentCraftingTick } from './crafting-equipment-tick'; import { startCraftingEquipment, cancelEquipmentCrafting, startFabricatorCrafting } from './pipelines/equipment-crafting'; -import { computeEffects } from '../effects/upgrade-effects'; export const useCraftingStore = create()( persist( @@ -36,100 +33,53 @@ export const useCraftingStore = create()( setApplicationProgress: (progress) => set({ applicationProgress: progress }), setEquipmentCraftingProgress: (progress) => set({ equipmentCraftingProgress: progress }), - // Enchantment design actions + // Enchantment design actions — delegated to design-actions.ts startDesigningEnchantment: (name, equipmentTypeId, effects) => { - const state = get(); // crafting state - const efficiencyBonus = getEnchantingEfficiencyBonus(); - - const validation = CraftingDesign.validateDesignEffects(effects, equipmentTypeId, 0, state.unlockedEffects); - if (!validation.valid) return false; - - const equipType = CraftingUtils.getEquipmentType(equipmentTypeId); - if (!equipType) return false; - - const totalCapacityCost = CraftingDesign.calculateDesignCapacityCost(effects, efficiencyBonus); - - if (totalCapacityCost > equipType.baseCapacity) return false; - - let updates: Partial = {}; - - if (!state.designProgress) { - updates = { - designProgress: { - designId: CraftingUtils.generateDesignId(), - progress: 0, - required: CraftingDesign.calculateDesignTime(effects), - name, - equipmentType: equipmentTypeId, - effects, - }, - }; - // Update currentAction in combatStore + const attunements = useAttunementStore.getState(); + const enchanterLevel = attunements.attunements?.enchanter?.level ?? 0; + const success = startDesignAction( + name, + equipmentTypeId, + effects, + { skills: { enchanting: enchanterLevel } }, + get, + set as unknown as (fn: (state: CraftingState) => Partial) => void + ); + if (success) { useCombatStore.setState({ currentAction: 'design' }); - } else if (!state.designProgress2) { - // Check for Enchant Mastery before allowing second design slot - const computedEffects = computeEffects(); - const hasEnchantMastery = hasSpecial(computedEffects, SPECIAL_EFFECTS.ENCHANT_MASTERY); - if (!hasEnchantMastery) return false; - updates = { - designProgress2: { - designId: CraftingUtils.generateDesignId(), - progress: 0, - required: CraftingDesign.calculateDesignTime(effects), - name, - equipmentType: equipmentTypeId, - effects, - }, - }; - useCombatStore.setState({ currentAction: 'design' }); - } else { - return false; } - - set(updates); - return true; + return success; }, cancelDesign: (slot?: 1 | 2) => { - const state = get(); if (slot === 2) { + const state = get(); if (state.designProgress2) { set({ designProgress2: null }); } } else if (slot === 1) { + const state = get(); if (state.designProgress) { set({ designProgress: null }); useCombatStore.setState({ currentAction: 'meditate' }); } - } else if (state.designProgress) { - set({ designProgress: null }); - useCombatStore.setState({ currentAction: 'meditate' }); - } else if (state.designProgress2) { - set({ designProgress2: null }); + } else { + cancelDesignAction(get, set as unknown as (fn: (state: CraftingState) => Partial) => void); + const state = get(); + // If both slots are now null, reset to meditate + if (!state.designProgress && !state.designProgress2) { + useCombatStore.setState({ currentAction: 'meditate' }); + } } }, deleteDesign: (designId) => { - set((state) => ({ - enchantmentDesigns: state.enchantmentDesigns.filter(d => d.id !== designId), - })); + deleteDesignAction(designId, set as unknown as (fn: (state: CraftingState) => Partial) => void); }, - // Enchantment design save saveDesign: (design) => { - const state = get(); - if (state.designProgress2 && state.designProgress2.designId === design.id) { - set((s) => ({ - enchantmentDesigns: [...s.enchantmentDesigns, design], - designProgress2: null, - })); - } else { - set((s) => ({ - enchantmentDesigns: [...s.enchantmentDesigns, design], - designProgress: null, - })); - useCombatStore.setState({ currentAction: 'meditate' }); - } + saveDesignAction(design, get, set as unknown as (fn: (state: CraftingState) => Partial) => void); + useCombatStore.setState({ currentAction: 'meditate' }); }, // Enchantment application actions