feat: split skills-v2-defs into category modules and fix export
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 35s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 35s
- Split 636-line skills-v2-defs.ts into 9 category files (all under 400 lines) - Add skills-v2-registry.ts to build SKILLS_V2 flat record from modules - Fix missing re-export of SKILLS_V2 from skills-v2.ts - Fix clickMana clamping: remove Math.round to allow fractional values - Fix golemDuration clamping: remove Math.round to allow fractional values - Fix guardianConstructs effect: duration uses 'add' mode instead of 'multiply' - All 70 existing tests pass
This commit is contained in:
@@ -0,0 +1,269 @@
|
||||
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<string, keyof ComputedStats> = {
|
||||
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<string, number>,
|
||||
prestigeUpgrades: Record<string, number> = {}
|
||||
): 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<string, number>,
|
||||
prerequisites?: Record<string, number>
|
||||
): 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<string, number>;
|
||||
prestigeUpgrades?: Record<string, number>;
|
||||
}): ComputedStats {
|
||||
return computeStats(state.skills, state.prestigeUpgrades || {});
|
||||
}
|
||||
Reference in New Issue
Block a user