import type { SkillV2Def, SkillEffect, StatKey, ComputedStats } from './skills-v2-types'; import { SKILLS_V2 } from './skills-v2-defs'; // Re-export individual skills from category modules export { manaWell, manaFlow, manaOverflow, manaTap, manaSurge, manaSpring, quickLearner, focusedMind, knowledgeRetention, meditation, deepTrance, voidMeditation, } from './skills-core'; export { enchanting, efficientEnchant, enchantSpeed, essenceRefining, disenchanting, } from './skills-enchant'; export { arcaneFury, combatTraining, precision, elementalMastery, attackSpeed, armorPiercing, spellDamage, } from './skills-combat'; export { golemMastery, golemEfficiency, golemLongevity, } from './skills-golemancy'; export { invocation, pactMastery, guardianLore, } from './skills-invocation'; export { effCrafting, fieldRepair, } from './skills-crafting'; export { fireManaCap, waterManaCap, airManaCap, earthManaCap, lightManaCap, darkManaCap, deathManaCap, metalManaCap, sandManaCap, lightningManaCap, transferenceManaCap, } from './skills-element-caps'; export { pactWeaving, guardianConstructs, enchantedGolemancy, } from './skills-hybrid'; export { researchManaSpells, researchFireSpells, researchWaterSpells, researchAirSpells, researchEarthSpells, researchLightSpells, researchDarkSpells, researchLifeDeathSpells, researchAdvancedFire, researchAdvancedWater, researchAdvancedAir, researchAdvancedEarth, researchAdvancedLight, researchAdvancedDark, researchMasterFire, researchMasterWater, researchMasterEarth, researchDamageEffects, researchCombatEffects, researchManaEffects, researchAdvancedManaEffects, researchUtilityEffects, researchSpecialEffects, researchOverpower, researchMetalSpells, researchSandSpells, researchLightningSpells, researchAdvancedMetal, researchAdvancedSand, researchAdvancedLightning, researchMasterMetal, researchMasterSand, researchMasterLightning, researchTransferenceSpells, researchAdvancedTransference, researchMasterTransference, researchAdvancedFireCap, researchAdvancedWaterCap, researchAdvancedAirCap, researchAdvancedEarthCap, researchAdvancedLightCap, researchAdvancedDarkCap, researchAdvancedDeathCap, researchMasterFireCap, researchMasterWaterCap, researchMasterAirCap, researchMasterEarthCap, researchMasterLightCap, researchMasterDarkCap, researchMasterDeathCap, researchMetalCapacity, researchAdvancedMetalCap, researchSandCapacity, researchAdvancedSandCap, researchLightningCapacity, researchAdvancedLightningCap, researchCrystalCapacity, researchAdvancedCrystalCap, researchStellarCapacity, researchAdvancedStellarCap, researchVoidCapacity, researchAdvancedVoidCap, } from './skills-research'; export { SKILLS_V2 }; // Default Base Stats export const BASE_STATS: ComputedStats = { maxMana: 100, manaRegen: 2, clickMana: 1, elementCap: 10, studySpeed: 1, studyCostMult: 1, meditationEfficiency: 1, enchantCapacity: 100, enchantSpeed: 1, enchantPower: 1, disenchantRecovery: 1, baseDamage: 5, damageMultiplier: 1, attackSpeed: 1, critChance: 0, critMultiplier: 1.5, armorPierce: 0, insightGain: 1, golemDamage: 1, golemDuration: 1, pactMultiplier: 1, conversionRate: 1, spellDamage: 1, guardianDamage: 1, craftSpeed: 1, repairSpeed: 1, fireCap: 0, waterCap: 0, airCap: 0, earthCap: 0, lightCap: 0, darkCap: 0, deathCap: 0, metalCap: 0, sandCap: 0, lightningCap: 0, transferenceCap: 0, crystalCap: 0, stellarCap: 0, voidCap: 0, elementalDamage: 1, }; const ELEMENT_CAP_STATS: Record = { fire: 'fireCap', water: 'waterCap', air: 'airCap', earth: 'earthCap', light: 'lightCap', dark: 'darkCap', death: 'deathCap', metal: 'metalCap', sand: 'sandCap', lightning: 'lightningCap', transference: 'transferenceCap', crystal: 'crystalCap', stellar: 'stellarCap', void: 'voidCap', }; /** * Compute all game stats from skill levels. */ export function computeStats( skills: Record, prestigeUpgrades: Record = {} ): ComputedStats { const stats: ComputedStats = { ...BASE_STATS }; for (const [skillId, level] of Object.entries(skills)) { if (level <= 0) continue; const def = SKILLS_V2[skillId]; if (!def) continue; for (const effect of def.effects) { const key = effect.stat as keyof ComputedStats; const currentVal = stats[key] as number; if (effect.mode === 'add') { (stats[key] as number) = currentVal + effect.valuePerLevel * level; } else { const perLevelMultiplier = 1 + effect.valuePerLevel; let result = currentVal; for (let i = 0; i < level; i++) result *= perLevelMultiplier; (stats[key] as number) = result; } } } if (prestigeUpgrades.manaWell) stats.maxMana += prestigeUpgrades.manaWell * 500; if (prestigeUpgrades.manaFlow) stats.manaRegen += prestigeUpgrades.manaFlow * 0.5; if (prestigeUpgrades.elementalAttune) stats.elementCap += prestigeUpgrades.elementalAttune * 25; if (prestigeUpgrades.pactBinding) stats.pactMultiplier += prestigeUpgrades.pactBinding * 0.1; if (prestigeUpgrades.insightAmp) stats.insightGain *= 1 + prestigeUpgrades.insightAmp * 0.25; let elementCapFromSkills = 0; for (const [, statKey] of Object.entries(ELEMENT_CAP_STATS)) { const val = stats[statKey] as number; if (val > 0) elementCapFromSkills += val; } if (elementCapFromSkills > 0) stats.elementCap += elementCapFromSkills; stats.maxMana = Math.max(1, Math.round(stats.maxMana)); stats.manaRegen = Math.round(stats.manaRegen * 100) / 100; stats.clickMana = Math.max(1, stats.clickMana); stats.elementCap = Math.max(10, Math.round(stats.elementCap)); stats.baseDamage = Math.max(1, Math.round(stats.baseDamage)); stats.critChance = Math.min(1, Math.max(0, stats.critChance)); stats.armorPierce = Math.min(1, Math.max(0, stats.armorPierce)); stats.attackSpeed = Math.max(0.1, stats.attackSpeed); stats.insightGain = Math.max(0, stats.insightGain); stats.golemDamage = Math.max(0.1, stats.golemDamage); stats.golemDuration = Math.max(1, stats.golemDuration); stats.enchantCapacity = Math.max(10, Math.round(stats.enchantCapacity)); stats.conversionRate = Math.max(0, stats.conversionRate); return stats; } /** * Get the base key for a tiered skill (strips _tN suffix). */ export function getBaseSkillId(skillId: string): string { const match = skillId.match(/^(.+?)_t(\d+)$/); return match ? match[1] : skillId; } /** * Check if a skill has prerequisites that are met. */ export function hasPrerequisites( skills: Record, prerequisites?: Record ): boolean { if (!prerequisites) return true; for (const [reqId, reqLevel] of Object.entries(prerequisites)) { if ((skills[reqId] || 0) < reqLevel) return false; } return true; } /** Legacy compat wrapper */ export function computeStatsLegacy(state: { skills: Record; prestigeUpgrades?: Record; }): ComputedStats { return computeStats(state.skills, state.prestigeUpgrades || {}); }