diff --git a/STATS_TAB_INVESTIGATION_REPORT.md b/STATS_TAB_INVESTIGATION_REPORT.md deleted file mode 100644 index 9f438d8..0000000 --- a/STATS_TAB_INVESTIGATION_REPORT.md +++ /dev/null @@ -1,94 +0,0 @@ -# StatsTab Loading Bug Investigation Report - -## Critical Issue Found - -**Main Problem**: The `StatsTab.tsx` component has incorrect import paths that prevent it from loading. All section imports use the pattern `./StatsTab/...` instead of `./` which causes TypeScript compilation failures. - -### Root Cause Analysis - -1. **Incorrect Import Paths**: In `StatsTab.tsx`, sections are imported with incorrect relative paths: - ```typescript - // BROKEN: All these imports are wrong - import { ManaStatsSection } from './StatsTab/ManaStatsSection'; - import { CombatStatsSection } from './StatsTab/CombatStatsSection'; - import { PactStatusSection } from './StatsTab/PactStatusSection'; - import { StudyStatsSection } from './StatsTab/StudyStatsSection'; - import { ElementStatsSection } from './StatsTab/ElementStatsSection'; - import { LoopStatsSection } from './StatsTab/LoopStatsSection'; - - // CORRECT (pattern used by other tabs): - // import { ComponentName } from './ComponentName'; - ``` - -2. **Missing Test Files**: No test files exist for StatsTab, unlike other tabs which have comprehensive test coverage. - -3. **TypeScript Compilation Status**: The codebase has significant other TypeScript errors, but StatsTab itself would fail to compile due to the import resolution errors. - -### File Structure Analysis - -``` -src/components/game/tabs/ -├── StatsTab/ ← Directory contains section files -│ ├── CombatStatsSection.tsx -│ ├── ElementStatsSection.tsx -│ ├── LoopStatsSection.tsx -│ ├── ManaStatsSection.tsx -│ ├── PactStatusSection.tsx -│ └── StudyStatsSection.tsx -└── StatsTab.tsx ← Main component file expecting nested 'StatsTab/' paths -``` - -### Impact - -- StatsTab does not load due to import resolution errors -- Application fails to compile for StatsTab modules -- No way to access character stats information - -### Comparison with Other Tabs - -All other tabs follow the correct pattern: - -**EquipmentTab.tsx** (lines 7-9): -```typescript -import { EquipmentSlotGrid } from './EquipmentTab/EquipmentSlotGrid'; -import { InventoryList } from './EquipmentTab/InventoryList'; -import { EquipmentEffectsSummary } from './EquipmentTab/EquipmentEffectsSummary'; -``` - -Note: EquipmentTab uses `./EquipmentTab/...` pattern while StatsTab incorrectly uses `./StatsTab/...` pattern relative to StatsTab.tsx. - -### Recommended Fix - -Change all import paths in `StatsTab.tsx` from: -```typescript -import { SectionName } from './StatsTab/SectionName'; -``` - -To: -```typescript -import { SectionName } from './SectionName'; -``` - -This will make all section files resolve correctly since they're located directly in the `StatsTab/` directory. - -### Files Read - -- ✅ StatsTab.tsx (main component) -- ✅ ManaStatsSection.tsx -- ✅ CombatStatsSection.tsx -- ✅ ElementStatsSection.tsx -- ✅ LoopStatsSection.tsx -- ✅ PactStatusSection.tsx -- ✅ StudyStatsSection.tsx -- ✅ index.ts (showing StatsTab export) - -### Assessment - -**Clear Root Cause**: The incorrect import paths prevent the component from loading. Fixing these import paths will resolve the issue. - -**Likely Guiding Factors**: -1. File was moved or renamed after being created, causing import paths to become stale -2. Developer accidentally referenced the directory name in import paths -3. Copy-paste error when creating StatsTab from another tab template - -The fix is straightforward: correct all six import statements to use the proper relative path. \ No newline at end of file diff --git a/docs/circular-deps.txt b/docs/circular-deps.txt index 1dbe844..225e5db 100644 --- a/docs/circular-deps.txt +++ b/docs/circular-deps.txt @@ -1,11 +1,4 @@ # Circular Dependencies -Generated: 2026-05-27T12:13:52.087Z -Found: 1 circular chain(s) — these MUST be fixed before modifying involved files. +Generated: 2026-05-27T12:39:49.991Z -1. 1) data/fabricator-recipes.ts > data/material-recipes.ts - -## How to fix -1. Identify which import in the chain can be extracted to a shared types/utils file. -2. Move the shared type or function there. -3. Both files import from the new shared module instead of each other. -4. Run: bunx madge --circular src/lib/game (should return clean) \ No newline at end of file +No circular dependencies found. ✅ diff --git a/docs/dependency-graph.json b/docs/dependency-graph.json index 9efc8e4..ca7311b 100644 --- a/docs/dependency-graph.json +++ b/docs/dependency-graph.json @@ -1,6 +1,6 @@ { "_meta": { - "generated": "2026-05-27T12:13:50.329Z", + "generated": "2026-05-27T12:39:48.093Z", "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." }, @@ -365,9 +365,11 @@ "data/equipment/equipment-types-data.ts", "data/equipment/types.ts" ], + "data/fabricator-recipe-types.ts": [ + "data/equipment/types.ts" + ], "data/fabricator-recipes.ts": [ - "data/equipment/types.ts", - "data/material-recipes.ts" + "data/fabricator-recipe-types.ts" ], "data/golems/base-golems.ts": [ "data/golems/types.ts" @@ -405,9 +407,6 @@ "data/loot-drops.ts": [ "types/game.ts" ], - "data/material-recipes.ts": [ - "data/fabricator-recipes.ts" - ], "effects.ts": [ "data/enchantment-effects.ts", "effects/discipline-effects.ts", diff --git a/docs/project-structure.txt b/docs/project-structure.txt index 18b5d8f..2ef42f6 100644 --- a/docs/project-structure.txt +++ b/docs/project-structure.txt @@ -313,8 +313,11 @@ Mana-Loop/ │ │ │ ├── crafting-recipes.ts │ │ │ ├── enchantment-effects.ts │ │ │ ├── enchantment-types.ts +│ │ │ ├── fabricator-material-recipes.ts +│ │ │ ├── fabricator-physical-recipes.ts │ │ │ ├── fabricator-recipe-types.ts │ │ │ ├── fabricator-recipes.ts +│ │ │ ├── fabricator-wizard-recipes.ts │ │ │ ├── guardian-data.ts │ │ │ ├── guardian-encounters.ts │ │ │ └── loot-drops.ts @@ -389,7 +392,6 @@ Mana-Loop/ ├── Caddyfile ├── Dockerfile ├── README.md -├── STATS_TAB_INVESTIGATION_REPORT.md ├── bun.lock ├── bunfig.toml ├── components.json diff --git a/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx b/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx index 7292ab1..757cf04 100644 --- a/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx +++ b/src/components/game/tabs/CraftingTab/FabricatorSubTab.tsx @@ -7,7 +7,7 @@ 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, FlaskConical, Hammer, Package } from 'lucide-react'; +import { Anvil, FlaskConical, Hammer, Package, Sparkles, Sword } from 'lucide-react'; import { MaterialRecipeCard } from './MaterialRecipeCard'; import { FABRICATOR_RECIPES, @@ -20,6 +20,24 @@ 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 BRANCH_RECIPE_IDS = new Set([ + 'oakStaff', 'arcanistStaff', 'battlestaff', 'arcanistCirclet', 'arcanistRobe', + 'voidCatalyst', 'arcanistPendant', + 'crystalBlade', 'arcanistBlade', 'voidBlade', 'battleHelm', 'battleRobe', + 'battleBoots', 'combatGauntlets', 'runicShield', 'manaShield', +]); + +function isWizardBranch(recipe: FabricatorRecipe): boolean { + return ['oakStaff', 'arcanistStaff', 'battlestaff', 'arcanistCirclet', + 'arcanistRobe', 'voidCatalyst', 'arcanistPendant'].includes(recipe.id); +} + +function isPhysicalBranch(recipe: FabricatorRecipe): boolean { + return ['crystalBlade', 'arcanistBlade', 'voidBlade', 'battleHelm', + 'battleRobe', 'battleBoots', 'combatGauntlets', 'runicShield', + 'manaShield'].includes(recipe.id); +} + function RecipeCard({ recipe, materials, @@ -35,7 +53,6 @@ function RecipeCard({ onCraft: (recipe: FabricatorRecipe) => void; isCrafting: boolean; }) { - // Determine the correct mana amount based on the recipe's mana type const pool = recipe.manaType === 'raw' ? rawMana : (elementalMana[recipe.manaType]?.current ?? 0); @@ -111,9 +128,12 @@ function RecipeCard({ ); } +type BranchFilter = 'all' | 'elemental' | 'wizard' | 'physical'; + export function FabricatorSubTab() { const [selectedManaType, setSelectedManaType] = useState('earth'); const [activeSection, setActiveSection] = useState<'equipment' | 'materials'>('equipment'); + const [branchFilter, setBranchFilter] = useState('all'); const lootInventory = useCraftingStore((s) => s.lootInventory); const equipmentCraftingProgress = useCraftingStore((s) => s.equipmentCraftingProgress); @@ -127,10 +147,17 @@ export function FabricatorSubTab() { return [...new Set(FABRICATOR_RECIPES.map((r) => r.manaType))]; }, []); - const filteredRecipes = useMemo( - () => getRecipesByManaType(selectedManaType), - [selectedManaType], - ); + const filteredRecipes = useMemo(() => { + let recipes = FABRICATOR_RECIPES; + if (branchFilter === 'elemental') { + recipes = recipes.filter(r => !BRANCH_RECIPE_IDS.has(r.id)); + } else if (branchFilter === 'wizard') { + recipes = recipes.filter(r => isWizardBranch(r)); + } else if (branchFilter === 'physical') { + recipes = recipes.filter(r => isPhysicalBranch(r)); + } + return recipes.filter(r => r.manaType === selectedManaType); + }, [selectedManaType, branchFilter]); const isCrafting = equipmentCraftingProgress !== null; @@ -166,20 +193,58 @@ export function FabricatorSubTab() { - {/* Mana type filter — only for equipment */} + {/* Branch filter — only for equipment */} {activeSection === 'equipment' && ( -
- {availableManaTypes.map((mt) => ( + <> +
- ))} -
+ + + +
+ + {/* Mana type filter */} +
+ {availableManaTypes.map((mt) => ( + + ))} +
+ )}
diff --git a/src/lib/game/data/fabricator-material-recipes.ts b/src/lib/game/data/fabricator-material-recipes.ts new file mode 100644 index 0000000..4fd51e2 --- /dev/null +++ b/src/lib/game/data/fabricator-material-recipes.ts @@ -0,0 +1,183 @@ +// ─── Material Crafting Recipes ───────────────────────────────────────────────── +// Separate file to keep equipment recipes under the 400-line limit. + +import type { FabricatorRecipe } from './fabricator-recipe-types'; + +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/data/fabricator-physical-recipes.ts b/src/lib/game/data/fabricator-physical-recipes.ts new file mode 100644 index 0000000..40d2e4b --- /dev/null +++ b/src/lib/game/data/fabricator-physical-recipes.ts @@ -0,0 +1,125 @@ +// ─── Physical Branch Recipes ──────────────────────────────────────────────────── +// Sword, speed, and combat gear focused on attack speed, damage, and combat +// effectiveness. + +import type { FabricatorRecipe } from './fabricator-recipe-types'; + +export const PHYSICAL_BRANCH_RECIPES: FabricatorRecipe[] = [ + { + id: 'crystalBlade', + name: 'Crystal Blade', + description: 'A blade made of crystallized mana. Excellent for elemental enchantments.', + manaType: 'crystal', + equipmentTypeId: 'crystalBlade', + slot: 'mainHand', + materials: { manaCrystalDust: 8, crystalShard: 4, elementalCore: 2 }, + manaCost: 500, + craftTime: 5, + rarity: 'rare', + gearTrait: '+20% Cast Speed, +15% Spell Damage', + }, + { + id: 'arcanistBlade', + name: 'Arcanist Blade', + description: 'A sword forged for battle mages. High capacity for powerful enchantments.', + manaType: 'metal', + equipmentTypeId: 'arcanistBlade', + slot: 'mainHand', + materials: { manaCrystalDust: 10, metalShard: 5, elementalCore: 3 }, + manaCost: 600, + craftTime: 7, + rarity: 'epic', + gearTrait: '+15% Spell Damage, +15% Cast Speed, +10% Enchantment Power', + }, + { + id: 'voidBlade', + name: 'Void-Touched Blade', + description: 'A blade corrupted by void energy. Powerful but consumes more mana.', + manaType: 'crystal', + equipmentTypeId: 'voidBlade', + slot: 'mainHand', + materials: { manaCrystalDust: 9, darkCrystal: 3, voidEssence: 2, elementalCore: 2 }, + manaCost: 550, + craftTime: 6, + rarity: 'epic', + gearTrait: '+25% Spell Damage, +10% Attack Speed', + }, + { + id: 'battleHelm', + name: 'Battle Helm', + description: 'A sturdy helm for battle mages. Balances protection with magical capacity.', + manaType: 'metal', + equipmentTypeId: 'battleHelm', + slot: 'head', + materials: { manaCrystalDust: 6, metalShard: 3, elementalCore: 1 }, + manaCost: 350, + craftTime: 4, + rarity: 'rare', + gearTrait: '+10% Spell Damage, +15% Attack Speed', + }, + { + id: 'battleRobe', + name: 'Battle Robe', + description: 'A reinforced robe designed for combat mages. Durable without sacrificing capacity.', + manaType: 'sand', + equipmentTypeId: 'battleRobe', + slot: 'body', + materials: { manaCrystalDust: 8, sandShard: 3, elementalCore: 2 }, + manaCost: 400, + craftTime: 5, + rarity: 'rare', + gearTrait: '+15% Cast Speed, +10% Evasion', + }, + { + id: 'battleBoots', + name: 'Battle Boots', + description: 'Sturdy boots for combat situations. Lightweight yet protective.', + manaType: 'sand', + equipmentTypeId: 'battleBoots', + slot: 'feet', + materials: { manaCrystalDust: 4, sandShard: 2 }, + manaCost: 180, + craftTime: 3, + rarity: 'uncommon', + gearTrait: '+12% Cast Speed, +8% Attack Speed', + }, + { + id: 'combatGauntlets', + name: 'Combat Gauntlets', + description: 'Armored gauntlets for battle mages. Enhances both casting and melee.', + manaType: 'metal', + equipmentTypeId: 'combatGauntlets', + slot: 'hands', + materials: { manaCrystalDust: 5, metalShard: 2, elementalCore: 1 }, + manaCost: 300, + craftTime: 3, + rarity: 'uncommon', + gearTrait: '+10% Attack Speed, +10% Cast Speed', + }, + { + id: 'runicShield', + name: 'Runic Shield', + description: 'A shield engraved with protective runes. Excellent for defensive enchantments.', + manaType: 'earth', + equipmentTypeId: 'runicShield', + slot: 'offHand', + materials: { manaCrystalDust: 8, earthShard: 4, elementalCore: 2 }, + manaCost: 450, + craftTime: 5, + rarity: 'rare', + gearTrait: '+20% Defensive Enchantment Power, +25 Earth Mana Capacity', + }, + { + id: 'manaShield', + name: 'Mana Shield', + description: 'A crystalline shield that can store and reflect mana. Deadly in the right hands.', + manaType: 'crystal', + equipmentTypeId: 'manaShield', + slot: 'offHand', + materials: { manaCrystalDust: 10, crystalShard: 5, elementalCore: 2 }, + manaCost: 550, + craftTime: 6, + rarity: 'epic', + gearTrait: '+15% Spell Damage, +15% Defensive Enchantment Power', + }, +]; diff --git a/src/lib/game/data/fabricator-recipes.ts b/src/lib/game/data/fabricator-recipes.ts index 7ec0e9d..f940ae8 100644 --- a/src/lib/game/data/fabricator-recipes.ts +++ b/src/lib/game/data/fabricator-recipes.ts @@ -1,10 +1,15 @@ -// ─── Fabricator Recipes ────────────────────────────────────────────────────── -// Crafting recipes for the Fabricator attunement. -// Each recipe is tied to a mana type the player has unlocked. +// ─── Fabricator Equipment Recipes ────────────────────────────────────────────── +// Core and elemental recipes. Branch recipes are in separate files. +// Material recipes are in fabricator-material-recipes.ts. +import type { FabricatorRecipe } from './fabricator-recipe-types'; export type { FabricatorRecipe, MANA_TYPE_LABELS } from './fabricator-recipe-types'; +export { MATERIAL_RECIPES } from './fabricator-material-recipes'; +export { WIZARD_BRANCH_RECIPES } from './fabricator-wizard-recipes'; +export { PHYSICAL_BRANCH_RECIPES } from './fabricator-physical-recipes'; - +import { WIZARD_BRANCH_RECIPES } from './fabricator-wizard-recipes'; +import { PHYSICAL_BRANCH_RECIPES } from './fabricator-physical-recipes'; export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ // ─── Earth Gear (Compacted Earth — high defense) ────────────────────── @@ -171,187 +176,9 @@ export const FABRICATOR_RECIPES: FabricatorRecipe[] = [ gearTrait: '+20% cast speed, +5% evasion', }, -]; - -// ─── Material Crafting 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, - }, + // ─── Branch recipes ─────────────────────────────────────────────────── + ...WIZARD_BRANCH_RECIPES, + ...PHYSICAL_BRANCH_RECIPES, ]; // ─── Helpers ────────────────────────────────────────────────────────────────── @@ -361,7 +188,7 @@ export function getRecipesByManaType(manaType: string): FabricatorRecipe[] { } export function getRecipeById(id: string): FabricatorRecipe | undefined { - return FABRICATOR_RECIPES.find(r => r.id === id) ?? MATERIAL_RECIPES.find(r => r.id === id); + return FABRICATOR_RECIPES.find(r => r.id === id); } export function canCraftRecipe( @@ -381,9 +208,6 @@ export function canCraftRecipe( } } - // If manaType is provided, manaAmount is already the correct pool value. - // Otherwise fall back to treating manaAmount as raw mana (backward compat). - const effectiveManaType = manaType ?? recipe.manaType; const missingMana = Math.max(0, recipe.manaCost - manaAmount); if (missingMana > 0) { canCraft = false; diff --git a/src/lib/game/data/fabricator-wizard-recipes.ts b/src/lib/game/data/fabricator-wizard-recipes.ts new file mode 100644 index 0000000..15be2f7 --- /dev/null +++ b/src/lib/game/data/fabricator-wizard-recipes.ts @@ -0,0 +1,99 @@ +// ─── Wizard Branch Recipes ───────────────────────────────────────────────────── +// Staff, crown/circlet, and catalyst gear focused on mana capacity, regen, +// enchantment power, and spell casting. + +import type { FabricatorRecipe } from './fabricator-recipe-types'; + +export const WIZARD_BRANCH_RECIPES: FabricatorRecipe[] = [ + { + id: 'oakStaff', + name: 'Oak Staff', + description: 'A sturdy oak staff with decent mana capacity. Reliable for extended casting.', + manaType: 'earth', + equipmentTypeId: 'oakStaff', + slot: 'mainHand', + materials: { manaCrystalDust: 5, earthShard: 2 }, + manaCost: 200, + craftTime: 3, + rarity: 'uncommon', + gearTrait: '+15% Mana Regen, +20 Earth Mana Capacity', + }, + { + id: 'arcanistStaff', + name: 'Arcanist Staff', + description: 'A staff designed for advanced spellcasters. High capacity for complex enchantments.', + manaType: 'crystal', + equipmentTypeId: 'arcanistStaff', + slot: 'mainHand', + materials: { manaCrystalDust: 12, crystalShard: 6, elementalCore: 3 }, + manaCost: 700, + craftTime: 8, + rarity: 'epic', + gearTrait: '+30% Enchantment Capacity, +20% Mana Regen', + }, + { + id: 'battlestaff', + name: 'Battlestaff', + description: 'A reinforced staff suitable for both casting and combat. Balanced and sturdy.', + manaType: 'metal', + equipmentTypeId: 'battlestaff', + slot: 'mainHand', + materials: { manaCrystalDust: 8, metalShard: 4, elementalCore: 2 }, + manaCost: 500, + craftTime: 6, + rarity: 'rare', + gearTrait: '+10% Enchantment Power, +10% Cast Speed', + }, + { + id: 'arcanistCirclet', + name: 'Arcanist Circlet', + description: 'A silver circlet worn by accomplished arcanists. Sharpens mental focus.', + manaType: 'crystal', + equipmentTypeId: 'arcanistCirclet', + slot: 'head', + materials: { manaCrystalDust: 6, crystalShard: 2, lightCrystal: 1 }, + manaCost: 300, + craftTime: 4, + rarity: 'rare', + gearTrait: '+20% Enchantment Power, +15 Light Mana Capacity', + }, + { + id: 'arcanistRobe', + name: 'Arcanist Robe', + description: 'An ornate robe for master arcanists. High capacity for body armor.', + manaType: 'crystal', + equipmentTypeId: 'arcanistRobe', + slot: 'body', + materials: { manaCrystalDust: 14, crystalShard: 7, elementalCore: 3 }, + manaCost: 800, + craftTime: 8, + rarity: 'epic', + gearTrait: '+35% Enchantment Capacity, +10% all Mana Regen', + }, + { + id: 'voidCatalyst', + name: 'Void Catalyst', + description: 'A rare catalyst touched by void energy. High capacity but volatile.', + manaType: 'crystal', + equipmentTypeId: 'voidCatalyst', + slot: 'mainHand', + materials: { manaCrystalDust: 10, darkCrystal: 3, voidEssence: 2, elementalCore: 2 }, + manaCost: 600, + craftTime: 7, + rarity: 'epic', + gearTrait: '+30% Dark Enchantment Power, +15% Spell Damage', + }, + { + id: 'arcanistPendant', + name: 'Arcanist Pendant', + description: 'A powerful pendant worn by master arcanists. Amplifies all enchantment effects.', + manaType: 'crystal', + equipmentTypeId: 'arcanistPendant', + slot: 'accessory1', + materials: { manaCrystalDust: 8, crystalShard: 4, elementalCore: 2 }, + manaCost: 500, + craftTime: 5, + rarity: 'epic', + gearTrait: '+15% all enchantment effects, +10% Mana Regen', + }, +];