From 3f20991d2de2b2449fe16cffe9c90fdfaae4e8d8 Mon Sep 17 00:00:00 2001 From: n8n-gitea Date: Wed, 27 May 2026 14:13:46 +0200 Subject: [PATCH] feat: add material crafting recipes to Fabricator --- docs/circular-deps.txt | 2 +- docs/dependency-graph.json | 2 +- docs/project-structure.txt | 7 +- .../tabs/CraftingTab/FabricatorSubTab.tsx | 127 ++++++++---- .../tabs/CraftingTab/MaterialRecipeCard.tsx | 101 ++++++++++ .../crafting-material-actions.ts | 42 ++++ src/lib/game/crafting-fabricator.ts | 37 ++++ src/lib/game/data/fabricator-recipes.ts | 34 +++- src/lib/game/data/loot-drops.ts | 72 +++++++ src/lib/game/data/material-recipes.ts | 184 ++++++++++++++++++ src/lib/game/stores/craftingStore.ts | 34 ++-- src/lib/game/stores/craftingStore.types.ts | 1 + 12 files changed, 579 insertions(+), 64 deletions(-) create mode 100644 src/components/game/tabs/CraftingTab/MaterialRecipeCard.tsx create mode 100644 src/lib/game/crafting-actions/crafting-material-actions.ts create mode 100644 src/lib/game/data/material-recipes.ts diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index e12de5f..450daea 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,4 +1,4 @@ # Circular Dependencies -Generated: 2026-05-27T10:40:00.800Z +Generated: 2026-05-27T10:56:11.451Z No circular dependencies found. ✅ diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index beb4b33..e0039cb 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-05-27T10:39:58.930Z", + "generated": "2026-05-27T10:56:09.647Z", "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 3c52250..f0f4d77 100644 --- a/docs/project-structure.txt +++ b/docs/project-structure.txt @@ -91,7 +91,8 @@ Mana-Loop/ │ │ │ ├── tabs/ │ │ │ │ ├── CraftingTab/ │ │ │ │ │ ├── EnchanterSubTab.tsx -│ │ │ │ │ └── FabricatorSubTab.tsx +│ │ │ │ │ ├── FabricatorSubTab.tsx +│ │ │ │ │ └── MaterialRecipeCard.tsx │ │ │ │ ├── DebugTab/ │ │ │ │ │ ├── AchievementDebugSection.tsx │ │ │ │ │ ├── AttunementDebugSection.tsx @@ -248,6 +249,7 @@ Mana-Loop/ │ │ │ ├── application-actions.ts │ │ │ ├── computed-getters.ts │ │ │ ├── crafting-equipment-actions.ts +│ │ │ ├── crafting-material-actions.ts │ │ │ ├── design-actions.ts │ │ │ ├── disenchant-actions.ts │ │ │ ├── equipment-actions.ts @@ -314,7 +316,8 @@ Mana-Loop/ │ │ │ ├── fabricator-recipes.ts │ │ │ ├── guardian-data.ts │ │ │ ├── guardian-encounters.ts -│ │ │ └── loot-drops.ts +│ │ │ ├── loot-drops.ts +│ │ │ └── material-recipes.ts │ │ ├── effects/ │ │ │ ├── discipline-effects.ts │ │ │ ├── dynamic-compute.ts diff --git a/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx b/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx index ec959cb..0df6a89 100644 --- a/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx +++ b/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx @@ -7,23 +7,19 @@ import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Separator } from '@/components/ui/separator'; -import { Anvil, Hammer, Package } from 'lucide-react'; +import { Anvil, FlaskConical, Hammer, Package } from 'lucide-react'; +import { MaterialRecipeCard } from './MaterialRecipeCard'; import { FABRICATOR_RECIPES, + MATERIAL_RECIPES, getRecipesByManaType, canCraftRecipe, + MANA_TYPE_LABELS, } from '@/lib/game/data/fabricator-recipes'; import { LOOT_DROPS, LOOT_RARITY_COLORS } from '@/lib/game/data/loot-drops'; import { useCraftingStore, useManaStore } from '@/lib/game/stores'; import type { FabricatorRecipe } from '@/lib/game/data/fabricator-recipes'; -const MANA_TYPE_LABELS: Record = { - earth: '⛰️ Earth', - metal: '🔩 Metal', - crystal: '💎 Crystal', - sand: '🏜️ Sand', -}; - function RecipeCard({ recipe, materials, @@ -117,12 +113,14 @@ function RecipeCard({ export function FabricatorSubTab() { const [selectedManaType, setSelectedManaType] = useState('earth'); + const [activeSection, setActiveSection] = useState<'equipment' | 'materials'>('equipment'); const lootInventory = useCraftingStore((s) => s.lootInventory); const equipmentCraftingProgress = useCraftingStore((s) => s.equipmentCraftingProgress); const rawMana = useManaStore((s) => s.rawMana); const elements = useManaStore((s) => s.elements); const startFabricatorCrafting = useCraftingStore((s) => s.startFabricatorCrafting); + const craftMaterial = useCraftingStore((s) => s.craftMaterial); const cancelEquipmentCrafting = useCraftingStore((s) => s.cancelEquipmentCrafting); const availableManaTypes = useMemo(() => { @@ -136,33 +134,64 @@ export function FabricatorSubTab() { const isCrafting = equipmentCraftingProgress !== null; + const materialRecipes = useMemo(() => MATERIAL_RECIPES, []); + const handleCraft = (recipe: FabricatorRecipe) => { - startFabricatorCrafting(recipe.id); + if (recipe.recipeType === 'material') { + craftMaterial(recipe.id); + } else { + startFabricatorCrafting(recipe.id); + } }; return (
- {/* Mana type filter */} -
- {availableManaTypes.map((mt) => ( - - ))} + {/* Section toggle: Equipment vs Materials */} +
+ +
+ {/* Mana type filter — only for equipment */} + {activeSection === 'equipment' && ( +
+ {availableManaTypes.map((mt) => ( + + ))} +
+ )} +
{/* Recipe list */} - - {MANA_TYPE_LABELS[selectedManaType] ?? selectedManaType} Recipes + {activeSection === 'equipment' ? ( + <>{MANA_TYPE_LABELS[selectedManaType] ?? selectedManaType} Recipes + ) : ( + <>Material Recipes + )} @@ -193,23 +222,43 @@ export function FabricatorSubTab() { ) : (
- {filteredRecipes.length === 0 ? ( -
- -

No recipes for this mana type yet.

-
+ {activeSection === 'equipment' ? ( + filteredRecipes.length === 0 ? ( +
+ +

No recipes for this mana type yet.

+
+ ) : ( + filteredRecipes.map((recipe) => ( + + )) + ) ) : ( - filteredRecipes.map((recipe) => ( - - )) + materialRecipes.length === 0 ? ( +
+ +

No material recipes available.

+
+ ) : ( + materialRecipes.map((recipe) => ( + + )) + ) )}
diff --git a/src/components/game/tabs/CraftingTab/MaterialRecipeCard.tsx b/src/components/game/tabs/CraftingTab/MaterialRecipeCard.tsx new file mode 100644 index 0000000..441f34d --- /dev/null +++ b/src/components/game/tabs/CraftingTab/MaterialRecipeCard.tsx @@ -0,0 +1,101 @@ +'use client'; + +import { Button } from '@/components/ui/button'; +import { Badge } from '@/components/ui/badge'; +import { Separator } from '@/components/ui/separator'; +import { LOOT_DROPS, LOOT_RARITY_COLORS } from '@/lib/game/data/loot-drops'; +import { canCraftRecipe, MANA_TYPE_LABELS } from '@/lib/game/data/fabricator-recipes'; +import type { FabricatorRecipe } from '@/lib/game/data/fabricator-recipes'; + +interface MaterialRecipeCardProps { + recipe: FabricatorRecipe; + materials: Record; + rawMana: number; + elementalMana: Record; + onCraft: (recipe: FabricatorRecipe) => void; +} + +export function MaterialRecipeCard({ + recipe, + materials, + rawMana, + elementalMana, + onCraft, +}: MaterialRecipeCardProps) { + const pool = recipe.manaType === 'raw' + ? rawMana + : (elementalMana[recipe.manaType]?.current ?? 0); + const { canCraft } = canCraftRecipe(recipe, materials, pool, recipe.manaType); + const resultDrop = recipe.resultMaterial ? LOOT_DROPS[recipe.resultMaterial] : null; + const resultRarity = resultDrop ? LOOT_RARITY_COLORS[resultDrop.rarity] : null; + + return ( +
+
+
+
+ {recipe.name} +
+
{recipe.rarity}
+
+ + {recipe.resultAmount}x Output + +
+ +
{recipe.description}
+ + + +
+ {Object.keys(recipe.materials).length > 0 && ( + <> +
Input Materials:
+ {Object.entries(recipe.materials).map(([matId, amount]) => { + const available = materials[matId] || 0; + const matDrop = LOOT_DROPS[matId]; + const hasEnough = available >= amount; + + return ( +
+ {matDrop?.name ?? matId} + + {available} / {amount} + +
+ ); + })} + + )} + + {recipe.manaCost > 0 && ( +
+ {MANA_TYPE_LABELS[recipe.manaType]?.split(' ')[1] ?? recipe.manaType} Mana: + = recipe.manaCost ? 'text-green-400' : 'text-red-400'}> + {pool} / {recipe.manaCost} + +
+ )} + +
+ Produces: + + {recipe.resultAmount}x {resultDrop?.name ?? recipe.resultMaterial} + +
+
+ + +
+ ); +} diff --git a/src/lib/game/crafting-actions/crafting-material-actions.ts b/src/lib/game/crafting-actions/crafting-material-actions.ts new file mode 100644 index 0000000..b6bc96f --- /dev/null +++ b/src/lib/game/crafting-actions/crafting-material-actions.ts @@ -0,0 +1,42 @@ +// ─── Material Crafting Actions ───────────────────────────────────────────────── +// Separate file to avoid exceeding the 400-line limit in craftingStore.ts. + +import { useManaStore } from '../stores/manaStore'; +import { useCombatStore } from '../stores/combatStore'; +import { useUIStore } from '../stores/uiStore'; +import { + getFabricatorRecipe, + deductFabricatorMana, + deductMaterials, +} from '../crafting-fabricator'; + +export interface CraftMaterialResult { + success: boolean; + newMaterials?: Record; +} + +export function craftMaterial( + recipeId: string, + lootInventoryMaterials: Record, +): CraftMaterialResult { + const currentAction = useCombatStore.getState().currentAction; + if (currentAction !== 'meditate') return { success: false }; + + const recipe = getFabricatorRecipe(recipeId); + if (!recipe || recipe.recipeType !== 'material') return { success: false }; + if (!recipe.resultMaterial || !recipe.resultAmount) return { success: false }; + + const rawMana = useManaStore.getState().rawMana; + const elements = useManaStore.getState().elements; + + const deducted = deductFabricatorMana(recipe, rawMana, elements); + if (!deducted) return { success: false }; + + const newMaterials = deductMaterials(recipe, lootInventoryMaterials); + newMaterials[recipe.resultMaterial] = (newMaterials[recipe.resultMaterial] || 0) + recipe.resultAmount; + + useManaStore.setState({ rawMana: deducted.rawMana, elements: deducted.elements }); + useUIStore.getState().addLog(`✨ Crafted ${recipe.resultAmount}x ${recipe.name}!`); + + return { success: true, newMaterials }; +} diff --git a/src/lib/game/crafting-fabricator.ts b/src/lib/game/crafting-fabricator.ts index 59103a0..7f34310 100644 --- a/src/lib/game/crafting-fabricator.ts +++ b/src/lib/game/crafting-fabricator.ts @@ -4,6 +4,9 @@ import type { EquipmentCraftingProgress } from './types'; import type { FabricatorRecipe } from './data/fabricator-recipes'; import { FABRICATOR_RECIPES } from './data/fabricator-recipes'; +import { useManaStore } from './stores/manaStore'; +import { useCombatStore } from './stores/combatStore'; +import { useUIStore } from './stores/uiStore'; // ─── Lookup ─────────────────────────────────────────────────────────────────── @@ -139,3 +142,37 @@ export function makeFabricatorProgress( manaSpent: manaCost, }; } + +// ─── Material Crafting ────────────────────────────────────────────────────── + +export interface CraftMaterialResult { + success: boolean; + newMaterials: Record; + newRawMana: number; + newElements: Record; + logMessage: string; +} + +export function executeMaterialCraft( + recipe: FabricatorRecipe, + materials: Record, +): CraftMaterialResult | null { + if (recipe.recipeType !== 'material' || !recipe.resultMaterial || !recipe.resultAmount) return null; + + const rawMana = useManaStore.getState().rawMana; + const elements = useManaStore.getState().elements; + + const deducted = deductFabricatorMana(recipe, rawMana, elements); + if (!deducted) return null; + + const newMaterials = deductMaterials(recipe, materials); + newMaterials[recipe.resultMaterial] = (newMaterials[recipe.resultMaterial] || 0) + recipe.resultAmount; + + return { + success: true, + newMaterials, + newRawMana: deducted.rawMana, + newElements: deducted.elements, + logMessage: `✨ Crafted ${recipe.resultAmount}x ${recipe.name}!`, + }; +} diff --git a/src/lib/game/data/fabricator-recipes.ts b/src/lib/game/data/fabricator-recipes.ts index 9da7e87..83a7b75 100644 --- a/src/lib/game/data/fabricator-recipes.ts +++ b/src/lib/game/data/fabricator-recipes.ts @@ -24,8 +24,18 @@ export interface FabricatorRecipe { rarity: 'common' | 'uncommon' | 'rare' | 'epic' | 'legendary'; /** Flavor text describing the gear's properties */ gearTrait: string; + /** Recipe type: 'equipment' (default) or 'material' */ + recipeType?: 'equipment' | 'material'; + /** For material recipes: the material ID produced */ + resultMaterial?: string; + /** For material recipes: how many are produced */ + resultAmount?: number; } +import { MATERIAL_RECIPES } from './material-recipes'; + +export { MATERIAL_RECIPES }; + export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ // ─── Earth Gear (Compacted Earth — high defense) ────────────────────── { @@ -190,16 +200,36 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ rarity: 'rare', gearTrait: '+20% cast speed, +5% evasion', }, + ]; +// ─── Mana Type Labels ──────────────────────────────────────────────────────── + +export const MANA_TYPE_LABELS: Record = { + raw: '⚪ Raw', + fire: '🔥 Fire', + water: '💧 Water', + air: '🌬️ Air', + earth: '⛰️ Earth', + light: '☀️ Light', + dark: '🌑 Dark', + metal: '🔩 Metal', + crystal: '💎 Crystal', + sand: '🏜️ Sand', +}; + // ─── Helpers ────────────────────────────────────────────────────────────────── export function getRecipesByManaType(manaType: string): FabricatorRecipe[] { - return FABRICATOR_RECIPES.filter(r => r.manaType === manaType); + return FABRICATOR_RECIPES.filter(r => r.manaType === manaType && r.recipeType !== 'material'); +} + +export function getMaterialRecipes(): FabricatorRecipe[] { + return FABRICATOR_RECIPES.filter(r => r.recipeType === 'material'); } export function getRecipeById(id: string): FabricatorRecipe | undefined { - return FABRICATOR_RECIPES.find(r => r.id === id); + return FABRICATOR_RECIPES.find(r => r.id === id) ?? MATERIAL_RECIPES.find(r => r.id === id); } export function canCraftRecipe( diff --git a/src/lib/game/data/loot-drops.ts b/src/lib/game/data/loot-drops.ts index 56e5493..8d4c25b 100755 --- a/src/lib/game/data/loot-drops.ts +++ b/src/lib/game/data/loot-drops.ts @@ -52,6 +52,78 @@ export const LOOT_DROPS: Record = { minFloor: 15, dropChance: 0.07, }, + manaCrystal: { + id: 'manaCrystal', + name: 'Mana Crystal', + rarity: 'uncommon', + type: 'material', + minFloor: 5, + dropChance: 0.10, + }, + fireCrystal: { + id: 'fireCrystal', + name: 'Fire Attuned Crystal', + rarity: 'rare', + type: 'material', + minFloor: 15, + dropChance: 0.06, + }, + waterCrystal: { + id: 'waterCrystal', + name: 'Water Attuned Crystal', + rarity: 'rare', + type: 'material', + minFloor: 15, + dropChance: 0.06, + }, + airCrystal: { + id: 'airCrystal', + name: 'Air Attuned Crystal', + rarity: 'rare', + type: 'material', + minFloor: 15, + dropChance: 0.06, + }, + earthCrystal: { + id: 'earthCrystal', + name: 'Earth Attuned Crystal', + rarity: 'rare', + type: 'material', + minFloor: 15, + dropChance: 0.06, + }, + lightCrystal: { + id: 'lightCrystal', + name: 'Light Attuned Crystal', + rarity: 'rare', + type: 'material', + minFloor: 25, + dropChance: 0.05, + }, + darkCrystal: { + id: 'darkCrystal', + name: 'Dark Attuned Crystal', + rarity: 'rare', + type: 'material', + minFloor: 25, + dropChance: 0.05, + }, + metalCrystal: { + id: 'metalCrystal', + name: 'Metal Attuned Crystal', + rarity: 'rare', + type: 'material', + minFloor: 30, + dropChance: 0.05, + }, + crystalCrystal: { + id: 'crystalCrystal', + name: 'Crystal Attuned Crystal', + rarity: 'epic', + type: 'material', + minFloor: 40, + dropChance: 0.03, + }, elementalCore: { id: 'elementalCore', name: 'Elemental Core', diff --git a/src/lib/game/data/material-recipes.ts b/src/lib/game/data/material-recipes.ts new file mode 100644 index 0000000..7258848 --- /dev/null +++ b/src/lib/game/data/material-recipes.ts @@ -0,0 +1,184 @@ +// ─── Material Crafting Recipes ──────────────────────────────────────────────── +// Recipes that produce materials rather than equipment. +// All recipes use the FabricatorRecipe interface with recipeType: 'material'. + +import type { FabricatorRecipe } from './fabricator-recipes'; + +export const MATERIAL_RECIPES: FabricatorRecipe[] = [ + { + id: 'manaCrystal', + name: 'Mana Crystal', + description: 'Condense raw mana into a stable crystal. Used in all advanced crafting.', + manaType: 'raw', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: {}, + manaCost: 500, + craftTime: 1, + rarity: 'uncommon', + gearTrait: 'Produces 1 Mana Crystal', + recipeType: 'material', + resultMaterial: 'manaCrystal', + resultAmount: 1, + }, + { + id: 'manaCrystalDustCraft', + name: 'Mana Crystal Dust', + description: 'Grind a Mana Crystal into dust. Used as a base material.', + manaType: 'raw', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 1 }, + manaCost: 10, + craftTime: 1, + rarity: 'common', + gearTrait: 'Produces 2 Mana Crystal Dust', + recipeType: 'material', + resultMaterial: 'manaCrystalDust', + resultAmount: 2, + }, + { + id: 'fireCrystal', + name: 'Fire Attuned Crystal', + description: 'Infuse a Mana Crystal with fire mana to attune it to the flame element.', + manaType: 'fire', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 1 }, + manaCost: 100, + craftTime: 1, + rarity: 'rare', + gearTrait: 'Produces 1 Fire Attuned Crystal', + recipeType: 'material', + resultMaterial: 'fireCrystal', + resultAmount: 1, + }, + { + id: 'waterCrystal', + name: 'Water Attuned Crystal', + description: 'Infuse a Mana Crystal with water mana to attune it to the flow element.', + manaType: 'water', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 1 }, + manaCost: 100, + craftTime: 1, + rarity: 'rare', + gearTrait: 'Produces 1 Water Attuned Crystal', + recipeType: 'material', + resultMaterial: 'waterCrystal', + resultAmount: 1, + }, + { + id: 'airCrystal', + name: 'Air Attuned Crystal', + description: 'Infuse a Mana Crystal with air mana to attune it to the wind element.', + manaType: 'air', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 1 }, + manaCost: 100, + craftTime: 1, + rarity: 'rare', + gearTrait: 'Produces 1 Air Attuned Crystal', + recipeType: 'material', + resultMaterial: 'airCrystal', + resultAmount: 1, + }, + { + id: 'earthCrystal', + name: 'Earth Attuned Crystal', + description: 'Infuse a Mana Crystal with earth mana to attune it to the stone element.', + manaType: 'earth', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 1 }, + manaCost: 100, + craftTime: 1, + rarity: 'rare', + gearTrait: 'Produces 1 Earth Attuned Crystal', + recipeType: 'material', + resultMaterial: 'earthCrystal', + resultAmount: 1, + }, + { + id: 'lightCrystal', + name: 'Light Attuned Crystal', + description: 'Infuse a Mana Crystal with light mana to attune it to the radiant element.', + manaType: 'light', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 1 }, + manaCost: 100, + craftTime: 1, + rarity: 'rare', + gearTrait: 'Produces 1 Light Attuned Crystal', + recipeType: 'material', + resultMaterial: 'lightCrystal', + resultAmount: 1, + }, + { + id: 'darkCrystal', + name: 'Dark Attuned Crystal', + description: 'Infuse a Mana Crystal with dark mana to attune it to the shadow element.', + manaType: 'dark', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 1 }, + manaCost: 100, + craftTime: 1, + rarity: 'rare', + gearTrait: 'Produces 1 Dark Attuned Crystal', + recipeType: 'material', + resultMaterial: 'darkCrystal', + resultAmount: 1, + }, + { + id: 'metalCrystal', + name: 'Metal Attuned Crystal', + description: 'Infuse a Mana Crystal with metal mana to attune it to the alloy element.', + manaType: 'metal', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 1 }, + manaCost: 100, + craftTime: 1, + rarity: 'rare', + gearTrait: 'Produces 1 Metal Attuned Crystal', + recipeType: 'material', + resultMaterial: 'metalCrystal', + resultAmount: 1, + }, + { + id: 'crystalCrystal', + name: 'Crystal Attuned Crystal', + description: 'Infuse a Mana Crystal with crystal mana to attune it to the prismatic element.', + manaType: 'crystal', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 1 }, + manaCost: 100, + craftTime: 1, + rarity: 'epic', + gearTrait: 'Produces 1 Crystal Attuned Crystal', + recipeType: 'material', + resultMaterial: 'crystalCrystal', + resultAmount: 1, + }, + { + id: 'elementalCore', + name: 'Elemental Core', + description: 'Combine mana crystals and all four base elements into a powerful core.', + manaType: 'raw', + equipmentTypeId: 'basicStaff', + slot: 'mainHand', + materials: { manaCrystal: 10 }, + manaCost: 100, + craftTime: 10, + rarity: 'epic', + gearTrait: 'Produces 1 Elemental Core', + recipeType: 'material', + resultMaterial: 'elementalCore', + resultAmount: 1, + }, +]; diff --git a/src/lib/game/stores/craftingStore.ts b/src/lib/game/stores/craftingStore.ts index 01d1c92..ed83706 100644 --- a/src/lib/game/stores/craftingStore.ts +++ b/src/lib/game/stores/craftingStore.ts @@ -22,6 +22,7 @@ import { deductMaterials, makeFabricatorProgress, } from '../crafting-fabricator'; +import { craftMaterial as craftMaterialAction } from '../crafting-actions/crafting-material-actions'; export const useCraftingStore = create()( persist( @@ -198,45 +199,29 @@ export const useCraftingStore = create()( useCombatStore.setState({ currentAction: 'meditate' }); }, - // Equipment crafting actions startCraftingEquipment: (blueprintId: string) => { const state = get(); const rawMana = useManaStore.getState().rawMana; const currentAction = useCombatStore.getState().currentAction; - - // Check if we can start crafting const check = CraftingEquipment.canStartEquipmentCrafting( blueprintId, state.lootInventory.blueprints.includes(blueprintId), state.lootInventory.materials, rawMana, - currentAction + currentAction, ); - if (!check.canCraft) return false; - - // Initialize crafting const result = CraftingEquipment.initializeEquipmentCrafting( blueprintId, state.lootInventory.materials, - rawMana + rawMana, ); - - // Update crafting store state set((s) => ({ - lootInventory: { - ...s.lootInventory, - materials: result.newMaterials, - }, + lootInventory: { ...s.lootInventory, materials: result.newMaterials }, equipmentCraftingProgress: result.progress, })); - - // Update mana store (deduct mana) useManaStore.setState((s) => ({ rawMana: s.rawMana - result.manaCost })); - - // Update combat store (set current action) useCombatStore.setState({ currentAction: 'craft' }); - return true; }, @@ -274,6 +259,17 @@ export const useCraftingStore = create()( return true; }, + // Material crafting — instant crafting of materials + craftMaterial: (recipeId: string) => { + const state = get(); + const result = craftMaterialAction(recipeId, state.lootInventory.materials); + if (!result.success) return false; + if (result.newMaterials) { + set((s) => ({ lootInventory: { ...s.lootInventory, materials: result.newMaterials! } })); + } + return true; + }, + // Enchantment selection actions setSelectedEquipmentType: (type) => { set((s) => ({ enchantmentSelection: { ...s.enchantmentSelection, selectedEquipmentType: type }})); diff --git a/src/lib/game/stores/craftingStore.types.ts b/src/lib/game/stores/craftingStore.types.ts index cb9e4cb..894cc6e 100644 --- a/src/lib/game/stores/craftingStore.types.ts +++ b/src/lib/game/stores/craftingStore.types.ts @@ -62,6 +62,7 @@ export interface CraftingActions { unequipItem: (slot: EquipmentSlot) => void; startCraftingEquipment: (blueprintId: string) => boolean; startFabricatorCrafting: (recipeId: string) => boolean; + craftMaterial: (recipeId: string) => boolean; cancelEquipmentCrafting: () => void; setSelectedEquipmentType: (type: string | null) => void; setSelectedEffects: (effects: DesignEffect[]) => void;