From 27500f37b7faa39bb32b78b7dfdba5bc0ab7f4e2 Mon Sep 17 00:00:00 2001 From: n8n-gitea Date: Wed, 27 May 2026 21:08:41 +0200 Subject: [PATCH] fix(#170): wire fabricator crafting completion + bonus enchantments + remove dead code --- docs/circular-deps.txt | 2 +- docs/dependency-graph.json | 2 +- docs/project-structure.txt | 1 + src/lib/game/crafting-equipment.ts | 10 +- src/lib/game/data/equipment/swords.ts | 13 +-- src/lib/game/data/equipment/types.ts | 2 - .../game/data/fabricator-physical-recipes.ts | 35 +++++++ src/lib/game/data/fabricator-recipe-types.ts | 4 +- src/lib/game/data/fabricator-recipes.ts | 40 ++++++++ .../game/data/fabricator-wizard-recipes.ts | 30 ++++++ .../game/stores/crafting-equipment-tick.ts | 91 +++++++++++++++++++ src/lib/game/stores/craftingStore.ts | 6 ++ src/lib/game/stores/craftingStore.types.ts | 1 + src/lib/game/stores/gameStore.ts | 27 +++--- 14 files changed, 230 insertions(+), 34 deletions(-) create mode 100644 src/lib/game/stores/crafting-equipment-tick.ts diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index cc286c8..8063280 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,4 +1,4 @@ # Circular Dependencies -Generated: 2026-05-27T13:57:23.187Z +Generated: 2026-05-27T17:14:06.661Z No circular dependencies found. ✅ diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index 71f3f35..8d063f5 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-05-27T13:57:21.361Z", + "generated": "2026-05-27T17:14:04.806Z", "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." }, diff --git a/docs/project-structure.txt b/docs/project-structure.txt index 95c3a30..ca9aed5 100644 --- a/docs/project-structure.txt +++ b/docs/project-structure.txt @@ -336,6 +336,7 @@ Mana-Loop/ │ │ │ ├── combat-actions.ts │ │ │ ├── combat-state.types.ts │ │ │ ├── combatStore.ts +│ │ │ ├── crafting-equipment-tick.ts │ │ │ ├── crafting-initial-state.ts │ │ │ ├── craftingStore.ts │ │ │ ├── craftingStore.types.ts diff --git a/src/lib/game/crafting-equipment.ts b/src/lib/game/crafting-equipment.ts index 860e6f5..e690c41 100644 --- a/src/lib/game/crafting-equipment.ts +++ b/src/lib/game/crafting-equipment.ts @@ -1,7 +1,7 @@ // ─── Equipment Crafting System ────────────────────────────────────────────── // Equipment crafting functions -import type { EquipmentInstance, EquipmentCraftingProgress } from './types'; +import type { EquipmentInstance, EquipmentCraftingProgress, AppliedEnchantment } from './types'; import { CRAFTING_RECIPES, canCraftRecipe, type CraftingRecipe } from './data/crafting-recipes'; import { EQUIPMENT_TYPES } from './data/equipment'; import { ok, fail, ErrorCode } from './utils/result'; @@ -92,20 +92,22 @@ const BASE_EQUIPMENT_QUALITY = 100; export function completeEquipmentCrafting( blueprintId: string, - recipe: CraftingRecipe + recipe: CraftingRecipe, + bonusEnchantments: AppliedEnchantment[] = [] ): Result<{ instanceId: string; instance: EquipmentInstance; logMessage: string }> { const equipType = EQUIPMENT_TYPES[recipe.equipmentTypeId]; if (!equipType) return fail(ErrorCode.INVALID_EQUIPMENT_TYPE, `Invalid equipment type: ${recipe.equipmentTypeId}`); const instanceId = `equip_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + const usedCapacity = bonusEnchantments.reduce((sum, e) => sum + e.actualCost, 0); return ok({ instanceId, instance: { instanceId, typeId: recipe.equipmentTypeId, name: recipe.name, - enchantments: [], - usedCapacity: 0, + enchantments: bonusEnchantments, + usedCapacity, totalCapacity: equipType.baseCapacity, rarity: recipe.rarity, quality: BASE_EQUIPMENT_QUALITY, diff --git a/src/lib/game/data/equipment/swords.ts b/src/lib/game/data/equipment/swords.ts index aff3942..f221306 100644 --- a/src/lib/game/data/equipment/swords.ts +++ b/src/lib/game/data/equipment/swords.ts @@ -4,16 +4,13 @@ import type { EquipmentType } from './types'; export const SWORD_EQUIPMENT: Record = { // ─── Main Hand - Magic Swords ───────────────────────────────────── - // Magic swords have low base damage but high cast speed - // They can be enchanted with elemental effects that use mana over time + // Magic swords can be enchanted with elemental effects that use mana over time ironBlade: { id: 'ironBlade', name: 'Iron Blade', category: 'sword', slot: 'mainHand', baseCapacity: 30, - baseDamage: 3, - baseCastSpeed: 4, description: 'A simple iron sword. Can be enchanted with elemental effects.', }, steelBlade: { @@ -22,8 +19,6 @@ export const SWORD_EQUIPMENT: Record = { category: 'sword', slot: 'mainHand', baseCapacity: 40, - baseDamage: 4, - baseCastSpeed: 4, description: 'A well-crafted steel sword. Balanced for combat and enchanting.', }, crystalBlade: { @@ -32,8 +27,6 @@ export const SWORD_EQUIPMENT: Record = { category: 'sword', slot: 'mainHand', baseCapacity: 55, - baseDamage: 3, - baseCastSpeed: 5, description: 'A blade made of crystallized mana. Excellent for elemental enchantments.', }, arcanistBlade: { @@ -42,8 +35,6 @@ export const SWORD_EQUIPMENT: Record = { category: 'sword', slot: 'mainHand', baseCapacity: 65, - baseDamage: 5, - baseCastSpeed: 4, description: 'A sword forged for battle mages. High capacity for powerful enchantments.', }, voidBlade: { @@ -52,8 +43,6 @@ export const SWORD_EQUIPMENT: Record = { category: 'sword', slot: 'mainHand', baseCapacity: 50, - baseDamage: 6, - baseCastSpeed: 3, description: 'A blade corrupted by void energy. Powerful but consumes more mana.', }, }; diff --git a/src/lib/game/data/equipment/types.ts b/src/lib/game/data/equipment/types.ts index 1585c0e..ae20d69 100644 --- a/src/lib/game/data/equipment/types.ts +++ b/src/lib/game/data/equipment/types.ts @@ -26,7 +26,5 @@ export interface EquipmentType { slot: EquipmentSlot; baseCapacity: number; description: string; - baseDamage?: number; // For swords - baseCastSpeed?: number; // For swords (higher = faster) twoHanded?: boolean; // If true, weapon occupies both main hand and offhand slots } diff --git a/src/lib/game/data/fabricator-physical-recipes.ts b/src/lib/game/data/fabricator-physical-recipes.ts index 40d2e4b..4896e15 100644 --- a/src/lib/game/data/fabricator-physical-recipes.ts +++ b/src/lib/game/data/fabricator-physical-recipes.ts @@ -17,6 +17,10 @@ export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 5, rarity: 'rare', gearTrait: '+20% Cast Speed, +15% Spell Damage', + bonusEnchantments: [ + { effectId: 'damage_10', stacks: 1, actualCost: 28 }, + { effectId: 'attack_speed_10', stacks: 1, actualCost: 22 }, + ], }, { id: 'arcanistBlade', @@ -30,6 +34,11 @@ export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 7, rarity: 'epic', gearTrait: '+15% Spell Damage, +15% Cast Speed, +10% Enchantment Power', + bonusEnchantments: [ + { effectId: 'damage_10', stacks: 1, actualCost: 28 }, + { effectId: 'attack_speed_10', stacks: 1, actualCost: 22 }, + { effectId: 'metal_cap_10', stacks: 1, actualCost: 30 }, + ], }, { id: 'voidBlade', @@ -43,6 +52,10 @@ export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 6, rarity: 'epic', gearTrait: '+25% Spell Damage, +10% Attack Speed', + bonusEnchantments: [ + { effectId: 'damage_10', stacks: 1, actualCost: 28 }, + { effectId: 'dark_cap_10', stacks: 1, actualCost: 30 }, + ], }, { id: 'battleHelm', @@ -56,6 +69,10 @@ export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 4, rarity: 'rare', gearTrait: '+10% Spell Damage, +15% Attack Speed', + bonusEnchantments: [ + { effectId: 'damage_5', stacks: 1, actualCost: 15 }, + { effectId: 'attack_speed_10', stacks: 1, actualCost: 22 }, + ], }, { id: 'battleRobe', @@ -69,6 +86,10 @@ export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 5, rarity: 'rare', gearTrait: '+15% Cast Speed, +10% Evasion', + bonusEnchantments: [ + { effectId: 'attack_speed_10', stacks: 1, actualCost: 22 }, + { effectId: 'mana_cap_50', stacks: 1, actualCost: 20 }, + ], }, { id: 'battleBoots', @@ -82,6 +103,9 @@ export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 3, rarity: 'uncommon', gearTrait: '+12% Cast Speed, +8% Attack Speed', + bonusEnchantments: [ + { effectId: 'attack_speed_10', stacks: 1, actualCost: 22 }, + ], }, { id: 'combatGauntlets', @@ -95,6 +119,9 @@ export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 3, rarity: 'uncommon', gearTrait: '+10% Attack Speed, +10% Cast Speed', + bonusEnchantments: [ + { effectId: 'attack_speed_10', stacks: 1, actualCost: 22 }, + ], }, { id: 'runicShield', @@ -108,6 +135,10 @@ export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 5, rarity: 'rare', gearTrait: '+20% Defensive Enchantment Power, +25 Earth Mana Capacity', + bonusEnchantments: [ + { effectId: 'earth_cap_10', stacks: 1, actualCost: 30 }, + { effectId: 'mana_cap_50', stacks: 1, actualCost: 20 }, + ], }, { id: 'manaShield', @@ -121,5 +152,9 @@ export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 6, rarity: 'epic', gearTrait: '+15% Spell Damage, +15% Defensive Enchantment Power', + bonusEnchantments: [ + { effectId: 'mana_cap_50', stacks: 1, actualCost: 20 }, + { effectId: 'damage_5', stacks: 1, actualCost: 15 }, + ], }, ]; diff --git a/src/lib/game/data/fabricator-recipe-types.ts b/src/lib/game/data/fabricator-recipe-types.ts index 399b2ee..eb1f061 100644 --- a/src/lib/game/data/fabricator-recipe-types.ts +++ b/src/lib/game/data/fabricator-recipe-types.ts @@ -1,7 +1,7 @@ // ─── Fabricator Recipe Types ─────────────────────────────────────────────────── // Shared types for fabricator and material recipes to avoid circular dependencies. - import type { EquipmentSlot } from './equipment/types'; +import type { AppliedEnchantment } from '../types/equipment'; export interface FabricatorRecipe { id: string; @@ -23,6 +23,8 @@ export interface FabricatorRecipe { rarity: 'common' | 'uncommon' | 'rare' | 'epic' | 'legendary'; /** Flavor text describing the gear's properties */ gearTrait: string; + /** Actual enchantments applied to the crafted instance (empty = no bonus effects) */ + bonusEnchantments?: AppliedEnchantment[]; /** Recipe type: 'equipment' (default) or 'material' */ recipeType?: 'equipment' | 'material'; /** For material recipes: the material ID produced */ diff --git a/src/lib/game/data/fabricator-recipes.ts b/src/lib/game/data/fabricator-recipes.ts index f940ae8..ecb7043 100644 --- a/src/lib/game/data/fabricator-recipes.ts +++ b/src/lib/game/data/fabricator-recipes.ts @@ -25,6 +25,9 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 3, rarity: 'uncommon', gearTrait: '+25 Earth Mana Capacity', + bonusEnchantments: [ + { effectId: 'earth_cap_10', stacks: 1, actualCost: 30 }, + ], }, { id: 'earthChest', @@ -38,6 +41,10 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 6, rarity: 'rare', gearTrait: '+50 Earth Mana Capacity, +10% Earth Mana Regen', + bonusEnchantments: [ + { effectId: 'earth_cap_10', stacks: 1, actualCost: 30 }, + { effectId: 'mana_regen_1', stacks: 1, actualCost: 15 }, + ], }, { id: 'earthBoots', @@ -51,6 +58,9 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 2, rarity: 'uncommon', gearTrait: '+20 Earth Mana Capacity', + bonusEnchantments: [ + { effectId: 'earth_cap_10', stacks: 1, actualCost: 30 }, + ], }, // ─── Metal Gear (Fire+Earth — balanced offense/defense) ────────────── @@ -66,6 +76,10 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 5, rarity: 'rare', gearTrait: '+15% Enchantment Power, +20 Metal Mana Capacity', + bonusEnchantments: [ + { effectId: 'damage_5', stacks: 1, actualCost: 15 }, + { effectId: 'metal_cap_10', stacks: 1, actualCost: 30 }, + ], }, { id: 'metalShield', @@ -79,6 +93,9 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 5, rarity: 'rare', gearTrait: '+15% Enchantment Capacity', + bonusEnchantments: [ + { effectId: 'mana_cap_50', stacks: 1, actualCost: 20 }, + ], }, { id: 'metalGloves', @@ -92,6 +109,9 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 3, rarity: 'uncommon', gearTrait: '+10% Enchantment Power, +15 Metal Mana Capacity', + bonusEnchantments: [ + { effectId: 'metal_cap_10', stacks: 1, actualCost: 30 }, + ], }, // ─── Crystal Gear (Sand+Sand+Light — high enchantment capacity) ────── @@ -107,6 +127,10 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 6, rarity: 'epic', gearTrait: '+40% enchantment capacity', + bonusEnchantments: [ + { effectId: 'mana_cap_50', stacks: 1, actualCost: 20 }, + { effectId: 'mana_regen_1', stacks: 1, actualCost: 15 }, + ], }, { id: 'crystalRing', @@ -120,6 +144,9 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 3, rarity: 'rare', gearTrait: '+15% enchantment capacity', + bonusEnchantments: [ + { effectId: 'mana_cap_50', stacks: 1, actualCost: 20 }, + ], }, { id: 'crystalAmulet', @@ -133,6 +160,9 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 4, rarity: 'rare', gearTrait: '+10% all enchantment effects', + bonusEnchantments: [ + { effectId: 'crystal_cap_10', stacks: 1, actualCost: 30 }, + ], }, // ─── Sand Gear (Earth+Water — lightweight, agile) ──────────────────── @@ -148,6 +178,9 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 2, rarity: 'uncommon', gearTrait: '+15% cast speed, +10% evasion', + bonusEnchantments: [ + { effectId: 'attack_speed_10', stacks: 1, actualCost: 22 }, + ], }, { id: 'sandGloves', @@ -161,6 +194,9 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 2, rarity: 'uncommon', gearTrait: '+10% cast speed', + bonusEnchantments: [ + { effectId: 'attack_speed_10', stacks: 1, actualCost: 22 }, + ], }, { id: 'sandVest', @@ -174,6 +210,10 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ craftTime: 4, rarity: 'rare', gearTrait: '+20% cast speed, +5% evasion', + bonusEnchantments: [ + { effectId: 'attack_speed_10', stacks: 1, actualCost: 22 }, + { effectId: 'sand_cap_10', stacks: 1, actualCost: 30 }, + ], }, // ─── Branch recipes ─────────────────────────────────────────────────── diff --git a/src/lib/game/data/fabricator-wizard-recipes.ts b/src/lib/game/data/fabricator-wizard-recipes.ts index 15be2f7..9482340 100644 --- a/src/lib/game/data/fabricator-wizard-recipes.ts +++ b/src/lib/game/data/fabricator-wizard-recipes.ts @@ -17,6 +17,10 @@ export const WIZARD_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 3, rarity: 'uncommon', gearTrait: '+15% Mana Regen, +20 Earth Mana Capacity', + bonusEnchantments: [ + { effectId: 'mana_regen_1', stacks: 1, actualCost: 15 }, + { effectId: 'earth_cap_10', stacks: 1, actualCost: 30 }, + ], }, { id: 'arcanistStaff', @@ -30,6 +34,10 @@ export const WIZARD_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 8, rarity: 'epic', gearTrait: '+30% Enchantment Capacity, +20% Mana Regen', + bonusEnchantments: [ + { effectId: 'mana_cap_100', stacks: 1, actualCost: 35 }, + { effectId: 'mana_regen_2', stacks: 1, actualCost: 28 }, + ], }, { id: 'battlestaff', @@ -43,6 +51,11 @@ export const WIZARD_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 6, rarity: 'rare', gearTrait: '+10% Enchantment Power, +10% Cast Speed', + bonusEnchantments: [ + { effectId: 'damage_5', stacks: 1, actualCost: 15 }, + { effectId: 'mana_cap_50', stacks: 1, actualCost: 20 }, + { effectId: 'metal_cap_10', stacks: 1, actualCost: 30 }, + ], }, { id: 'arcanistCirclet', @@ -56,6 +69,10 @@ export const WIZARD_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 4, rarity: 'rare', gearTrait: '+20% Enchantment Power, +15 Light Mana Capacity', + bonusEnchantments: [ + { effectId: 'mana_cap_50', stacks: 1, actualCost: 20 }, + { effectId: 'light_cap_10', stacks: 1, actualCost: 30 }, + ], }, { id: 'arcanistRobe', @@ -69,6 +86,10 @@ export const WIZARD_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 8, rarity: 'epic', gearTrait: '+35% Enchantment Capacity, +10% all Mana Regen', + bonusEnchantments: [ + { effectId: 'mana_cap_100', stacks: 1, actualCost: 35 }, + { effectId: 'mana_regen_5', stacks: 1, actualCost: 50 }, + ], }, { id: 'voidCatalyst', @@ -82,6 +103,11 @@ export const WIZARD_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 7, rarity: 'epic', gearTrait: '+30% Dark Enchantment Power, +15% Spell Damage', + bonusEnchantments: [ + { effectId: 'mana_cap_100', stacks: 1, actualCost: 35 }, + { effectId: 'damage_10', stacks: 1, actualCost: 28 }, + { effectId: 'dark_cap_10', stacks: 1, actualCost: 30 }, + ], }, { id: 'arcanistPendant', @@ -95,5 +121,9 @@ export const WIZARD_BRANCH_RECIPES: FabricatorRecipe[] = [ craftTime: 5, rarity: 'epic', gearTrait: '+15% all enchantment effects, +10% Mana Regen', + bonusEnchantments: [ + { effectId: 'mana_cap_50', stacks: 1, actualCost: 20 }, + { effectId: 'mana_regen_2', stacks: 1, actualCost: 28 }, + ], }, ]; diff --git a/src/lib/game/stores/crafting-equipment-tick.ts b/src/lib/game/stores/crafting-equipment-tick.ts new file mode 100644 index 0000000..e15fac0 --- /dev/null +++ b/src/lib/game/stores/crafting-equipment-tick.ts @@ -0,0 +1,91 @@ +// ─── Equipment Crafting Tick ───────────────────────────────────────────────── +// Handles advancing equipment crafting progress and completing crafted items. +// Extracted from craftingStore.ts to stay under the 400-line file limit. + +import type { CraftingState } from './craftingStore.types'; +import * as CraftingEquipment from '../crafting-equipment'; +import { CRAFTING_RECIPES } from '../data/crafting-recipes'; +import { FABRICATOR_RECIPES } from '../data/fabricator-recipes'; +import { HOURS_PER_TICK } from '../constants'; +import type { AppliedEnchantment } from '../types/equipment'; +import { useCombatStore } from './combatStore'; + +export interface CraftingTickResult { + completed: boolean; + logMessage?: string; +} + +export function processEquipmentCraftingTick( + state: CraftingState, + set: (partial: Partial) => void, +): CraftingTickResult { + const progress = state.equipmentCraftingProgress; + if (!progress) return { completed: false }; + + const newProgress = progress.progress + HOURS_PER_TICK; + + // Still in progress — just advance + if (newProgress < progress.required) { + set({ equipmentCraftingProgress: { ...progress, progress: newProgress } }); + return { completed: false }; + } + + // Crafting complete — resolve the recipe and create instance + const isFabricator = progress.blueprintId.startsWith('fabricator-'); + + if (isFabricator) { + const recipeId = progress.blueprintId.replace('fabricator-', ''); + const recipe = FABRICATOR_RECIPES.find(r => r.id === recipeId); + if (!recipe) { + set({ equipmentCraftingProgress: null }); + useCombatStore.setState({ currentAction: 'meditate' }); + return { completed: false, logMessage: '🔨 Crafting failed: recipe not found.' }; + } + const bonusEnchantments: AppliedEnchantment[] = recipe.bonusEnchantments + ? recipe.bonusEnchantments.map(e => ({ ...e })) + : []; + const result = CraftingEquipment.completeEquipmentCrafting( + progress.blueprintId, + recipe as any, + bonusEnchantments, + ); + if (result.success) { + const { instanceId, instance, logMessage } = result.data; + set({ + equipmentInstances: { ...state.equipmentInstances, [instanceId]: instance }, + equipmentCraftingProgress: null, + }); + useCombatStore.setState({ currentAction: 'meditate' }); + return { completed: true, logMessage }; + } else { + set({ equipmentCraftingProgress: null }); + useCombatStore.setState({ currentAction: 'meditate' }); + return { completed: false, logMessage: `🔨 Crafting failed: ${result.error}` }; + } + } else { + // Blueprint crafting + const blueprint = CRAFTING_RECIPES[progress.blueprintId]; + if (!blueprint) { + set({ equipmentCraftingProgress: null }); + useCombatStore.setState({ currentAction: 'meditate' }); + return { completed: false, logMessage: '🔨 Crafting failed: blueprint not found.' }; + } + const result = CraftingEquipment.completeEquipmentCrafting( + progress.blueprintId, + blueprint, + ); + if (result.success) { + const { instanceId, instance, logMessage } = result.data; + set({ + equipmentInstances: { ...state.equipmentInstances, [instanceId]: instance }, + equipmentCraftingProgress: null, + }); + useCombatStore.setState({ currentAction: 'meditate' }); + return { completed: true, logMessage }; + } else { + set({ equipmentCraftingProgress: null }); + useCombatStore.setState({ currentAction: 'meditate' }); + return { completed: false, logMessage: `🔨 Crafting failed: ${result.error}` }; + } + } +} diff --git a/src/lib/game/stores/craftingStore.ts b/src/lib/game/stores/craftingStore.ts index ed83706..4fa1e05 100644 --- a/src/lib/game/stores/craftingStore.ts +++ b/src/lib/game/stores/craftingStore.ts @@ -23,6 +23,7 @@ import { makeFabricatorProgress, } from '../crafting-fabricator'; import { craftMaterial as craftMaterialAction } from '../crafting-actions/crafting-material-actions'; +import { processEquipmentCraftingTick } from './crafting-equipment-tick'; export const useCraftingStore = create()( persist( @@ -363,6 +364,11 @@ export const useCraftingStore = create()( return { unlockedEffects: Array.from(existing) }; }); }, + + processEquipmentCraftingTick: (): { completed: boolean; logMessage?: string } => { + const state = get(); + return processEquipmentCraftingTick(state, set as unknown as (partial: Partial) => void); + }, }; }, { diff --git a/src/lib/game/stores/craftingStore.types.ts b/src/lib/game/stores/craftingStore.types.ts index 894cc6e..c55bfc0 100644 --- a/src/lib/game/stores/craftingStore.types.ts +++ b/src/lib/game/stores/craftingStore.types.ts @@ -72,6 +72,7 @@ export interface CraftingActions { resetEnchantmentSelection: () => void; clearLastError: () => void; unlockEffects: (effectIds: string[]) => void; + processEquipmentCraftingTick: () => { completed: boolean; logMessage?: string }; } export type CraftingStore = CraftingState & CraftingActions; diff --git a/src/lib/game/stores/gameStore.ts b/src/lib/game/stores/gameStore.ts index f38486f..bdff91f 100644 --- a/src/lib/game/stores/gameStore.ts +++ b/src/lib/game/stores/gameStore.ts @@ -1,6 +1,6 @@ -// ─── Game Store (Coordinator) ───────────────────────────────────────────────── +// ─── Game Store (Coordinator) ────────────────────────────────────── // Manages: day, hour, incursionStrength, containmentWards -// Orchestrates tick across all stores via a read → compute → write pipeline. +// Orchestrates tick across all stores via read → compute → write pipeline. import { create } from 'zustand'; import { persist } from 'zustand/middleware'; @@ -11,13 +11,7 @@ import { computeEquipmentEffects } from '../effects'; import type { ComputedEffects } from '../effects/upgrade-effects.types'; import { computeDisciplineEffects } from '../effects/discipline-effects'; -import { - computeMaxMana, - computeRegen, - getMeditationBonus, - getIncursionStrength, - calcInsight -} from '../utils'; +import { computeMaxMana, computeRegen, getMeditationBonus, getIncursionStrength, calcInsight } from '../utils'; import { useUIStore } from './uiStore'; import { usePrestigeStore } from './prestigeStore'; import { useManaStore } from './manaStore'; @@ -161,7 +155,6 @@ export const useGameStore = create()( return; } - // Incursion const incursionStrength = getIncursionStrength(day, hour); // Meditation bonus tracking @@ -208,7 +201,7 @@ export const useGameStore = create()( }); let totalManaGathered = ctx.mana.totalManaGathered; - // Convert action — delegate to manaStore + // Convert action if (ctx.combat.currentAction === 'convert') { const convertResult = useManaStore.getState().processConvertAction(rawMana); if (convertResult) { @@ -217,7 +210,7 @@ export const useGameStore = create()( } } - // Pact ritual progress + // Pact ritual if (ctx.prestige.pactRitualFloor !== null) { const guardian = getGuardianForFloor(ctx.prestige.pactRitualFloor); if (guardian) { @@ -253,7 +246,7 @@ export const useGameStore = create()( } } - // Discipline tick — process active disciplines (XP accrual + mana drain) + // Discipline tick const disciplineResult = useDisciplineStore.getState().processTick({ rawMana, elements, @@ -355,6 +348,14 @@ export const useGameStore = create()( }; } + // Equipment crafting tick — advance progress and complete when done + if (ctx.combat.currentAction === 'craft') { + const craftingResult = useCraftingStore.getState().processEquipmentCraftingTick(); + if (craftingResult.logMessage) { + addLog(craftingResult.logMessage); + } + } + // ── Phase 3: Write — batch all state updates ───────────────────────── writes.game = { day, hour, incursionStrength }; writes.mana = {