Refactor large files into modular components
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m9s

- Refactored page.tsx (613→252 lines) with GameOverScreen and LeftPanel extracted
- Refactored StatsTab.tsx (584→92 lines) with section components
- Refactored SkillsTab.tsx (434→54 lines) with sub-components
- Created modular structure for GameContext, LootInventory, and other components
- All extracted components organized into feature directories
This commit is contained in:
Refactoring Agent
2026-05-02 17:35:03 +02:00
parent c9ae2576f4
commit d2d28887b1
194 changed files with 16862 additions and 15729 deletions
@@ -1,473 +0,0 @@
// ─── Spell Enchantment Effects ────────────────────────────────────────────────
// All spell-related enchantment effects that can be applied to equipment
import type { EquipmentCategory } from '../equipment'
import type { EnchantmentEffectDef } from '../enchantment-types'
// Helper to define allowed equipment categories for each effect type
const ALL_CASTER: EquipmentCategory[] = ['caster']
export const SPELL_EFFECTS: Record<string, EnchantmentEffectDef> = {
// ═══════════════════════════════════════════════════════════════════════════
// SPELL EFFECTS - Only for CASTER equipment (staves, wands, rods, orbs)
// ═══════════════════════════════════════════════════════════════════════════
// Tier 0 - Basic Spells
spell_manaBolt: {
id: 'spell_manaBolt',
name: 'Mana Bolt',
description: 'Grants the ability to cast Mana Bolt (5 base damage, raw mana cost)',
category: 'spell',
baseCapacityCost: 50,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'manaBolt' }
},
spell_manaStrike: {
id: 'spell_manaStrike',
name: 'Mana Strike',
description: 'Grants the ability to cast Mana Strike (8 base damage, raw mana cost)',
category: 'spell',
baseCapacityCost: 40,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'manaStrike' }
},
// Tier 1 - Basic Elemental Spells
spell_fireball: {
id: 'spell_fireball',
name: 'Fireball',
description: 'Grants the ability to cast Fireball (15 fire damage)',
category: 'spell',
baseCapacityCost: 80,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'fireball' }
},
spell_emberShot: {
id: 'spell_emberShot',
name: 'Ember Shot',
description: 'Grants the ability to cast Ember Shot (10 fire damage, fast cast)',
category: 'spell',
baseCapacityCost: 60,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'emberShot' }
},
spell_waterJet: {
id: 'spell_waterJet',
name: 'Water Jet',
description: 'Grants the ability to cast Water Jet (12 water damage)',
category: 'spell',
baseCapacityCost: 70,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'waterJet' }
},
spell_iceShard: {
id: 'spell_iceShard',
name: 'Ice Shard',
description: 'Grants the ability to cast Ice Shard (14 water damage)',
category: 'spell',
baseCapacityCost: 75,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'iceShard' }
},
spell_gust: {
id: 'spell_gust',
name: 'Gust',
description: 'Grants the ability to cast Gust (10 air damage, fast cast)',
category: 'spell',
baseCapacityCost: 60,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'gust' }
},
spell_stoneBullet: {
id: 'spell_stoneBullet',
name: 'Stone Bullet',
description: 'Grants the ability to cast Stone Bullet (16 earth damage)',
category: 'spell',
baseCapacityCost: 80,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'stoneBullet' }
},
spell_lightLance: {
id: 'spell_lightLance',
name: 'Light Lance',
description: 'Grants the ability to cast Light Lance (18 light damage)',
category: 'spell',
baseCapacityCost: 95,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'lightLance' }
},
spell_shadowBolt: {
id: 'spell_shadowBolt',
name: 'Shadow Bolt',
description: 'Grants the ability to cast Shadow Bolt (16 dark damage)',
category: 'spell',
baseCapacityCost: 95,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'shadowBolt' }
},
spell_drain: {
id: 'spell_drain',
name: 'Drain',
description: 'Grants the ability to cast Drain (10 death damage)',
category: 'spell',
baseCapacityCost: 85,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'drain' }
},
// Tier 2 - Advanced Spells
spell_inferno: {
id: 'spell_inferno',
name: 'Inferno',
description: 'Grants the ability to cast Inferno (60 fire damage)',
category: 'spell',
baseCapacityCost: 180,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'inferno' }
},
spell_tidalWave: {
id: 'spell_tidalWave',
name: 'Tidal Wave',
description: 'Grants the ability to cast Tidal Wave (55 water damage)',
category: 'spell',
baseCapacityCost: 175,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'tidalWave' }
},
spell_hurricane: {
id: 'spell_hurricane',
name: 'Hurricane',
description: 'Grants the ability to cast Hurricane (50 air damage)',
category: 'spell',
baseCapacityCost: 170,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'hurricane' }
},
spell_earthquake: {
id: 'spell_earthquake',
name: 'Earthquake',
description: 'Grants the ability to cast Earthquake (70 earth damage)',
category: 'spell',
baseCapacityCost: 200,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'earthquake' }
},
spell_solarFlare: {
id: 'spell_solarFlare',
name: 'Solar Flare',
description: 'Grants the ability to cast Solar Flare (65 light damage)',
category: 'spell',
baseCapacityCost: 190,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'solarFlare' }
},
spell_voidRift: {
id: 'spell_voidRift',
name: 'Void Rift',
description: 'Grants the ability to cast Void Rift (55 dark damage)',
category: 'spell',
baseCapacityCost: 175,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'voidRift' }
},
// Additional Tier 1 Spells
spell_windSlash: {
id: 'spell_windSlash',
name: 'Wind Slash',
description: 'Grants the ability to cast Wind Slash (12 air damage)',
category: 'spell',
baseCapacityCost: 72,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'windSlash' }
},
spell_rockSpike: {
id: 'spell_rockSpike',
name: 'Rock Spike',
description: 'Grants the ability to cast Rock Spike (18 earth damage)',
category: 'spell',
baseCapacityCost: 88,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'rockSpike' }
},
spell_radiance: {
id: 'spell_radiance',
name: 'Radiance',
description: 'Grants the ability to cast Radiance (14 light damage)',
category: 'spell',
baseCapacityCost: 80,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'radiance' }
},
spell_darkPulse: {
id: 'spell_darkPulse',
name: 'Dark Pulse',
description: 'Grants the ability to cast Dark Pulse (12 dark damage)',
category: 'spell',
baseCapacityCost: 68,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'darkPulse' }
},
// Additional Tier 2 Spells
spell_flameWave: {
id: 'spell_flameWave',
name: 'Flame Wave',
description: 'Grants the ability to cast Flame Wave (45 fire damage)',
category: 'spell',
baseCapacityCost: 165,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'flameWave' }
},
spell_iceStorm: {
id: 'spell_iceStorm',
name: 'Ice Storm',
description: 'Grants the ability to cast Ice Storm (50 water damage)',
category: 'spell',
baseCapacityCost: 170,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'iceStorm' }
},
spell_windBlade: {
id: 'spell_windBlade',
name: 'Wind Blade',
description: 'Grants the ability to cast Wind Blade (40 air damage)',
category: 'spell',
baseCapacityCost: 155,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'windBlade' }
},
spell_stoneBarrage: {
id: 'spell_stoneBarrage',
name: 'Stone Barrage',
description: 'Grants the ability to cast Stone Barrage (55 earth damage)',
category: 'spell',
baseCapacityCost: 175,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'stoneBarrage' }
},
spell_divineSmite: {
id: 'spell_divineSmite',
name: 'Divine Smite',
description: 'Grants the ability to cast Divine Smite (55 light damage)',
category: 'spell',
baseCapacityCost: 175,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'divineSmite' }
},
spell_shadowStorm: {
id: 'spell_shadowStorm',
name: 'Shadow Storm',
description: 'Grants the ability to cast Shadow Storm (48 dark damage)',
category: 'spell',
baseCapacityCost: 168,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'shadowStorm' }
},
// Tier 3 - Master Spells
spell_pyroclasm: {
id: 'spell_pyroclasm',
name: 'Pyroclasm',
description: 'Grants the ability to cast Pyroclasm (250 fire damage)',
category: 'spell',
baseCapacityCost: 400,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'pyroclasm' }
},
spell_tsunami: {
id: 'spell_tsunami',
name: 'Tsunami',
description: 'Grants the ability to cast Tsunami (220 water damage)',
category: 'spell',
baseCapacityCost: 380,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'tsunami' }
},
spell_meteorStrike: {
id: 'spell_meteorStrike',
name: 'Meteor Strike',
description: 'Grants the ability to cast Meteor Strike (280 earth damage)',
category: 'spell',
baseCapacityCost: 420,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'meteorStrike' }
},
// ═══════════════════════════════════════════════════════════════════════════
// LIGHTNING SPELL EFFECTS - Fast, armor-piercing, harder to dodge
// ═══════════════════════════════════════════════════════════════════════════
spell_spark: {
id: 'spell_spark',
name: 'Spark',
description: 'Grants the ability to cast Spark (8 lightning damage, very fast, armor pierce)',
category: 'spell',
baseCapacityCost: 70,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'spark' }
},
spell_lightningBolt: {
id: 'spell_lightningBolt',
name: 'Lightning Bolt',
description: 'Grants the ability to cast Lightning Bolt (14 lightning damage, armor pierce)',
category: 'spell',
baseCapacityCost: 90,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'lightningBolt' }
},
spell_chainLightning: {
id: 'spell_chainLightning',
name: 'Chain Lightning',
description: 'Grants the ability to cast Chain Lightning (25 lightning damage, hits 3 targets)',
category: 'spell',
baseCapacityCost: 160,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'chainLightning' }
},
spell_stormCall: {
id: 'spell_stormCall',
name: 'Storm Call',
description: 'Grants the ability to cast Storm Call (40 lightning damage, hits 2 targets)',
category: 'spell',
baseCapacityCost: 190,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'stormCall' }
},
spell_thunderStrike: {
id: 'spell_thunderStrike',
name: 'Thunder Strike',
description: 'Grants the ability to cast Thunder Strike (150 lightning damage, 50% armor pierce)',
category: 'spell',
baseCapacityCost: 350,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'thunderStrike' }
},
// ═══════════════════════════════════════════════════════════════════════════
// METAL SPELL EFFECTS - Fire + Earth compound, armor pierce focus
// ═══════════════════════════════════════════════════════════════════════════
spell_metalShard: {
id: 'spell_metalShard',
name: 'Metal Shard',
description: 'Grants the ability to cast Metal Shard (16 metal damage, 25% armor pierce)',
category: 'spell',
baseCapacityCost: 85,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'metalShard' }
},
spell_ironFist: {
id: 'spell_ironFist',
name: 'Iron Fist',
description: 'Grants the ability to cast Iron Fist (28 metal damage, 35% armor pierce)',
category: 'spell',
baseCapacityCost: 120,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'ironFist' }
},
spell_steelTempest: {
id: 'spell_steelTempest',
name: 'Steel Tempest',
description: 'Grants the ability to cast Steel Tempest (55 metal damage, 45% armor pierce)',
category: 'spell',
baseCapacityCost: 190,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'steelTempest' }
},
spell_furnaceBlast: {
id: 'spell_furnaceBlast',
name: 'Furnace Blast',
description: 'Grants the ability to cast Furnace Blast (200 metal damage, 60% armor pierce)',
category: 'spell',
baseCapacityCost: 400,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'furnaceBlast' }
},
// ═══════════════════════════════════════════════════════════════════════════
// SAND SPELL EFFECTS - Earth + Water compound, AOE focus
// ═══════════════════════════════════════════════════════════════════════════
spell_sandBlast: {
id: 'spell_sandBlast',
name: 'Sand Blast',
description: 'Grants the ability to cast Sand Blast (11 sand damage, very fast)',
category: 'spell',
baseCapacityCost: 72,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'sandBlast' }
},
spell_sandstorm: {
id: 'spell_sandstorm',
name: 'Sandstorm',
description: 'Grants the ability to cast Sandstorm (22 sand damage, hits 2 enemies)',
category: 'spell',
baseCapacityCost: 100,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'sandstorm' }
},
spell_desertWind: {
id: 'spell_desertWind',
name: 'Desert Wind',
description: 'Grants the ability to cast Desert Wind (38 sand damage, hits 3 enemies)',
category: 'spell',
baseCapacityCost: 155,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'desertWind' }
},
spell_duneCollapse: {
id: 'spell_duneCollapse',
name: 'Dune Collapse',
description: 'Grants the ability to cast Dune Collapse (100 sand damage, hits 5 enemies)',
category: 'spell',
baseCapacityCost: 300,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'duneCollapse' }
},
};
@@ -0,0 +1,162 @@
// ─── Tier 0 & 1 Basic Spells ───────────────────────────────────
import type { EnchantmentEffectDef } from './types';
import { ALL_CASTER } from './types';
export const BASIC_SPELL_EFFECTS: Record<string, EnchantmentEffectDef> = {
// Tier 0 - Basic Spells
spell_manaBolt: {
id: 'spell_manaBolt',
name: 'Mana Bolt',
description: 'Grants the ability to cast Mana Bolt (5 base damage, raw mana cost)',
category: 'spell',
baseCapacityCost: 50,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'manaBolt' }
},
spell_manaStrike: {
id: 'spell_manaStrike',
name: 'Mana Strike',
description: 'Grants the ability to cast Mana Strike (8 base damage, raw mana cost)',
category: 'spell',
baseCapacityCost: 40,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'manaStrike' }
},
// Tier 1 - Basic Elemental Spells
spell_fireball: {
id: 'spell_fireball',
name: 'Fireball',
description: 'Grants the ability to cast Fireball (15 fire damage)',
category: 'spell',
baseCapacityCost: 80,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'fireball' }
},
spell_emberShot: {
id: 'spell_emberShot',
name: 'Ember Shot',
description: 'Grants the ability to cast Ember Shot (10 fire damage, fast cast)',
category: 'spell',
baseCapacityCost: 60,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'emberShot' }
},
spell_waterJet: {
id: 'spell_waterJet',
name: 'Water Jet',
description: 'Grants the ability to cast Water Jet (12 water damage)',
category: 'spell',
baseCapacityCost: 70,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'waterJet' }
},
spell_iceShard: {
id: 'spell_iceShard',
name: 'Ice Shard',
description: 'Grants the ability to cast Ice Shard (14 water damage)',
category: 'spell',
baseCapacityCost: 75,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'iceShard' }
},
spell_gust: {
id: 'spell_gust',
name: 'Gust',
description: 'Grants the ability to cast Gust (10 air damage, fast cast)',
category: 'spell',
baseCapacityCost: 60,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'gust' }
},
spell_stoneBullet: {
id: 'spell_stoneBullet',
name: 'Stone Bullet',
description: 'Grants the ability to cast Stone Bullet (16 earth damage)',
category: 'spell',
baseCapacityCost: 80,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'stoneBullet' }
},
spell_lightLance: {
id: 'spell_lightLance',
name: 'Light Lance',
description: 'Grants the ability to cast Light Lance (18 light damage)',
category: 'spell',
baseCapacityCost: 95,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'lightLance' }
},
spell_shadowBolt: {
id: 'spell_shadowBolt',
name: 'Shadow Bolt',
description: 'Grants the ability to cast Shadow Bolt (16 dark damage)',
category: 'spell',
baseCapacityCost: 95,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'shadowBolt' }
},
spell_drain: {
id: 'spell_drain',
name: 'Drain',
description: 'Grants the ability to cast Drain (10 death damage)',
category: 'spell',
baseCapacityCost: 85,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'drain' }
},
// Additional Tier 1 Spells
spell_windSlash: {
id: 'spell_windSlash',
name: 'Wind Slash',
description: 'Grants the ability to cast Wind Slash (12 air damage)',
category: 'spell',
baseCapacityCost: 72,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'windSlash' }
},
spell_rockSpike: {
id: 'spell_rockSpike',
name: 'Rock Spike',
description: 'Grants the ability to cast Rock Spike (18 earth damage)',
category: 'spell',
baseCapacityCost: 88,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'rockSpike' }
},
spell_radiance: {
id: 'spell_radiance',
name: 'Radiance',
description: 'Grants the ability to cast Radiance (14 light damage)',
category: 'spell',
baseCapacityCost: 80,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'radiance' }
},
spell_darkPulse: {
id: 'spell_darkPulse',
name: 'Dark Pulse',
description: 'Grants the ability to cast Dark Pulse (12 dark damage)',
category: 'spell',
baseCapacityCost: 68,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'darkPulse' }
},
};
@@ -0,0 +1,8 @@
// ─── Spell Enchantment Effects Index ───────────────────────────────
// Re-exports all spell effects from modular files
// Re-export types
export type { EnchantmentEffectDef, ALL_CASTER } from './types';
// Re-export data
export { SPELL_EFFECTS } from './data';
@@ -0,0 +1,58 @@
// ─── Lightning Spell Effects ──────────────────────────────────
// Lightning spells - Fast, armor-piercing, harder to dodge
import type { EnchantmentEffectDef } from './types';
import { ALL_CASTER } from './types';
export const LIGHTNING_SPELL_EFFECTS: Record<string, EnchantmentEffectDef> = {
spell_spark: {
id: 'spell_spark',
name: 'Spark',
description: 'Grants the ability to cast Spark (8 lightning damage, very fast, armor pierce)',
category: 'spell',
baseCapacityCost: 70,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'spark' }
},
spell_lightningBolt: {
id: 'spell_lightningBolt',
name: 'Lightning Bolt',
description: 'Grants the ability to cast Lightning Bolt (14 lightning damage, armor pierce)',
category: 'spell',
baseCapacityCost: 90,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'lightningBolt' }
},
spell_chainLightning: {
id: 'spell_chainLightning',
name: 'Chain Lightning',
description: 'Grants the ability to cast Chain Lightning (25 lightning damage, hits 3 targets)',
category: 'spell',
baseCapacityCost: 160,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'chainLightning' }
},
spell_stormCall: {
id: 'spell_stormCall',
name: 'Storm Call',
description: 'Grants the ability to cast Storm Call (40 lightning damage, hits 2 targets)',
category: 'spell',
baseCapacityCost: 190,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'stormCall' }
},
spell_thunderStrike: {
id: 'spell_thunderStrike',
name: 'Thunder Strike',
description: 'Grants the ability to cast Thunder Strike (150 lightning damage, 50% armor pierce)',
category: 'spell',
baseCapacityCost: 350,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'thunderStrike' }
},
};
@@ -0,0 +1,48 @@
// ─── Metal Spell Effects ──────────────────────────────────────
// Metal spells - Fire + Earth compound, armor pierce focus
import type { EnchantmentEffectDef } from './types';
import { ALL_CASTER } from './types';
export const METAL_SPELL_EFFECTS: Record<string, EnchantmentEffectDef> = {
spell_metalShard: {
id: 'spell_metalShard',
name: 'Metal Shard',
description: 'Grants the ability to cast Metal Shard (16 metal damage, 25% armor pierce)',
category: 'spell',
baseCapacityCost: 85,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'metalShard' }
},
spell_ironFist: {
id: 'spell_ironFist',
name: 'Iron Fist',
description: 'Grants the ability to cast Iron Fist (28 metal damage, 35% armor pierce)',
category: 'spell',
baseCapacityCost: 120,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'ironFist' }
},
spell_steelTempest: {
id: 'spell_steelTempest',
name: 'Steel Tempest',
description: 'Grants the ability to cast Steel Tempest (55 metal damage, 45% armor pierce)',
category: 'spell',
baseCapacityCost: 190,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'steelTempest' }
},
spell_furnaceBlast: {
id: 'spell_furnaceBlast',
name: 'Furnace Blast',
description: 'Grants the ability to cast Furnace Blast (200 metal damage, 60% armor pierce)',
category: 'spell',
baseCapacityCost: 400,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'furnaceBlast' }
},
};
@@ -0,0 +1,48 @@
// ─── Sand Spell Effects ───────────────────────────────────────
// Sand spells - Earth + Water compound, AOE focus
import type { EnchantmentEffectDef } from './types';
import { ALL_CASTER } from './types';
export const SAND_SPELL_EFFECTS: Record<string, EnchantmentEffectDef> = {
spell_sandBlast: {
id: 'spell_sandBlast',
name: 'Sand Blast',
description: 'Grants the ability to cast Sand Blast (11 sand damage, very fast)',
category: 'spell',
baseCapacityCost: 72,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'sandBlast' }
},
spell_sandstorm: {
id: 'spell_sandstorm',
name: 'Sandstorm',
description: 'Grants the ability to cast Sandstorm (22 sand damage, hits 2 enemies)',
category: 'spell',
baseCapacityCost: 100,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'sandstorm' }
},
spell_desertWind: {
id: 'spell_desertWind',
name: 'Desert Wind',
description: 'Grants the ability to cast Desert Wind (38 sand damage, hits 3 enemies)',
category: 'spell',
baseCapacityCost: 155,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'desertWind' }
},
spell_duneCollapse: {
id: 'spell_duneCollapse',
name: 'Dune Collapse',
description: 'Grants the ability to cast Dune Collapse (100 sand damage, hits 5 enemies)',
category: 'spell',
baseCapacityCost: 300,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'duneCollapse' }
},
};
@@ -0,0 +1,129 @@
// ─── Tier 2 Advanced Spells ───────────────────────────────────
import type { EnchantmentEffectDef } from './types';
import { ALL_CASTER } from './types';
export const TIER2_SPELL_EFFECTS: Record<string, EnchantmentEffectDef> = {
spell_inferno: {
id: 'spell_inferno',
name: 'Inferno',
description: 'Grants the ability to cast Inferno (60 fire damage)',
category: 'spell',
baseCapacityCost: 180,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'inferno' }
},
spell_tidalWave: {
id: 'spell_tidalWave',
name: 'Tidal Wave',
description: 'Grants the ability to cast Tidal Wave (55 water damage)',
category: 'spell',
baseCapacityCost: 175,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'tidalWave' }
},
spell_hurricane: {
id: 'spell_hurricane',
name: 'Hurricane',
description: 'Grants the ability to cast Hurricane (50 air damage)',
category: 'spell',
baseCapacityCost: 170,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'hurricane' }
},
spell_earthquake: {
id: 'spell_earthquake',
name: 'Earthquake',
description: 'Grants the ability to cast Earthquake (70 earth damage)',
category: 'spell',
baseCapacityCost: 200,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'earthquake' }
},
spell_solarFlare: {
id: 'spell_solarFlare',
name: 'Solar Flare',
description: 'Grants the ability to cast Solar Flare (65 light damage)',
category: 'spell',
baseCapacityCost: 190,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'solarFlare' }
},
spell_voidRift: {
id: 'spell_voidRift',
name: 'Void Rift',
description: 'Grants the ability to cast Void Rift (55 dark damage)',
category: 'spell',
baseCapacityCost: 175,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'voidRift' }
},
// Additional Tier 2 Spells
spell_flameWave: {
id: 'spell_flameWave',
name: 'Flame Wave',
description: 'Grants the ability to cast Flame Wave (45 fire damage)',
category: 'spell',
baseCapacityCost: 165,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'flameWave' }
},
spell_iceStorm: {
id: 'spell_iceStorm',
name: 'Ice Storm',
description: 'Grants the ability to cast Ice Storm (50 water damage)',
category: 'spell',
baseCapacityCost: 170,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'iceStorm' }
},
spell_windBlade: {
id: 'spell_windBlade',
name: 'Wind Blade',
description: 'Grants the ability to cast Wind Blade (40 air damage)',
category: 'spell',
baseCapacityCost: 155,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'windBlade' }
},
spell_stoneBarrage: {
id: 'spell_stoneBarrage',
name: 'Stone Barrage',
description: 'Grants the ability to cast Stone Barrage (55 earth damage)',
category: 'spell',
baseCapacityCost: 175,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'stoneBarrage' }
},
spell_divineSmite: {
id: 'spell_divineSmite',
name: 'Divine Smite',
description: 'Grants the ability to cast Divine Smite (55 light damage)',
category: 'spell',
baseCapacityCost: 175,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'divineSmite' }
},
spell_shadowStorm: {
id: 'spell_shadowStorm',
name: 'Shadow Storm',
description: 'Grants the ability to cast Shadow Storm (48 dark damage)',
category: 'spell',
baseCapacityCost: 168,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'shadowStorm' }
},
};
@@ -0,0 +1,37 @@
// ─── Tier 3 Master Spells ─────────────────────────────────────
import type { EnchantmentEffectDef } from './types';
import { ALL_CASTER } from './types';
export const TIER3_SPELL_EFFECTS: Record<string, EnchantmentEffectDef> = {
spell_pyroclasm: {
id: 'spell_pyroclasm',
name: 'Pyroclasm',
description: 'Grants the ability to cast Pyroclasm (250 fire damage)',
category: 'spell',
baseCapacityCost: 400,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'pyroclasm' }
},
spell_tsunami: {
id: 'spell_tsunami',
name: 'Tsunami',
description: 'Grants the ability to cast Tsunami (220 water damage)',
category: 'spell',
baseCapacityCost: 380,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'tsunami' }
},
spell_meteorStrike: {
id: 'spell_meteorStrike',
name: 'Meteor Strike',
description: 'Grants the ability to cast Meteor Strike (280 earth damage)',
category: 'spell',
baseCapacityCost: 420,
maxStacks: 1,
allowedEquipmentCategories: ALL_CASTER,
effect: { type: 'spell', spellId: 'meteorStrike' }
},
};
@@ -0,0 +1,20 @@
// ─── Spell Enchantment Effects Types ─────────────────
export interface EnchantmentEffectDef {
id: string;
name: string;
description: string;
category: string;
baseCapacityCost: number;
maxStacks: number;
allowedEquipmentCategories: string[];
effect: {
type: string;
spellId?: string;
stat?: string;
value?: number;
};
}
// Helper to define allowed equipment categories for each effect type
export const ALL_CASTER: string[] = ['caster']
-497
View File
@@ -1,497 +0,0 @@
// ─── Equipment Types ─────────────────────────────────────────────────────────
export type EquipmentSlot = 'mainHand' | 'offHand' | 'head' | 'body' | 'hands' | 'feet' | 'accessory1' | 'accessory2';
export type EquipmentCategory = 'caster' | 'shield' | 'catalyst' | 'sword' | 'head' | 'body' | 'hands' | 'feet' | 'accessory';
// All equipment slots in order
export const EQUIPMENT_SLOTS: EquipmentSlot[] = ['mainHand', 'offHand', 'head', 'body', 'hands', 'feet', 'accessory1', 'accessory2'];
// Human-readable names for equipment slots
export const SLOT_NAMES: Record<EquipmentSlot, string> = {
mainHand: 'Main Hand',
offHand: 'Off Hand',
head: 'Head',
body: 'Body',
hands: 'Hands',
feet: 'Feet',
accessory1: 'Accessory 1',
accessory2: 'Accessory 2',
};
export interface EquipmentType {
id: string;
name: string;
category: EquipmentCategory;
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
}
// ─── Equipment Types Definition ─────────────────────────────────────────────
export const EQUIPMENT_TYPES: Record<string, EquipmentType> = {
// ─── Main Hand - Casters ─────────────────────────────────────────────────
basicStaff: {
id: 'basicStaff',
name: 'Basic Staff',
category: 'caster',
slot: 'mainHand',
baseCapacity: 50,
description: 'A simple wooden staff, basic but reliable for channeling mana.',
twoHanded: true,
},
apprenticeWand: {
id: 'apprenticeWand',
name: 'Apprentice Wand',
category: 'caster',
slot: 'mainHand',
baseCapacity: 35,
description: 'A lightweight wand favored by apprentices. Lower capacity but faster to prepare.',
},
oakStaff: {
id: 'oakStaff',
name: 'Oak Staff',
category: 'caster',
slot: 'mainHand',
baseCapacity: 65,
description: 'A sturdy oak staff with decent mana capacity.',
twoHanded: true,
},
crystalWand: {
id: 'crystalWand',
name: 'Crystal Wand',
category: 'caster',
slot: 'mainHand',
baseCapacity: 45,
description: 'A wand tipped with a small crystal. Excellent for elemental enchantments.',
},
arcanistStaff: {
id: 'arcanistStaff',
name: 'Arcanist Staff',
category: 'caster',
slot: 'mainHand',
baseCapacity: 80,
description: 'A staff designed for advanced spellcasters. High capacity for complex enchantments.',
twoHanded: true,
},
battlestaff: {
id: 'battlestaff',
name: 'Battlestaff',
category: 'caster',
slot: 'mainHand',
baseCapacity: 70,
description: 'A reinforced staff suitable for both casting and combat.',
twoHanded: true,
},
// ─── Main Hand - Catalysts ────────────────────────────────────────────────
basicCatalyst: {
id: 'basicCatalyst',
name: 'Basic Catalyst',
category: 'catalyst',
slot: 'mainHand',
baseCapacity: 40,
description: 'A simple catalyst for amplifying magical effects.',
},
fireCatalyst: {
id: 'fireCatalyst',
name: 'Fire Catalyst',
category: 'catalyst',
slot: 'mainHand',
baseCapacity: 55,
description: 'A catalyst attuned to fire magic. Enhances fire enchantments.',
},
voidCatalyst: {
id: 'voidCatalyst',
name: 'Void Catalyst',
category: 'catalyst',
slot: 'mainHand',
baseCapacity: 75,
description: 'A rare catalyst touched by void energy. High capacity but volatile.',
},
// ─── 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
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: {
id: 'steelBlade',
name: 'Steel Blade',
category: 'sword',
slot: 'mainHand',
baseCapacity: 40,
baseDamage: 4,
baseCastSpeed: 4,
description: 'A well-crafted steel sword. Balanced for combat and enchanting.',
},
crystalBlade: {
id: 'crystalBlade',
name: 'Crystal Blade',
category: 'sword',
slot: 'mainHand',
baseCapacity: 55,
baseDamage: 3,
baseCastSpeed: 5,
description: 'A blade made of crystallized mana. Excellent for elemental enchantments.',
},
arcanistBlade: {
id: 'arcanistBlade',
name: 'Arcanist Blade',
category: 'sword',
slot: 'mainHand',
baseCapacity: 65,
baseDamage: 5,
baseCastSpeed: 4,
description: 'A sword forged for battle mages. High capacity for powerful enchantments.',
},
voidBlade: {
id: 'voidBlade',
name: 'Void-Touched Blade',
category: 'sword',
slot: 'mainHand',
baseCapacity: 50,
baseDamage: 6,
baseCastSpeed: 3,
description: 'A blade corrupted by void energy. Powerful but consumes more mana.',
},
// ─── Off Hand - Shields ───────────────────────────────────────────────────
basicShield: {
id: 'basicShield',
name: 'Basic Shield',
category: 'shield',
slot: 'offHand',
baseCapacity: 40,
description: 'A simple wooden shield. Provides basic protection.',
},
reinforcedShield: {
id: 'reinforcedShield',
name: 'Reinforced Shield',
category: 'shield',
slot: 'offHand',
baseCapacity: 55,
description: 'A metal-reinforced shield with enhanced durability and capacity.',
},
runicShield: {
id: 'runicShield',
name: 'Runic Shield',
category: 'shield',
slot: 'offHand',
baseCapacity: 70,
description: 'A shield engraved with protective runes. Excellent for defensive enchantments.',
},
manaShield: {
id: 'manaShield',
name: 'Mana Shield',
category: 'shield',
slot: 'offHand',
baseCapacity: 60,
description: 'A crystalline shield that can store and reflect mana.',
},
// ─── Head ─────────────────────────────────────────────────────────────────
clothHood: {
id: 'clothHood',
name: 'Cloth Hood',
category: 'head',
slot: 'head',
baseCapacity: 25,
description: 'A simple cloth hood. Minimal protection but comfortable.',
},
apprenticeCap: {
id: 'apprenticeCap',
name: 'Apprentice Cap',
category: 'head',
slot: 'head',
baseCapacity: 30,
description: 'The traditional cap of magic apprentices.',
},
wizardHat: {
id: 'wizardHat',
name: 'Wizard Hat',
category: 'head',
slot: 'head',
baseCapacity: 45,
description: 'A classic pointed wizard hat. Decent capacity for headwear.',
},
arcanistCirclet: {
id: 'arcanistCirclet',
name: 'Arcanist Circlet',
category: 'head',
slot: 'head',
baseCapacity: 40,
description: 'A silver circlet worn by accomplished arcanists.',
},
battleHelm: {
id: 'battleHelm',
name: 'Battle Helm',
category: 'head',
slot: 'head',
baseCapacity: 50,
description: 'A sturdy helm for battle mages.',
},
// ─── Body ────────────────────────────────────────────────────────────────
civilianShirt: {
id: 'civilianShirt',
name: 'Civilian Shirt',
category: 'body',
slot: 'body',
baseCapacity: 30,
description: 'A plain shirt with minimal magical properties.',
},
apprenticeRobe: {
id: 'apprenticeRobe',
name: 'Apprentice Robe',
category: 'body',
slot: 'body',
baseCapacity: 45,
description: 'The standard robe for magic apprentices.',
},
scholarRobe: {
id: 'scholarRobe',
name: 'Scholar Robe',
category: 'body',
slot: 'body',
baseCapacity: 55,
description: 'A robe worn by scholars and researchers.',
},
battleRobe: {
id: 'battleRobe',
name: 'Battle Robe',
category: 'body',
slot: 'body',
baseCapacity: 65,
description: 'A reinforced robe designed for combat mages.',
},
arcanistRobe: {
id: 'arcanistRobe',
name: 'Arcanist Robe',
category: 'body',
slot: 'body',
baseCapacity: 80,
description: 'An ornate robe for master arcanists. High capacity for body armor.',
},
// ─── Hands ───────────────────────────────────────────────────────────────
civilianGloves: {
id: 'civilianGloves',
name: 'Civilian Gloves',
category: 'hands',
slot: 'hands',
baseCapacity: 20,
description: 'Simple cloth gloves. Minimal magical capacity.',
},
apprenticeGloves: {
id: 'apprenticeGloves',
name: 'Apprentice Gloves',
category: 'hands',
slot: 'hands',
baseCapacity: 30,
description: 'Basic gloves for handling magical components.',
},
spellweaveGloves: {
id: 'spellweaveGloves',
name: 'Spellweave Gloves',
category: 'hands',
slot: 'hands',
baseCapacity: 40,
description: 'Gloves woven with mana-conductive threads.',
},
combatGauntlets: {
id: 'combatGauntlets',
name: 'Combat Gauntlets',
category: 'hands',
slot: 'hands',
baseCapacity: 35,
description: 'Armored gauntlets for battle mages.',
},
// ─── Feet ────────────────────────────────────────────────────────────────
civilianShoes: {
id: 'civilianShoes',
name: 'Civilian Shoes',
category: 'feet',
slot: 'feet',
baseCapacity: 15,
description: 'Simple leather shoes. No special properties.',
},
apprenticeBoots: {
id: 'apprenticeBoots',
name: 'Apprentice Boots',
category: 'feet',
slot: 'feet',
baseCapacity: 25,
description: 'Basic boots for magic students.',
},
travelerBoots: {
id: 'travelerBoots',
name: 'Traveler Boots',
category: 'feet',
slot: 'feet',
baseCapacity: 30,
description: 'Comfortable boots for long journeys.',
},
battleBoots: {
id: 'battleBoots',
name: 'Battle Boots',
category: 'feet',
slot: 'feet',
baseCapacity: 35,
description: 'Sturdy boots for combat situations.',
},
// ─── Accessories ────────────────────────────────────────────────────────
copperRing: {
id: 'copperRing',
name: 'Copper Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 15,
description: 'A simple copper ring. Basic capacity for accessories.',
},
silverRing: {
id: 'silverRing',
name: 'Silver Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 25,
description: 'A silver ring with decent magical conductivity.',
},
goldRing: {
id: 'goldRing',
name: 'Gold Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 35,
description: 'A gold ring with excellent magical properties.',
},
signetRing: {
id: 'signetRing',
name: 'Signet Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 30,
description: 'A ring bearing a magical sigil.',
},
copperAmulet: {
id: 'copperAmulet',
name: 'Copper Amulet',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 20,
description: 'A simple copper amulet on a leather cord.',
},
silverAmulet: {
id: 'silverAmulet',
name: 'Silver Amulet',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 30,
description: 'A silver amulet with a small gem.',
},
crystalPendant: {
id: 'crystalPendant',
name: 'Crystal Pendant',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 45,
description: 'A pendant with a mana-infused crystal.',
},
manaBrooch: {
id: 'manaBrooch',
name: 'Mana Brooch',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 40,
description: 'A decorative brooch that can hold enchantments.',
},
arcanistPendant: {
id: 'arcanistPendant',
name: 'Arcanist Pendant',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 55,
description: 'A powerful pendant worn by master arcanists.',
},
voidTouchedRing: {
id: 'voidTouchedRing',
name: 'Void-Touched Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 50,
description: 'A ring corrupted by void energy. High capacity but risky.',
},
};
// ─── Helper Functions ─────────────────────────────────────────────────────────
export function getEquipmentType(id: string): EquipmentType | undefined {
return EQUIPMENT_TYPES[id];
}
export function getEquipmentByCategory(category: EquipmentCategory): EquipmentType[] {
return Object.values(EQUIPMENT_TYPES).filter(e => e.category === category);
}
export function getEquipmentBySlot(slot: EquipmentSlot): EquipmentType[] {
return Object.values(EQUIPMENT_TYPES).filter(e => e.slot === slot);
}
export function getAllEquipmentTypes(): EquipmentType[] {
return Object.values(EQUIPMENT_TYPES);
}
// Get valid slots for a category
// Note: For 2-handed weapons, use getValidSlotsForEquipmentType instead
export function getValidSlotsForCategory(category: EquipmentCategory): EquipmentSlot[] {
switch (category) {
case 'caster':
case 'catalyst':
case 'sword':
return ['mainHand'];
case 'shield':
return ['offHand'];
case 'head':
return ['head'];
case 'body':
return ['body'];
case 'hands':
return ['hands'];
case 'feet':
return ['feet'];
case 'accessory':
return ['accessory1', 'accessory2'];
default:
return [];
}
}
// Get valid slots for a specific equipment type (considers 2-handed weapons)
export function getValidSlotsForEquipmentType(equipType: EquipmentType): EquipmentSlot[] {
// 2-handed weapons occupy both main hand and offhand
if (equipType.twoHanded) {
return ['mainHand', 'offHand'];
}
// Otherwise use category-based slots
return getValidSlotsForCategory(equipType.category);
}
// Check if an equipment type can be equipped in a specific slot
export function canEquipInSlot(equipmentType: EquipmentType, slot: EquipmentSlot): boolean {
const validSlots = getValidSlotsForCategory(equipmentType.category);
return validSlots.includes(slot);
}
@@ -0,0 +1,87 @@
// ─── Accessories Equipment Types ──────────────────────────────────
import type { EquipmentType } from './types';
export const ACCESSORIES_EQUIPMENT: Record<string, EquipmentType> = {
// ─── Accessories ────────────────────────────────────────────────
copperRing: {
id: 'copperRing',
name: 'Copper Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 15,
description: 'A simple copper ring. Basic capacity for accessories.',
},
silverRing: {
id: 'silverRing',
name: 'Silver Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 25,
description: 'A silver ring with decent magical conductivity.',
},
goldRing: {
id: 'goldRing',
name: 'Gold Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 35,
description: 'A gold ring with excellent magical properties.',
},
signetRing: {
id: 'signetRing',
name: 'Signet Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 30,
description: 'A ring bearing a magical sigil.',
},
copperAmulet: {
id: 'copperAmulet',
name: 'Copper Amulet',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 20,
description: 'A simple copper amulet on a leather cord.',
},
silverAmulet: {
id: 'silverAmulet',
name: 'Silver Amulet',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 30,
description: 'A silver amulet with a small gem.',
},
crystalPendant: {
id: 'crystalPendant',
name: 'Crystal Pendant',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 45,
description: 'A pendant with a mana-infused crystal.',
},
manaBrooch: {
id: 'manaBrooch',
name: 'Mana Brooch',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 40,
description: 'A decorative brooch that can hold enchantments.',
},
arcanistPendant: {
id: 'arcanistPendant',
name: 'Arcanist Pendant',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 55,
description: 'A powerful pendant worn by master arcanists.',
},
voidTouchedRing: {
id: 'voidTouchedRing',
name: 'Void-Touched Ring',
category: 'accessory',
slot: 'accessory1',
baseCapacity: 50,
description: 'A ring corrupted by void energy. High capacity but risky.',
},
};
+47
View File
@@ -0,0 +1,47 @@
// ─── Body Equipment Types ─────────────────────────────────────────
import type { EquipmentType } from './types';
export const BODY_EQUIPMENT: Record<string, EquipmentType> = {
// ─── Body ────────────────────────────────────────────────────────
civilianShirt: {
id: 'civilianShirt',
name: 'Civilian Shirt',
category: 'body',
slot: 'body',
baseCapacity: 30,
description: 'A plain shirt with minimal magical properties.',
},
apprenticeRobe: {
id: 'apprenticeRobe',
name: 'Apprentice Robe',
category: 'body',
slot: 'body',
baseCapacity: 45,
description: 'The standard robe for magic apprentices.',
},
scholarRobe: {
id: 'scholarRobe',
name: 'Scholar Robe',
category: 'body',
slot: 'body',
baseCapacity: 55,
description: 'A robe worn by scholars and researchers.',
},
battleRobe: {
id: 'battleRobe',
name: 'Battle Robe',
category: 'body',
slot: 'body',
baseCapacity: 65,
description: 'A reinforced robe designed for combat mages.',
},
arcanistRobe: {
id: 'arcanistRobe',
name: 'Arcanist Robe',
category: 'body',
slot: 'body',
baseCapacity: 80,
description: 'An ornate robe for master arcanists. High capacity for body armor.',
},
};
+59
View File
@@ -0,0 +1,59 @@
// ─── Caster Equipment Types ────────────────────────────────────────────
import type { EquipmentType } from './types';
export const CASTER_EQUIPMENT: Record<string, EquipmentType> = {
// ─── Main Hand - Casters ─────────────────────────────────────────────────
basicStaff: {
id: 'basicStaff',
name: 'Basic Staff',
category: 'caster',
slot: 'mainHand',
baseCapacity: 50,
description: 'A simple wooden staff, basic but reliable for channeling mana.',
twoHanded: true,
},
apprenticeWand: {
id: 'apprenticeWand',
name: 'Apprentice Wand',
category: 'caster',
slot: 'mainHand',
baseCapacity: 35,
description: 'A lightweight wand favored by apprentices. Lower capacity but faster to prepare.',
},
oakStaff: {
id: 'oakStaff',
name: 'Oak Staff',
category: 'caster',
slot: 'mainHand',
baseCapacity: 65,
description: 'A sturdy oak staff with decent mana capacity.',
twoHanded: true,
},
crystalWand: {
id: 'crystalWand',
name: 'Crystal Wand',
category: 'caster',
slot: 'mainHand',
baseCapacity: 45,
description: 'A wand tipped with a small crystal. Excellent for elemental enchantments.',
},
arcanistStaff: {
id: 'arcanistStaff',
name: 'Arcanist Staff',
category: 'caster',
slot: 'mainHand',
baseCapacity: 80,
description: 'A staff designed for advanced spellcasters. High capacity for complex enchantments.',
twoHanded: true,
},
battlestaff: {
id: 'battlestaff',
name: 'Battlestaff',
category: 'caster',
slot: 'mainHand',
baseCapacity: 70,
description: 'A reinforced staff suitable for both casting and combat.',
twoHanded: true,
},
};
+31
View File
@@ -0,0 +1,31 @@
// ─── Catalyst Equipment Types ───────────────────────────────────────────
import type { EquipmentType } from './types';
export const CATALYST_EQUIPMENT: Record<string, EquipmentType> = {
// ─── Main Hand - Catalysts ────────────────────────────────────────────────
basicCatalyst: {
id: 'basicCatalyst',
name: 'Basic Catalyst',
category: 'catalyst',
slot: 'mainHand',
baseCapacity: 40,
description: 'A simple catalyst for amplifying magical effects.',
},
fireCatalyst: {
id: 'fireCatalyst',
name: 'Fire Catalyst',
category: 'catalyst',
slot: 'mainHand',
baseCapacity: 55,
description: 'A catalyst attuned to fire magic. Enhances fire enchantments.',
},
voidCatalyst: {
id: 'voidCatalyst',
name: 'Void Catalyst',
category: 'catalyst',
slot: 'mainHand',
baseCapacity: 75,
description: 'A rare catalyst touched by void energy. High capacity but volatile.',
},
};
+39
View File
@@ -0,0 +1,39 @@
// ─── Feet Equipment Types ─────────────────────────────────────────
import type { EquipmentType } from './types';
export const FEET_EQUIPMENT: Record<string, EquipmentType> = {
// ─── Feet ────────────────────────────────────────────────────────
civilianShoes: {
id: 'civilianShoes',
name: 'Civilian Shoes',
category: 'feet',
slot: 'feet',
baseCapacity: 15,
description: 'Simple leather shoes. No special properties.',
},
apprenticeBoots: {
id: 'apprenticeBoots',
name: 'Apprentice Boots',
category: 'feet',
slot: 'feet',
baseCapacity: 25,
description: 'Basic boots for magic students.',
},
travelerBoots: {
id: 'travelerBoots',
name: 'Traveler Boots',
category: 'feet',
slot: 'feet',
baseCapacity: 30,
description: 'Comfortable boots for long journeys.',
},
battleBoots: {
id: 'battleBoots',
name: 'Battle Boots',
category: 'feet',
slot: 'feet',
baseCapacity: 35,
description: 'Sturdy boots for combat situations.',
},
};
+39
View File
@@ -0,0 +1,39 @@
// ─── Hands Equipment Types ─────────────────────────────────────────
import type { EquipmentType } from './types';
export const HANDS_EQUIPMENT: Record<string, EquipmentType> = {
// ─── Hands ───────────────────────────────────────────────────────
civilianGloves: {
id: 'civilianGloves',
name: 'Civilian Gloves',
category: 'hands',
slot: 'hands',
baseCapacity: 20,
description: 'Simple cloth gloves. Minimal magical capacity.',
},
apprenticeGloves: {
id: 'apprenticeGloves',
name: 'Apprentice Gloves',
category: 'hands',
slot: 'hands',
baseCapacity: 30,
description: 'Basic gloves for handling magical components.',
},
spellweaveGloves: {
id: 'spellweaveGloves',
name: 'Spellweave Gloves',
category: 'hands',
slot: 'hands',
baseCapacity: 40,
description: 'Gloves woven with mana-conductive threads.',
},
combatGauntlets: {
id: 'combatGauntlets',
name: 'Combat Gauntlets',
category: 'hands',
slot: 'hands',
baseCapacity: 35,
description: 'Armored gauntlets for battle mages.',
},
};
+47
View File
@@ -0,0 +1,47 @@
// ─── Head Equipment Types ────────────────────────────────────────────
import type { EquipmentType } from './types';
export const HEAD_EQUIPMENT: Record<string, EquipmentType> = {
// ─── Head ─────────────────────────────────────────────────────────
clothHood: {
id: 'clothHood',
name: 'Cloth Hood',
category: 'head',
slot: 'head',
baseCapacity: 25,
description: 'A simple cloth hood. Minimal protection but comfortable.',
},
apprenticeCap: {
id: 'apprenticeCap',
name: 'Apprentice Cap',
category: 'head',
slot: 'head',
baseCapacity: 30,
description: 'The traditional cap of magic apprentices.',
},
wizardHat: {
id: 'wizardHat',
name: 'Wizard Hat',
category: 'head',
slot: 'head',
baseCapacity: 45,
description: 'A classic pointed wizard hat. Decent capacity for headwear.',
},
arcanistCirclet: {
id: 'arcanistCirclet',
name: 'Arcanist Circlet',
category: 'head',
slot: 'head',
baseCapacity: 40,
description: 'A silver circlet worn by accomplished arcanists.',
},
battleHelm: {
id: 'battleHelm',
name: 'Battle Helm',
category: 'head',
slot: 'head',
baseCapacity: 50,
description: 'A sturdy helm for battle mages.',
},
};
+28
View File
@@ -0,0 +1,28 @@
// ─── Equipment Types Index ───────────────────────────────
// Re-exports from all equipment type modules
// Re-export types
export type {
EquipmentSlot,
EquipmentCategory,
EquipmentType
} from './types';
export {
EQUIPMENT_SLOTS,
SLOT_NAMES
} from './types';
// Re-export data
export { EQUIPMENT_TYPES } from './data';
// Re-export utility functions
export {
getEquipmentType,
getEquipmentByCategory,
getEquipmentBySlot,
getAllEquipmentTypes,
getValidSlotsForCategory,
getValidSlotsForEquipmentType,
canEquipInSlot,
} from './utils';
+39
View File
@@ -0,0 +1,39 @@
// ─── Shield Equipment Types ───────────────────────────────────────────
import type { EquipmentType } from './types';
export const SHIELD_EQUIPMENT: Record<string, EquipmentType> = {
// ─── Off Hand - Shields ───────────────────────────────────────────
basicShield: {
id: 'basicShield',
name: 'Basic Shield',
category: 'shield',
slot: 'offHand',
baseCapacity: 40,
description: 'A simple wooden shield. Provides basic protection.',
},
reinforcedShield: {
id: 'reinforcedShield',
name: 'Reinforced Shield',
category: 'shield',
slot: 'offHand',
baseCapacity: 55,
description: 'A metal-reinforced shield with enhanced durability and capacity.',
},
runicShield: {
id: 'runicShield',
name: 'Runic Shield',
category: 'shield',
slot: 'offHand',
baseCapacity: 70,
description: 'A shield engraved with protective runes. Excellent for defensive enchantments.',
},
manaShield: {
id: 'manaShield',
name: 'Mana Shield',
category: 'shield',
slot: 'offHand',
baseCapacity: 60,
description: 'A crystalline shield that can store and reflect mana.',
},
};
+59
View File
@@ -0,0 +1,59 @@
// ─── Sword Equipment Types ───────────────────────────────────────────
import type { EquipmentType } from './types';
export const SWORD_EQUIPMENT: Record<string, EquipmentType> = {
// ─── 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
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: {
id: 'steelBlade',
name: 'Steel Blade',
category: 'sword',
slot: 'mainHand',
baseCapacity: 40,
baseDamage: 4,
baseCastSpeed: 4,
description: 'A well-crafted steel sword. Balanced for combat and enchanting.',
},
crystalBlade: {
id: 'crystalBlade',
name: 'Crystal Blade',
category: 'sword',
slot: 'mainHand',
baseCapacity: 55,
baseDamage: 3,
baseCastSpeed: 5,
description: 'A blade made of crystallized mana. Excellent for elemental enchantments.',
},
arcanistBlade: {
id: 'arcanistBlade',
name: 'Arcanist Blade',
category: 'sword',
slot: 'mainHand',
baseCapacity: 65,
baseDamage: 5,
baseCastSpeed: 4,
description: 'A sword forged for battle mages. High capacity for powerful enchantments.',
},
voidBlade: {
id: 'voidBlade',
name: 'Void-Touched Blade',
category: 'sword',
slot: 'mainHand',
baseCapacity: 50,
baseDamage: 6,
baseCastSpeed: 3,
description: 'A blade corrupted by void energy. Powerful but consumes more mana.',
},
};
+31
View File
@@ -0,0 +1,31 @@
// ─── Equipment Types ─────────────────────────────────────────────────
export type EquipmentSlot = 'mainHand' | 'offHand' | 'head' | 'body' | 'hands' | 'feet' | 'accessory1' | 'accessory2';
export type EquipmentCategory = 'caster' | 'shield' | 'catalyst' | 'sword' | 'head' | 'body' | 'hands' | 'feet' | 'accessory';
// All equipment slots in order
export const EQUIPMENT_SLOTS: EquipmentSlot[] = ['mainHand', 'offHand', 'head', 'body', 'hands', 'feet', 'accessory1', 'accessory2'];
// Human-readable names for equipment slots
export const SLOT_NAMES: Record<EquipmentSlot, string> = {
mainHand: 'Main Hand',
offHand: 'Off Hand',
head: 'Head',
body: 'Body',
hands: 'Hands',
feet: 'Feet',
accessory1: 'Accessory 1',
accessory2: 'Accessory 2',
};
export interface EquipmentType {
id: string;
name: string;
category: EquipmentCategory;
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
}
+62
View File
@@ -0,0 +1,62 @@
// ─── Equipment Helper Functions ─────────────────────────
import type { EquipmentType, EquipmentSlot, EquipmentCategory } from './types';
import { EQUIPMENT_TYPES } from './index';
export function getEquipmentType(id: string): EquipmentType | undefined {
return EQUIPMENT_TYPES[id];
}
export function getEquipmentByCategory(category: EquipmentCategory): EquipmentType[] {
return Object.values(EQUIPMENT_TYPES).filter(e => e.category === category) as EquipmentType[];
}
export function getEquipmentBySlot(slot: EquipmentSlot): EquipmentType[] {
return Object.values(EQUIPMENT_TYPES).filter(e => e.slot === slot) as EquipmentType[];
}
export function getAllEquipmentTypes(): EquipmentType[] {
return Object.values(EQUIPMENT_TYPES) as EquipmentType[];
}
// Get valid slots for a category
// Note: For 2-handed weapons, use getValidSlotsForEquipmentType instead
export function getValidSlotsForCategory(category: EquipmentCategory): EquipmentSlot[] {
switch (category) {
case 'caster':
case 'catalyst':
case 'sword':
return ['mainHand'];
case 'shield':
return ['offHand'];
case 'head':
return ['head'];
case 'body':
return ['body'];
case 'hands':
return ['hands'];
case 'feet':
return ['feet'];
case 'accessory':
return ['accessory1', 'accessory2'];
default:
return [];
}
}
// Get valid slots for a specific equipment type (considers 2-handed weapons)
export function getValidSlotsForEquipmentType(equipType: EquipmentType): EquipmentSlot[] {
// 2-handed weapons occupy both main hand and offhand
if (equipType.twoHanded) {
return ['mainHand', 'offHand'];
}
// Otherwise use category-based slots
return getValidSlotsForCategory(equipType.category);
}
// Check if an equipment type can be equipped in a specific slot
export function canEquipInSlot(equipmentType: EquipmentType, slot: EquipmentSlot): boolean {
const validSlots = getValidSlotsForEquipmentType(equipmentType);
return validSlots.includes(slot);
}
-471
View File
@@ -1,471 +0,0 @@
// ─── Golem Definitions ─────────────────────────────────────────────────────────
// Golems are magical constructs that fight alongside the player
// They cost mana to summon and maintain
import type { SpellCost } from '../types';
// Golem mana cost helper
function elemCost(element: string, amount: number): SpellCost {
return { type: 'element', element, amount };
}
function rawCost(amount: number): SpellCost {
return { type: 'raw', amount };
}
export interface GolemManaCost {
type: 'raw' | 'element';
element?: string;
amount: number;
}
export interface GolemDef {
id: string;
name: string;
description: string;
baseManaType: string; // The primary mana type this golem uses
summonCost: GolemManaCost[]; // Cost to summon (can be multiple types)
maintenanceCost: GolemManaCost[]; // Cost per hour to maintain
damage: number; // Base damage per attack
attackSpeed: number; // Attacks per hour
hp: number; // Golem HP (for display, they don't take damage)
armorPierce: number; // Armor piercing (0-1)
isAoe: boolean; // Whether golem attacks are AOE
aoeTargets: number; // Number of targets for AOE
unlockCondition: {
type: 'attunement_level' | 'mana_unlocked' | 'dual_attunement';
attunement?: string;
level?: number;
manaType?: string;
attunements?: string[];
levels?: number[];
};
tier: number; // Power tier (1-4)
}
// All golem definitions
export const GOLEMS_DEF: Record<string, GolemDef> = {
// ─── BASE GOLEMS ─────────────────────────────────────────────────────────────
// Earth Golem - Basic, available with Fabricator attunement
earthGolem: {
id: 'earthGolem',
name: 'Earth Golem',
description: 'A sturdy construct of stone and soil. Slow but powerful.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 10)],
maintenanceCost: [elemCost('earth', 0.5)],
damage: 8,
attackSpeed: 1.5,
hp: 50,
armorPierce: 0.15,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'attunement_level',
attunement: 'fabricator',
level: 2,
},
tier: 1,
},
// ─── ELEMENTAL VARIANT GOLEMS ────────────────────────────────────────────────
// Steel Golem - Metal mana variant
steelGolem: {
id: 'steelGolem',
name: 'Steel Golem',
description: 'Forged from metal, this golem has high armor piercing.',
baseManaType: 'metal',
summonCost: [elemCost('metal', 8), elemCost('earth', 5)],
maintenanceCost: [elemCost('metal', 0.6), elemCost('earth', 0.2)],
damage: 12,
attackSpeed: 1.2,
hp: 60,
armorPierce: 0.35,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'mana_unlocked',
manaType: 'metal',
},
tier: 2,
},
// Crystal Golem - Crystal mana variant
crystalGolem: {
id: 'crystalGolem',
name: 'Crystal Golem',
description: 'A prismatic construct that deals high damage with precision.',
baseManaType: 'crystal',
summonCost: [elemCost('crystal', 6), elemCost('earth', 3)],
maintenanceCost: [elemCost('crystal', 0.4), elemCost('earth', 0.2)],
damage: 18,
attackSpeed: 1.0,
hp: 40,
armorPierce: 0.25,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'mana_unlocked',
manaType: 'crystal',
},
tier: 3,
},
// Sand Golem - Sand mana variant
sandGolem: {
id: 'sandGolem',
name: 'Sand Golem',
description: 'A shifting construct of sand particles. Hits multiple enemies.',
baseManaType: 'sand',
summonCost: [elemCost('sand', 8), elemCost('earth', 3)],
maintenanceCost: [elemCost('sand', 0.5), elemCost('earth', 0.2)],
damage: 6,
attackSpeed: 2.0,
hp: 35,
armorPierce: 0.1,
isAoe: true,
aoeTargets: 2,
unlockCondition: {
type: 'mana_unlocked',
manaType: 'sand',
},
tier: 2,
},
// ─── ADVANCED HYBRID GOLEMS ──────────────────────────────────────────────────
// Require Enchanter 5 + Fabricator 5
// Lava Golem - Fire + Earth fusion
lavaGolem: {
id: 'lavaGolem',
name: 'Lava Golem',
description: 'Molten earth and fire combined. Burns enemies over time.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 10), elemCost('fire', 8)],
maintenanceCost: [elemCost('earth', 0.4), elemCost('fire', 0.5)],
damage: 15,
attackSpeed: 1.0,
hp: 70,
armorPierce: 0.2,
isAoe: true,
aoeTargets: 2,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 3,
},
// Galvanic Golem - Metal + Lightning fusion
galvanicGolem: {
id: 'galvanicGolem',
name: 'Galvanic Golem',
description: 'A conductive metal construct charged with lightning. Extremely fast attacks.',
baseManaType: 'metal',
summonCost: [elemCost('metal', 8), elemCost('lightning', 6)],
maintenanceCost: [elemCost('metal', 0.3), elemCost('lightning', 0.6)],
damage: 10,
attackSpeed: 3.5,
hp: 45,
armorPierce: 0.45,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 3,
},
// Obsidian Golem - Dark + Earth fusion
obsidianGolem: {
id: 'obsidianGolem',
name: 'Obsidian Golem',
description: 'Volcanic glass animated by shadow. Devastating single-target damage.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 12), elemCost('dark', 6)],
maintenanceCost: [elemCost('earth', 0.3), elemCost('dark', 0.4)],
damage: 25,
attackSpeed: 0.8,
hp: 55,
armorPierce: 0.5,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 4,
},
// Prism Golem - Light + Crystal fusion
prismGolem: {
id: 'prismGolem',
name: 'Prism Golem',
description: 'A radiant crystal construct. Channels light into piercing beams.',
baseManaType: 'crystal',
summonCost: [elemCost('crystal', 10), elemCost('light', 6)],
maintenanceCost: [elemCost('crystal', 0.4), elemCost('light', 0.4)],
damage: 20,
attackSpeed: 1.5,
hp: 50,
armorPierce: 0.35,
isAoe: true,
aoeTargets: 3,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 4,
},
// Quicksilver Golem - Water + Metal fusion
quicksilverGolem: {
id: 'quicksilverGolem',
name: 'Quicksilver Golem',
description: 'Liquid metal that flows around defenses. Fast and hard to dodge.',
baseManaType: 'metal',
summonCost: [elemCost('metal', 6), elemCost('water', 6)],
maintenanceCost: [elemCost('metal', 0.3), elemCost('water', 0.3)],
damage: 8,
attackSpeed: 4.0,
hp: 40,
armorPierce: 0.3,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 3,
},
// Voidstone Golem - Void + Earth fusion (ultimate)
voidstoneGolem: {
id: 'voidstoneGolem',
name: 'Voidstone Golem',
description: 'Earth infused with void energy. The ultimate golem construct.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 15), elemCost('void', 8)],
maintenanceCost: [elemCost('earth', 0.3), elemCost('void', 0.6)],
damage: 40,
attackSpeed: 0.6,
hp: 100,
armorPierce: 0.6,
isAoe: true,
aoeTargets: 3,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 4,
},
};
// Get golem slots based on Fabricator attunement level
// Level 2 = 1, Level 4 = 2, Level 6 = 3, Level 8 = 4, Level 10 = 5
export function getGolemSlots(fabricatorLevel: number): number {
if (fabricatorLevel < 2) return 0;
return Math.floor(fabricatorLevel / 2);
}
// Check if a golem is unlocked based on player state
export function isGolemUnlocked(
golemId: string,
attunements: Record<string, { active: boolean; level: number }>,
unlockedElements: string[]
): boolean {
const golem = GOLEMS_DEF[golemId];
if (!golem) return false;
const condition = golem.unlockCondition;
switch (condition.type) {
case 'attunement_level':
const attState = attunements[condition.attunement || ''];
return attState?.active && (attState.level || 1) >= (condition.level || 1);
case 'mana_unlocked':
return unlockedElements.includes(condition.manaType || '');
case 'dual_attunement':
if (!condition.attunements || !condition.levels) return false;
return condition.attunements.every((attId, idx) => {
const att = attunements[attId];
return att?.active && (att.level || 1) >= condition.levels![idx];
});
default:
return false;
}
}
// Get all unlocked golems for a player
export function getUnlockedGolems(
attunements: Record<string, { active: boolean; level: number }>,
unlockedElements: string[]
): GolemDef[] {
return Object.values(GOLEMS_DEF).filter(golem =>
isGolemUnlocked(golem.id, attunements, unlockedElements)
);
}
// Calculate golem damage with skill bonuses
export function getGolemDamage(
golemId: string,
skills: Record<string, number>
): number {
const golem = GOLEMS_DEF[golemId];
if (!golem) return 0;
let damage = golem.damage;
// Golem Mastery skill bonus
const masteryBonus = 1 + (skills.golemMastery || 0) * 0.1;
damage *= masteryBonus;
return damage;
}
// Calculate golem attack speed with skill bonuses
export function getGolemAttackSpeed(
golemId: string,
skills: Record<string, number>
): number {
const golem = GOLEMS_DEF[golemId];
if (!golem) return 0;
let speed = golem.attackSpeed;
// Golem Efficiency skill bonus
const efficiencyBonus = 1 + (skills.golemEfficiency || 0) * 0.05;
speed *= efficiencyBonus;
return speed;
}
// Get floors golems can last (base 1, +1 per Golem Longevity skill level)
export function getGolemFloorDuration(skills: Record<string, number>): number {
return 1 + (skills.golemLongevity || 0);
}
// Get maintenance cost multiplier (Golem Siphon reduces by 10% per level)
export function getGolemMaintenanceMultiplier(skills: Record<string, number>): number {
return 1 - (skills.golemSiphon || 0) * 0.1;
}
// Check if player can afford golem summon cost
export function canAffordGolemSummon(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>
): boolean {
const golem = GOLEMS_DEF[golemId];
if (!golem) return false;
for (const cost of golem.summonCost) {
if (cost.type === 'raw') {
if (rawMana < cost.amount) return false;
} else if (cost.element) {
const elem = elements[cost.element];
if (!elem || !elem.unlocked || elem.current < cost.amount) return false;
}
}
return true;
}
// Deduct golem summon cost from mana pools
export function deductGolemSummonCost(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>
): { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> } {
const golem = GOLEMS_DEF[golemId];
if (!golem) return { rawMana, elements };
let newRawMana = rawMana;
let newElements = { ...elements };
for (const cost of golem.summonCost) {
if (cost.type === 'raw') {
newRawMana -= cost.amount;
} else if (cost.element && newElements[cost.element]) {
newElements = {
...newElements,
[cost.element]: {
...newElements[cost.element],
current: newElements[cost.element].current - cost.amount,
},
};
}
}
return { rawMana: newRawMana, elements: newElements };
}
// Check if player can afford golem maintenance for one tick
export function canAffordGolemMaintenance(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
skills: Record<string, number>
): boolean {
const golem = GOLEMS_DEF[golemId];
if (!golem) return false;
const maintenanceMult = getGolemMaintenanceMultiplier(skills);
for (const cost of golem.maintenanceCost) {
const adjustedAmount = cost.amount * maintenanceMult;
if (cost.type === 'raw') {
if (rawMana < adjustedAmount) return false;
} else if (cost.element) {
const elem = elements[cost.element];
if (!elem || !elem.unlocked || elem.current < adjustedAmount) return false;
}
}
return true;
}
// Deduct golem maintenance cost for one tick
export function deductGolemMaintenance(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
skills: Record<string, number>
): { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> } {
const golem = GOLEMS_DEF[golemId];
if (!golem) return { rawMana, elements };
const maintenanceMult = getGolemMaintenanceMultiplier(skills);
let newRawMana = rawMana;
let newElements = { ...elements };
for (const cost of golem.maintenanceCost) {
const adjustedAmount = cost.amount * maintenanceMult;
if (cost.type === 'raw') {
newRawMana -= adjustedAmount;
} else if (cost.element && newElements[cost.element]) {
newElements = {
...newElements,
[cost.element]: {
...newElements[cost.element],
current: newElements[cost.element].current - adjustedAmount,
},
};
}
}
return { rawMana: newRawMana, elements: newElements };
}
+30
View File
@@ -0,0 +1,30 @@
// ─── Base Golem Definitions ───────────────────────────────────
import type { GolemDef } from './types';
import { elemCost } from './types';
export const BASE_GOLEMS: Record<string, GolemDef> = {
// ─── BASE GOLEMS ─────────────────────────────────────────────────────
// Earth Golem - Basic, available with Fabricator attunement
earthGolem: {
id: 'earthGolem',
name: 'Earth Golem',
description: 'A sturdy construct of stone and soil. Slow but powerful.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 10)],
maintenanceCost: [elemCost('earth', 0.5)],
damage: 8,
attackSpeed: 1.5,
hp: 50,
armorPierce: 0.15,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'attunement_level',
attunement: 'fabricator',
level: 2,
},
tier: 1,
},
};
@@ -0,0 +1,71 @@
// ─── Elemental Variant Golems ───────────────────────────────────
import type { GolemDef } from './types';
import { elemCost } from './types';
export const ELEMENTAL_GOLEMS: Record<string, GolemDef> = {
// ─── ELEMENTAL VARIANT GOLEMS ────────────────────────────────────────
// Steel Golem - Metal mana variant
steelGolem: {
id: 'steelGolem',
name: 'Steel Golem',
description: 'Forged from metal, this golem has high armor piercing.',
baseManaType: 'metal',
summonCost: [elemCost('metal', 8), elemCost('earth', 5)],
maintenanceCost: [elemCost('metal', 0.6), elemCost('earth', 0.2)],
damage: 12,
attackSpeed: 1.2,
hp: 60,
armorPierce: 0.35,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'mana_unlocked',
manaType: 'metal',
},
tier: 2,
},
// Crystal Golem - Crystal mana variant
crystalGolem: {
id: 'crystalGolem',
name: 'Crystal Golem',
description: 'A prismatic construct that deals high damage with precision.',
baseManaType: 'crystal',
summonCost: [elemCost('crystal', 6), elemCost('earth', 3)],
maintenanceCost: [elemCost('crystal', 0.4), elemCost('earth', 0.2)],
damage: 18,
attackSpeed: 1.0,
hp: 40,
armorPierce: 0.25,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'mana_unlocked',
manaType: 'crystal',
},
tier: 3,
},
// Sand Golem - Sand mana variant
sandGolem: {
id: 'sandGolem',
name: 'Sand Golem',
description: 'A shifting construct of sand particles. Hits multiple enemies.',
baseManaType: 'sand',
summonCost: [elemCost('sand', 8), elemCost('earth', 3)],
maintenanceCost: [elemCost('sand', 0.5), elemCost('earth', 0.2)],
damage: 6,
attackSpeed: 2.0,
hp: 35,
armorPierce: 0.1,
isAoe: true,
aoeTargets: 2,
unlockCondition: {
type: 'mana_unlocked',
manaType: 'sand',
},
tier: 2,
},
};
+139
View File
@@ -0,0 +1,139 @@
// ─── Advanced Hybrid Golems ────────────────────────────────────
// Require Enchanter 5 + Fabricator 5
import type { GolemDef } from './types';
import { elemCost } from './types';
export const HYBRID_GOLEMS: Record<string, GolemDef> = {
// Lava Golem - Fire + Earth fusion
lavaGolem: {
id: 'lavaGolem',
name: 'Lava Golem',
description: 'Molten earth and fire combined. Burns enemies over time.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 10), elemCost('fire', 8)],
maintenanceCost: [elemCost('earth', 0.4), elemCost('fire', 0.5)],
damage: 15,
attackSpeed: 1.0,
hp: 70,
armorPierce: 0.2,
isAoe: true,
aoeTargets: 2,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 3,
},
// Galvanic Golem - Metal + Lightning fusion
galvanicGolem: {
id: 'galvanicGolem',
name: 'Galvanic Golem',
description: 'A conductive metal construct charged with lightning. Extremely fast attacks.',
baseManaType: 'metal',
summonCost: [elemCost('metal', 8), elemCost('lightning', 6)],
maintenanceCost: [elemCost('metal', 0.3), elemCost('lightning', 0.6)],
damage: 10,
attackSpeed: 3.5,
hp: 45,
armorPierce: 0.45,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 3,
},
// Obsidian Golem - Dark + Earth fusion
obsidianGolem: {
id: 'obsidianGolem',
name: 'Obsidian Golem',
description: 'Volcanic glass animated by shadow. Devastating single-target damage.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 12), elemCost('dark', 6)],
maintenanceCost: [elemCost('earth', 0.3), elemCost('dark', 0.4)],
damage: 25,
attackSpeed: 0.8,
hp: 55,
armorPierce: 0.5,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 4,
},
// Prism Golem - Light + Crystal fusion
prismGolem: {
id: 'prismGolem',
name: 'Prism Golem',
description: 'A radiant crystal construct. Channels light into piercing beams.',
baseManaType: 'crystal',
summonCost: [elemCost('crystal', 10), elemCost('light', 6)],
maintenanceCost: [elemCost('crystal', 0.4), elemCost('light', 0.4)],
damage: 20,
attackSpeed: 1.5,
hp: 50,
armorPierce: 0.35,
isAoe: true,
aoeTargets: 3,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 4,
},
// Quicksilver Golem - Water + Metal fusion
quicksilverGolem: {
id: 'quicksilverGolem',
name: 'Quicksilver Golem',
description: 'Liquid metal that flows around defenses. Fast and hard to dodge.',
baseManaType: 'metal',
summonCost: [elemCost('metal', 6), elemCost('water', 6)],
maintenanceCost: [elemCost('metal', 0.3), elemCost('water', 0.3)],
damage: 8,
attackSpeed: 4.0,
hp: 40,
armorPierce: 0.3,
isAoe: false,
aoeTargets: 1,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 3,
},
// Voidstone Golem - Void + Earth fusion (ultimate)
voidstoneGolem: {
id: 'voidstoneGolem',
name: 'Voidstone Golem',
description: 'Earth infused with void energy. The ultimate golem construct.',
baseManaType: 'earth',
summonCost: [elemCost('earth', 15), elemCost('void', 8)],
maintenanceCost: [elemCost('earth', 0.3), elemCost('void', 0.6)],
damage: 40,
attackSpeed: 0.6,
hp: 100,
armorPierce: 0.6,
isAoe: true,
aoeTargets: 3,
unlockCondition: {
type: 'dual_attunement',
attunements: ['enchanter', 'fabricator'],
levels: [5, 5],
},
tier: 4,
},
};
+23
View File
@@ -0,0 +1,23 @@
// ─── Golem Definitions Index ─────────────────────────────────
// Re-exports from all golem modules
// Re-export types
export type { GolemDef, GolemManaCost } from './types';
// Re-export data
export { GOLEMS_DEF } from './data';
// Re-export utility functions
export {
getGolemSlots,
isGolemUnlocked,
getUnlockedGolems,
getGolemDamage,
getGolemAttackSpeed,
getGolemFloorDuration,
getGolemMaintenanceMultiplier,
canAffordGolemSummon,
deductGolemSummonCost,
canAffordGolemMaintenance,
deductGolemMaintenance,
} from './utils';
+42
View File
@@ -0,0 +1,42 @@
// ─── Golem Types ─────────────────────────────────────────────────
import type { SpellCost } from '../types';
// Golem mana cost helper
export function elemCost(element: string, amount: number): SpellCost {
return { type: 'element', element, amount };
}
export function rawCost(amount: number): SpellCost {
return { type: 'raw', amount };
}
export interface GolemManaCost {
type: 'raw' | 'element';
element?: string;
amount: number;
}
export interface GolemDef {
id: string;
name: string;
description: string;
baseManaType: string; // The primary mana type this golem uses
summonCost: GolemManaCost[]; // Cost to summon (can be multiple types)
maintenanceCost: GolemManaCost[]; // Cost per hour to maintain
damage: number; // Base damage per attack
attackSpeed: number; // Attacks per hour
hp: number; // Golem HP (for display, they don't take damage)
armorPierce: number; // Armor piercing (0-1)
isAoe: boolean; // Whether golem attacks are AOE
aoeTargets: number; // Number of targets for AOE
unlockCondition: {
type: 'attunement_level' | 'mana_unlocked' | 'dual_attunement';
attunement?: string;
level?: number;
manaType?: string;
attunements?: string[];
levels?: number[];
};
tier: number; // Power tier (1-4)
}
+204
View File
@@ -0,0 +1,204 @@
// ─── Golem Helper Functions ─────────────────────────
import type { GolemDef, GolemManaCost } from './types';
import { GOLEMS_DEF } from './index';
// Get golem slots based on Fabricator attunement level
// Level 2 = 1, Level 4 = 2, Level 6 = 3, Level 8 = 4, Level 10 = 5
export function getGolemSlots(fabricatorLevel: number): number {
if (fabricatorLevel < 2) return 0;
return Math.floor(fabricatorLevel / 2);
}
// Check if a golem is unlocked based on player state
export function isGolemUnlocked(
golemId: string,
attunements: Record<string, { active: boolean; level: number }>,
unlockedElements: string[]
): boolean {
const golem = GOLEMS_DEF[golemId];
if (!golem) return false;
const condition = golem.unlockCondition;
switch (condition.type) {
case 'attunement_level':
const attState = attunements[condition.attunement || ''];
return attState?.active && (attState.level || 1) >= (condition.level || 1);
case 'mana_unlocked':
return unlockedElements.includes(condition.manaType || '');
case 'dual_attunement':
if (!condition.attunements || !condition.levels) return false;
return condition.attunements.every((attId, idx) => {
const att = attunements[attId];
return att?.active && (att.level || 1) >= condition.levels![idx];
});
default:
return false;
}
}
// Get all unlocked golems for a player
export function getUnlockedGolems(
attunements: Record<string, { active: boolean; level: number }>,
unlockedElements: string[]
): GolemDef[] {
return Object.values(GOLEMS_DEF).filter(golem =>
isGolemUnlocked(golem.id, attunements, unlockedElements)
) as GolemDef[];
}
// Calculate golem damage with skill bonuses
export function getGolemDamage(
golemId: string,
skills: Record<string, number>
): number {
const golem = GOLEMS_DEF[golemId];
if (!golem) return 0;
let damage = golem.damage;
// Golem Mastery skill bonus
const masteryBonus = 1 + (skills.golemMastery || 0) * 0.1;
damage *= masteryBonus;
return damage;
}
// Calculate golem attack speed with skill bonuses
export function getGolemAttackSpeed(
golemId: string,
skills: Record<string, number>
): number {
const golem = GOLEMS_DEF[golemId];
if (!golem) return 0;
let speed = golem.attackSpeed;
// Golem Efficiency skill bonus
const efficiencyBonus = 1 + (skills.golemEfficiency || 0) * 0.05;
speed *= efficiencyBonus;
return speed;
}
// Get floors golems can last (base 1, +1 per Golem Longevity skill level)
export function getGolemFloorDuration(skills: Record<string, number>): number {
return 1 + (skills.golemLongevity || 0);
}
// Get maintenance cost multiplier (Golem Siphon reduces by 10% per level)
export function getGolemMaintenanceMultiplier(skills: Record<string, number>): number {
return 1 - (skills.golemSiphon || 0) * 0.1;
}
// Check if player can afford golem summon cost
export function canAffordGolemSummon(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>
): boolean {
const golem = GOLEMS_DEF[golemId];
if (!golem) return false;
for (const cost of golem.summonCost) {
if (cost.type === 'raw') {
if (rawMana < cost.amount) return false;
} else if (cost.element) {
const elem = elements[cost.element];
if (!elem || !elem.unlocked || elem.current < cost.amount) return false;
}
}
return true;
}
// Deduct golem summon cost from mana pools
export function deductGolemSummonCost(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>
): { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> } {
const golem = GOLEMS_DEF[golemId];
if (!golem) return { rawMana, elements };
let newRawMana = rawMana;
let newElements = { ...elements };
for (const cost of golem.summonCost) {
if (cost.type === 'raw') {
newRawMana -= cost.amount;
} else if (cost.element && newElements[cost.element]) {
newElements = {
...newElements,
[cost.element]: {
...newElements[cost.element],
current: newElements[cost.element].current - cost.amount,
},
};
}
}
return { rawMana: newRawMana, elements: newElements };
}
// Check if player can afford golem maintenance for one tick
export function canAffordGolemMaintenance(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
skills: Record<string, number>
): boolean {
const golem = GOLEMS_DEF[golemId];
if (!golem) return false;
const maintenanceMult = getGolemMaintenanceMultiplier(skills);
for (const cost of golem.maintenanceCost) {
const adjustedAmount = cost.amount * maintenanceMult;
if (cost.type === 'raw') {
if (rawMana < adjustedAmount) return false;
} else if (cost.element) {
const elem = elements[cost.element];
if (!elem || !elem.unlocked || elem.current < adjustedAmount) return false;
}
}
return true;
}
// Deduct golem maintenance cost for one tick
export function deductGolemMaintenance(
golemId: string,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
skills: Record<string, number>
): { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> } {
const golem = GOLEMS_DEF[golemId];
if (!golem) return { rawMana, elements };
const maintenanceMult = getGolemMaintenanceMultiplier(skills);
let newRawMana = rawMana;
let newElements = { ...elements };
for (const cost of golem.maintenanceCost) {
const adjustedAmount = cost.amount * maintenanceMult;
if (cost.type === 'raw') {
newRawMana -= adjustedAmount;
} else if (cost.element && newElements[cost.element]) {
newElements = {
...newElements,
[cost.element]: {
...newElements[cost.element],
current: newElements[cost.element].current - adjustedAmount,
},
};
}
}
return { rawMana: newRawMana, elements: newElements };
}