diff --git a/src/lib/game/constants.ts b/src/lib/game/constants.ts index 0c9ac2f..2b50b82 100755 --- a/src/lib/game/constants.ts +++ b/src/lib/game/constants.ts @@ -39,10 +39,11 @@ export const ELEMENTS: Record = { force: { name: "Force", sym: "💨", color: "#E74C3C", glow: "#E74C3C40", cat: "utility" }, // Composite Elements - blood: { name: "Blood", sym: "🩸", color: "#C0392B", glow: "#C0392B40", cat: "composite", recipe: ["life", "water"] }, - metal: { name: "Metal", sym: "⚙️", color: "#BDC3C7", glow: "#BDC3C740", cat: "composite", recipe: ["fire", "earth"] }, - wood: { name: "Wood", sym: "🪵", color: "#8B5E3C", glow: "#8B5E3C40", cat: "composite", recipe: ["life", "earth"] }, - sand: { name: "Sand", sym: "⏳", color: "#D4AC0D", glow: "#D4AC0D40", cat: "composite", recipe: ["earth", "water"] }, + blood: { name: "Blood", sym: "🩸", color: "#C0392B", glow: "#C0392B40", cat: "composite", recipe: ["life", "water"] }, + metal: { name: "Metal", sym: "⚙️", color: "#BDC3C7", glow: "#BDC3C740", cat: "composite", recipe: ["fire", "earth"] }, + wood: { name: "Wood", sym: "🪵", color: "#8B5E3C", glow: "#8B5E3C40", cat: "composite", recipe: ["life", "earth"] }, + sand: { name: "Sand", sym: "⏳", color: "#D4AC0D", glow: "#D4AC0D40", cat: "composite", recipe: ["earth", "water"] }, + lightning: { name: "Lightning", sym: "⚡", color: "#FFEB3B", glow: "#FFEB3B40", cat: "composite", recipe: ["fire", "air"] }, // Exotic Elements crystal: { name: "Crystal", sym: "💎", color: "#85C1E9", glow: "#85C1E940", cat: "exotic", recipe: ["sand", "sand", "mental"] }, @@ -52,10 +53,103 @@ export const ELEMENTS: Record = { export const FLOOR_ELEM_CYCLE = ["fire", "water", "air", "earth", "light", "dark", "life", "death"]; +// ─── Room Types ──────────────────────────────────────────────────────────────── +// Room types for spire floors +export type RoomType = 'combat' | 'puzzle' | 'swarm' | 'speed' | 'guardian'; + +// Room generation rules: +// - Guardian floors (10, 20, 30, etc.) are ALWAYS guardian type +// - Every 5th floor (5, 15, 25, etc.) has a chance for special rooms +// - Other floors are combat with chance for swarm/speed +export const PUZZLE_ROOM_INTERVAL = 7; // Every 7 floors, chance for puzzle +export const SWARM_ROOM_CHANCE = 0.15; // 15% chance for swarm room +export const SPEED_ROOM_CHANCE = 0.10; // 10% chance for speed room +export const PUZZLE_ROOM_CHANCE = 0.20; // 20% chance for puzzle room on puzzle floors + +// Puzzle room definitions - themed around attunements +export const PUZZLE_ROOMS: Record = { + enchanter_trial: { + name: "Enchanter's Trial", + attunements: ['enchanter'], + baseProgressPerTick: 0.02, + attunementBonus: 0.03, + description: "Decipher ancient enchantment runes." + }, + fabricator_trial: { + name: "Fabricator's Trial", + attunements: ['fabricator'], + baseProgressPerTick: 0.02, + attunementBonus: 0.03, + description: "Construct a mana-powered mechanism." + }, + invoker_trial: { + name: "Invoker's Trial", + attunements: ['invoker'], + baseProgressPerTick: 0.02, + attunementBonus: 0.03, + description: "Commune with guardian spirits." + }, + hybrid_enchanter_fabricator: { + name: "Fusion Workshop", + attunements: ['enchanter', 'fabricator'], + baseProgressPerTick: 0.015, + attunementBonus: 0.025, + description: "Enchant and construct in harmony." + }, + hybrid_enchanter_invoker: { + name: "Ritual Circle", + attunements: ['enchanter', 'invoker'], + baseProgressPerTick: 0.015, + attunementBonus: 0.025, + description: "Bind pact energies into enchantments." + }, + hybrid_fabricator_invoker: { + name: "Golem Forge", + attunements: ['fabricator', 'invoker'], + baseProgressPerTick: 0.015, + attunementBonus: 0.025, + description: "Channel guardian power into constructs." + }, +}; + +// Swarm room configuration +export const SWARM_CONFIG = { + minEnemies: 3, + maxEnemies: 6, + hpMultiplier: 0.4, // Each enemy has 40% of normal floor HP + armorBase: 0, // Swarm enemies start with no armor + armorPerFloor: 0.01, // Gain 1% armor per 10 floors +}; + +// Speed room configuration (dodging enemies) +export const SPEED_ROOM_CONFIG = { + baseDodgeChance: 0.25, // 25% base dodge chance + dodgePerFloor: 0.005, // +0.5% dodge per floor + maxDodge: 0.50, // Max 50% dodge + speedBonus: 0.5, // 50% less time to complete if dodged +}; + +// Armor scaling for normal floors +export const FLOOR_ARMOR_CONFIG = { + baseChance: 0, // No armor on floor 1-9 + chancePerFloor: 0.01, // +1% chance per floor after 10 + maxArmorChance: 0.5, // Max 50% of floors have armor + minArmor: 0.05, // Min 5% armor + maxArmor: 0.25, // Max 25% armor on non-guardians +}; + // ─── Guardians ──────────────────────────────────────────────────────────────── +// All guardians have armor - damage reduction percentage export const GUARDIANS: Record = { 10: { name: "Ignis Prime", element: "fire", hp: 5000, pact: 1.5, color: "#FF6B35", + armor: 0.10, // 10% damage reduction boons: [ { type: 'elementalDamage', value: 5, desc: '+5% Fire damage' }, { type: 'maxMana', value: 50, desc: '+50 max mana' }, @@ -66,6 +160,7 @@ export const GUARDIANS: Record = { }, 20: { name: "Aqua Regia", element: "water", hp: 15000, pact: 1.75, color: "#4ECDC4", + armor: 0.15, boons: [ { type: 'elementalDamage', value: 5, desc: '+5% Water damage' }, { type: 'manaRegen', value: 0.5, desc: '+0.5 mana regen' }, @@ -76,6 +171,7 @@ export const GUARDIANS: Record = { }, 30: { name: "Ventus Rex", element: "air", hp: 30000, pact: 2.0, color: "#00D4FF", + armor: 0.18, boons: [ { type: 'elementalDamage', value: 5, desc: '+5% Air damage' }, { type: 'castingSpeed', value: 5, desc: '+5% cast speed' }, @@ -86,6 +182,7 @@ export const GUARDIANS: Record = { }, 40: { name: "Terra Firma", element: "earth", hp: 50000, pact: 2.25, color: "#F4A261", + armor: 0.25, // Earth guardian - highest armor boons: [ { type: 'elementalDamage', value: 5, desc: '+5% Earth damage' }, { type: 'maxMana', value: 100, desc: '+100 max mana' }, @@ -96,6 +193,7 @@ export const GUARDIANS: Record = { }, 50: { name: "Lux Aeterna", element: "light", hp: 80000, pact: 2.5, color: "#FFD700", + armor: 0.20, boons: [ { type: 'elementalDamage', value: 10, desc: '+10% Light damage' }, { type: 'insightGain', value: 10, desc: '+10% insight gain' }, @@ -106,6 +204,7 @@ export const GUARDIANS: Record = { }, 60: { name: "Umbra Mortis", element: "dark", hp: 120000, pact: 2.75, color: "#9B59B6", + armor: 0.22, boons: [ { type: 'elementalDamage', value: 10, desc: '+10% Dark damage' }, { type: 'critDamage', value: 15, desc: '+15% crit damage' }, @@ -116,6 +215,7 @@ export const GUARDIANS: Record = { }, 70: { name: "Vita Sempiterna", element: "life", hp: 180000, pact: 3.0, color: "#2ECC71", + armor: 0.20, boons: [ { type: 'elementalDamage', value: 10, desc: '+10% Life damage' }, { type: 'manaRegen', value: 1, desc: '+1 mana regen' }, @@ -126,6 +226,7 @@ export const GUARDIANS: Record = { }, 80: { name: "Mors Ultima", element: "death", hp: 250000, pact: 3.25, color: "#778CA3", + armor: 0.25, boons: [ { type: 'elementalDamage', value: 10, desc: '+10% Death damage' }, { type: 'rawDamage', value: 10, desc: '+10% raw damage' }, @@ -136,6 +237,7 @@ export const GUARDIANS: Record = { }, 90: { name: "Primordialis", element: "void", hp: 400000, pact: 4.0, color: "#4A235A", + armor: 0.30, boons: [ { type: 'elementalDamage', value: 15, desc: '+15% Void damage' }, { type: 'maxMana', value: 200, desc: '+200 max mana' }, @@ -147,6 +249,7 @@ export const GUARDIANS: Record = { }, 100: { name: "The Awakened One", element: "stellar", hp: 1000000, pact: 5.0, color: "#F0E68C", + armor: 0.35, // Final boss has highest armor boons: [ { type: 'elementalDamage', value: 20, desc: '+20% Stellar damage' }, { type: 'maxMana', value: 500, desc: '+500 max mana' }, @@ -648,6 +751,228 @@ export const SPELLS_DEF: Record = { studyTime: 36, desc: "Shatter crystalline energy." }, + + // ═══════════════════════════════════════════════════════════════════════════ + // LIGHTNING SPELLS - Fast, armor-piercing, harder to dodge + // ═══════════════════════════════════════════════════════════════════════════ + + // Tier 1 - Basic Lightning + spark: { + name: "Spark", + elem: "lightning", + dmg: 8, + cost: elemCost("lightning", 1), + tier: 1, + castSpeed: 4, + unlock: 120, + studyTime: 2, + desc: "A quick spark of lightning. Very fast and hard to dodge.", + effects: [{ type: 'armor_pierce', value: 0.2 }] + }, + lightningBolt: { + name: "Lightning Bolt", + elem: "lightning", + dmg: 14, + cost: elemCost("lightning", 2), + tier: 1, + castSpeed: 3, + unlock: 150, + studyTime: 3, + desc: "A bolt of lightning that pierces armor.", + effects: [{ type: 'armor_pierce', value: 0.3 }] + }, + + // Tier 2 - Advanced Lightning + chainLightning: { + name: "Chain Lightning", + elem: "lightning", + dmg: 25, + cost: elemCost("lightning", 5), + tier: 2, + castSpeed: 2, + unlock: 900, + studyTime: 8, + desc: "Lightning that arcs between enemies. Hits 3 targets.", + isAoe: true, + aoeTargets: 3, + effects: [{ type: 'chain', value: 3 }] + }, + stormCall: { + name: "Storm Call", + elem: "lightning", + dmg: 40, + cost: elemCost("lightning", 6), + tier: 2, + castSpeed: 1.5, + unlock: 1100, + studyTime: 10, + desc: "Call down a storm. Hits 2 targets with armor pierce.", + isAoe: true, + aoeTargets: 2, + effects: [{ type: 'armor_pierce', value: 0.4 }] + }, + + // Tier 3 - Master Lightning + thunderStrike: { + name: "Thunder Strike", + elem: "lightning", + dmg: 150, + cost: elemCost("lightning", 15), + tier: 3, + castSpeed: 0.8, + unlock: 10000, + studyTime: 24, + desc: "Devastating lightning that ignores 50% armor.", + effects: [{ type: 'armor_pierce', value: 0.5 }] + }, + + // ═══════════════════════════════════════════════════════════════════════════ + // AOE SPELLS - Hit multiple enemies, less damage per target + // ═══════════════════════════════════════════════════════════════════════════ + + // Tier 1 AOE + fireballAoe: { + name: "Fireball (AOE)", + elem: "fire", + dmg: 8, + cost: elemCost("fire", 3), + tier: 1, + castSpeed: 2, + unlock: 150, + studyTime: 3, + desc: "An explosive fireball that hits 3 enemies.", + isAoe: true, + aoeTargets: 3, + effects: [{ type: 'aoe', value: 3 }] + }, + frostNova: { + name: "Frost Nova", + elem: "water", + dmg: 6, + cost: elemCost("water", 3), + tier: 1, + castSpeed: 2, + unlock: 140, + studyTime: 3, + desc: "A burst of frost hitting 4 enemies. May freeze.", + isAoe: true, + aoeTargets: 4, + effects: [{ type: 'freeze', value: 0.15, chance: 0.2 }] + }, + + // Tier 2 AOE + meteorShower: { + name: "Meteor Shower", + elem: "fire", + dmg: 20, + cost: elemCost("fire", 8), + tier: 2, + castSpeed: 1, + unlock: 1200, + studyTime: 10, + desc: "Rain meteors on 5 enemies.", + isAoe: true, + aoeTargets: 5 + }, + blizzard: { + name: "Blizzard", + elem: "water", + dmg: 18, + cost: elemCost("water", 7), + tier: 2, + castSpeed: 1.2, + unlock: 1000, + studyTime: 9, + desc: "A freezing blizzard hitting 4 enemies.", + isAoe: true, + aoeTargets: 4, + effects: [{ type: 'freeze', value: 0.1, chance: 0.15 }] + }, + earthquakeAoe: { + name: "Earth Tremor", + elem: "earth", + dmg: 25, + cost: elemCost("earth", 8), + tier: 2, + castSpeed: 0.8, + unlock: 1400, + studyTime: 10, + desc: "Shake the ground, hitting 3 enemies with high damage.", + isAoe: true, + aoeTargets: 3 + }, + + // Tier 3 AOE + apocalypse: { + name: "Apocalypse", + elem: "fire", + dmg: 80, + cost: elemCost("fire", 20), + tier: 3, + castSpeed: 0.5, + unlock: 15000, + studyTime: 30, + desc: "End times. Hits ALL enemies with devastating fire.", + isAoe: true, + aoeTargets: 10 + }, + + // ═══════════════════════════════════════════════════════════════════════════ + // MAGIC SWORD ENCHANTMENTS - For weapon enchanting system + // ═══════════════════════════════════════════════════════════════════════════ + + fireBlade: { + name: "Fire Blade", + elem: "fire", + dmg: 3, + cost: rawCost(1), + tier: 1, + castSpeed: 4, + unlock: 100, + studyTime: 2, + desc: "Enchant a blade with fire. Burns enemies over time.", + isWeaponEnchant: true, + effects: [{ type: 'burn', value: 2, duration: 3 }] + }, + frostBlade: { + name: "Frost Blade", + elem: "water", + dmg: 3, + cost: rawCost(1), + tier: 1, + castSpeed: 4, + unlock: 100, + studyTime: 2, + desc: "Enchant a blade with frost. Prevents enemy dodge.", + isWeaponEnchant: true, + effects: [{ type: 'freeze', value: 0, chance: 1 }] // 100% freeze = no dodge + }, + lightningBlade: { + name: "Lightning Blade", + elem: "lightning", + dmg: 4, + cost: rawCost(1), + tier: 1, + castSpeed: 5, + unlock: 150, + studyTime: 3, + desc: "Enchant a blade with lightning. Pierces 30% armor.", + isWeaponEnchant: true, + effects: [{ type: 'armor_pierce', value: 0.3 }] + }, + voidBlade: { + name: "Void Blade", + elem: "dark", + dmg: 5, + cost: rawCost(2), + tier: 2, + castSpeed: 3, + unlock: 800, + studyTime: 8, + desc: "Enchant a blade with void. 10% lifesteal.", + isWeaponEnchant: true, + effects: [{ type: 'lifesteal', value: 0.1 }] + }, }; // ─── Skills ─────────────────────────────────────────────────────────────────── @@ -848,6 +1173,7 @@ export const ELEMENT_OPPOSITES: Record = { air: 'earth', earth: 'air', light: 'dark', dark: 'light', life: 'death', death: 'life', + lightning: 'earth', // Lightning is weak to earth (grounding) }; // ─── Element Icon Mapping (Lucide Icons) ────────────────────────────────────── @@ -869,6 +1195,7 @@ export const ELEMENT_ICON_NAMES: Record = { metal: 'Target', wood: 'TreeDeciduous', sand: 'Hourglass', + lightning: 'Zap', crystal: 'Gem', stellar: 'Star', void: 'CircleDot', diff --git a/src/lib/game/store.ts b/src/lib/game/store.ts index e7b82d4..ce95476 100755 --- a/src/lib/game/store.ts +++ b/src/lib/game/store.ts @@ -2,7 +2,7 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; -import type { GameState, GameAction, StudyTarget, SpellCost, SkillUpgradeChoice, EquipmentSlot, EquipmentInstance, EnchantmentDesign, DesignEffect, AttunementState } from './types'; +import type { GameState, GameAction, StudyTarget, SpellCost, SkillUpgradeChoice, EquipmentSlot, EquipmentInstance, EnchantmentDesign, DesignEffect, AttunementState, FloorState, EnemyState, RoomType } from './types'; import { ELEMENTS, GUARDIANS, @@ -22,6 +22,14 @@ import { EFFECT_RESEARCH_MAPPING, BASE_UNLOCKED_EFFECTS, ENCHANTING_UNLOCK_EFFECTS, + PUZZLE_ROOMS, + PUZZLE_ROOM_INTERVAL, + PUZZLE_ROOM_CHANCE, + SWARM_ROOM_CHANCE, + SPEED_ROOM_CHANCE, + SWARM_CONFIG, + SPEED_ROOM_CONFIG, + FLOOR_ARMOR_CONFIG, } from './constants'; import { computeEffects, hasSpecial, SPECIAL_EFFECTS, type ComputedEffects } from './upgrade-effects'; import { @@ -99,6 +107,174 @@ export function getFloorElement(floor: number): string { return FLOOR_ELEM_CYCLE[(floor - 1) % 8]; } +// ─── Room Generation Functions ──────────────────────────────────────────────── + +// Generate room type for a floor +export function generateRoomType(floor: number): RoomType { + // Guardian floors are always guardian type + if (GUARDIANS[floor]) { + return 'guardian'; + } + + // Check for puzzle room (every PUZZLE_ROOM_INTERVAL floors) + if (floor % PUZZLE_ROOM_INTERVAL === 0 && Math.random() < PUZZLE_ROOM_CHANCE) { + return 'puzzle'; + } + + // Check for swarm room + if (Math.random() < SWARM_ROOM_CHANCE) { + return 'swarm'; + } + + // Check for speed room + if (Math.random() < SPEED_ROOM_CHANCE) { + return 'speed'; + } + + // Default to combat + return 'combat'; +} + +// Get armor for a non-guardian floor +export function getFloorArmor(floor: number): number { + if (GUARDIANS[floor]) { + return GUARDIANS[floor].armor || 0; + } + + // Armor becomes more common on higher floors + if (floor < 10) return 0; + + const armorChance = Math.min(FLOOR_ARMOR_CONFIG.maxArmorChance, + FLOOR_ARMOR_CONFIG.baseChance + (floor - 10) * FLOOR_ARMOR_CONFIG.chancePerFloor); + + if (Math.random() > armorChance) return 0; + + // Scale armor with floor + const armorRange = FLOOR_ARMOR_CONFIG.maxArmor - FLOOR_ARMOR_CONFIG.minArmor; + const floorProgress = Math.min(1, (floor - 10) / 90); + return FLOOR_ARMOR_CONFIG.minArmor + armorRange * floorProgress * Math.random(); +} + +// Get dodge chance for a speed room +export function getDodgeChance(floor: number): number { + return Math.min( + SPEED_ROOM_CONFIG.maxDodge, + SPEED_ROOM_CONFIG.baseDodgeChance + floor * SPEED_ROOM_CONFIG.dodgePerFloor + ); +} + +// Generate enemies for a swarm room +export function generateSwarmEnemies(floor: number): EnemyState[] { + const baseHP = getFloorMaxHP(floor); + const element = getFloorElement(floor); + const numEnemies = SWARM_CONFIG.minEnemies + + Math.floor(Math.random() * (SWARM_CONFIG.maxEnemies - SWARM_CONFIG.minEnemies + 1)); + + const enemies: EnemyState[] = []; + for (let i = 0; i < numEnemies; i++) { + enemies.push({ + id: `enemy_${i}`, + hp: Math.floor(baseHP * SWARM_CONFIG.hpMultiplier), + maxHP: Math.floor(baseHP * SWARM_CONFIG.hpMultiplier), + armor: SWARM_CONFIG.armorBase + Math.floor(floor / 10) * SWARM_CONFIG.armorPerFloor, + dodgeChance: 0, + element, + }); + } + return enemies; +} + +// Generate initial floor state +export function generateFloorState(floor: number): FloorState { + const roomType = generateRoomType(floor); + const element = getFloorElement(floor); + const baseHP = getFloorMaxHP(floor); + const guardian = GUARDIANS[floor]; + + switch (roomType) { + case 'guardian': + return { + roomType: 'guardian', + enemies: [{ + id: 'guardian', + hp: guardian.hp, + maxHP: guardian.hp, + armor: guardian.armor || 0, + dodgeChance: 0, + element: guardian.element, + }], + }; + + case 'swarm': + return { + roomType: 'swarm', + enemies: generateSwarmEnemies(floor), + }; + + case 'speed': + return { + roomType: 'speed', + enemies: [{ + id: 'speed_enemy', + hp: baseHP, + maxHP: baseHP, + armor: getFloorArmor(floor), + dodgeChance: getDodgeChance(floor), + element, + }], + }; + + case 'puzzle': { + // Select a puzzle type based on player's attunements + const puzzleKeys = Object.keys(PUZZLE_ROOMS); + const selectedPuzzle = puzzleKeys[Math.floor(Math.random() * puzzleKeys.length)]; + const puzzle = PUZZLE_ROOMS[selectedPuzzle]; + return { + roomType: 'puzzle', + enemies: [], + puzzleProgress: 0, + puzzleRequired: 1, + puzzleId: selectedPuzzle, + puzzleAttunements: puzzle.attunements, + }; + } + + default: // combat + return { + roomType: 'combat', + enemies: [{ + id: 'enemy', + hp: baseHP, + maxHP: baseHP, + armor: getFloorArmor(floor), + dodgeChance: 0, + element, + }], + }; + } +} + +// Get puzzle progress speed based on attunements +export function getPuzzleProgressSpeed( + puzzleId: string, + attunements: Record +): number { + const puzzle = PUZZLE_ROOMS[puzzleId]; + if (!puzzle) return 0.02; // Default slow progress + + let speed = puzzle.baseProgressPerTick; + + // Add bonus for each relevant attunement level + for (const attId of puzzle.attunements) { + const attState = attunements[attId]; + if (attState?.active) { + speed += puzzle.attunementBonus * (attState.level || 1); + } + } + + return speed; +} + // ─── Computed Stats Functions ───────────────────────────────────────────────── // Helper to get effective skill level accounting for tiers @@ -466,6 +642,9 @@ function makeInitial(overrides: Partial = {}): GameState { activeSpell: 'manaBolt', currentAction: 'meditate', castProgress: 0, + + // Initialize room state + currentRoom: generateFloorState(startFloor), spells: startSpells, skills: overrides.skills || {}, diff --git a/src/lib/game/types.ts b/src/lib/game/types.ts index 6ed6904..65221ff 100755 --- a/src/lib/game/types.ts +++ b/src/lib/game/types.ts @@ -64,6 +64,7 @@ export interface GuardianDef { pactCost: number; // Mana cost to perform pact ritual pactTime: number; // Hours required for pact ritual uniquePerk: string; // Description of unique perk + armor?: number; // Damage reduction (0-1, e.g., 0.2 = 20% reduction) } // Spell cost can be raw mana or elemental mana @@ -84,12 +85,17 @@ export interface SpellDef { castSpeed?: number; // Casts per hour (default 1, higher = faster) desc?: string; // Optional spell description effects?: SpellEffect[]; // Optional special effects + isAoe?: boolean; // AOE spell that hits multiple enemies + aoeTargets?: number; // Number of enemies hit by AOE + isWeaponEnchant?: boolean; // Can be used as weapon enchantment (magic swords) } export interface SpellEffect { - type: 'lifesteal' | 'burn' | 'freeze' | 'stun' | 'pierce' | 'multicast' | 'shield' | 'buff'; + type: 'lifesteal' | 'burn' | 'freeze' | 'stun' | 'pierce' | 'multicast' | 'shield' | 'buff' | 'chain' | 'aoe' | 'armor_pierce'; value: number; // Effect potency duration?: number; // Duration in hours for timed effects + targets?: number; // For AOE: number of targets + chance?: number; // For chance-based effects (e.g., stun chance) } export interface SpellState { @@ -98,6 +104,28 @@ export interface SpellState { studyProgress?: number; // Hours studied so far (for in-progress spells) } +// ─── Room and Enemy Types ───────────────────────────────────────────────────── + +export type RoomType = 'combat' | 'puzzle' | 'swarm' | 'speed' | 'guardian'; + +export interface EnemyState { + id: string; + hp: number; + maxHP: number; + armor: number; // Damage reduction (0-1) + dodgeChance: number; // For speed rooms (0-1) + element: string; +} + +export interface FloorState { + roomType: RoomType; + enemies: EnemyState[]; // For swarm rooms, multiple enemies + puzzleProgress?: number; // For puzzle rooms (0-1) + puzzleRequired?: number; // Total progress needed + puzzleId?: string; // Which puzzle type + puzzleAttunements?: string[]; // Which attunements speed up this puzzle +} + export interface SkillDef { name: string; desc: string; @@ -183,6 +211,11 @@ export interface EquipmentInstance { totalCapacity: number; // Base capacity + bonuses rarity: 'common' | 'uncommon' | 'rare' | 'epic' | 'legendary' | 'mythic'; quality: number; // 0-100, affects capacity efficiency + weaponMana?: number; // Current mana stored in weapon (for weapon enchantments) + weaponManaMax?: number; // Max mana the weapon can store + weaponManaRegen?: number; // Mana regen per hour for weapon + weaponManaType?: string; // Type of mana the weapon stores + activeWeaponEnchant?: string; // Active weapon enchantment (for magic swords) } export interface AppliedEnchantment { @@ -346,6 +379,9 @@ export interface GameState { activeSpell: string; currentAction: GameAction; castProgress: number; // Progress towards next spell cast (0-1) + + // Room system for special floors + currentRoom: FloorState; // Current room state (swarm, puzzle, speed, etc.) // Spells spells: Record;