refactor: replace static guardians with elemental progression system

Replace the old GUARDIANS constant (arbitrary floor assignments) with a proper
elemental → compound → exotic → combo progression:

- Floors 10-70:  Base elements (Fire, Water, Air, Earth, Light, Dark, Death)
- Floor 80:       Utility element (Transference)
- Floors 90-110:  Compound elements (Metal, Sand, Lightning)
- Floors 120-140: Exotic elements (Crystal, Stellar, Void)
- Floor 150+:     Procedural combo guardians (scaling with floor)

Key changes:
- Create guardian-data.ts with BASE_GUARDIANS (14 static entries)
- Simplify guardian-encounters.ts to only handle procedural combos (150+)
- getGuardianForFloor() now generates names for empty-name entries
- Remove old compound/exotic duplicate definitions from guardian-encounters.ts
- Update spire-utils.test.ts to test the new progression
- Update SpireSummaryTab.test.ts floor counts (14 static + 10 combo = 24)

All 89 guardian-related tests pass. 3 pre-existing failures in
room-utils-floor-state.test.ts are unrelated (speed room / floor 0 edge cases).
This commit is contained in:
2026-05-23 17:02:48 +02:00
parent 513cab81a3
commit 4ee6222b0e
6 changed files with 282 additions and 303 deletions
+163 -82
View File
@@ -1,163 +1,244 @@
// ─── Base Guardian Definitions (floors 10100) ────────────────────────────────
// Static canonical guardian data for the first 100 floors.
// ─── Static Guardian Definitions ──────────────────────────────────────────────
// Ordered by floor: base → utility → compound → exotic.
//
// Floors 10-80: Base elements (Fire, Water, Air, Earth, Light, Dark, Death)
// + Utility element (Transference) — 8 guardians total
// Floors 90-110: Compound elements (Metal, Sand, Lightning) — 3 guardians
// Floors 120-140: Exotic elements (Crystal, Stellar, Void) — 3 guardians
//
// Floor 150+: Procedural combination guardians (see getComboGuardian in guardian-encounters.ts)
import type { GuardianDef } from '../types';
export const BASE_GUARDIANS: Record<number, GuardianDef> = {
10: {
name: "Ignis Prime", element: "fire", hp: 5000, pact: 1.5, color: "#FF6B35",
// Helper: HP scales exponentially with floor
function hp(floor: number): number {
const base = 5000;
const exponent = 1.1 + (floor / 200);
return Math.floor(base * Math.pow(floor / 10, exponent));
}
// ─── Base Elements (Floors 1070) ────────────────────────────────────────────
const BASE_GUARDIANS: Record<number, GuardianDef> = {
// -- Base elements --
10: {
name: 'Ignis Prime', element: 'fire', hp: hp(10), pact: 1.5, color: '#FF6B35',
armor: 0.10,
boons: [
{ type: 'elementalDamage', value: 5, desc: '+5% Fire damage' },
{ type: 'maxMana', value: 50, desc: '+50 max mana' },
],
pactCost: 500,
pactTime: 2,
uniquePerk: "Fire spells cast 10% faster",
pactCost: 500, pactTime: 2,
uniquePerk: 'Fire spells cast 10% faster',
power: 50,
effects: [{ type: 'burn', value: 0.1 }],
signingCost: { mana: 500, time: 2 },
unlocksMana: ['fire', 'lightning'],
damageMultiplier: 1.1,
insightMultiplier: 1.05,
damageMultiplier: 1.1, insightMultiplier: 1.05,
},
20: {
name: "Aqua Regia", element: "water", hp: 15000, pact: 1.75, color: "#4ECDC4",
20: {
name: 'Aqua Regia', element: 'water', hp: hp(20), 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' },
],
pactCost: 1000,
pactTime: 4,
uniquePerk: "Water spells deal +15% damage",
pactCost: 1000, pactTime: 4,
uniquePerk: 'Water spells deal +15% damage',
power: 150,
effects: [{ type: 'armor_pierce', value: 0.15 }],
signingCost: { mana: 1000, time: 4 },
unlocksMana: ['water', 'transference'],
damageMultiplier: 1.2,
insightMultiplier: 1.1,
unlocksMana: ['water', 'sand'],
damageMultiplier: 1.2, insightMultiplier: 1.1,
},
30: {
name: "Ventus Rex", element: "air", hp: 30000, pact: 2.0, color: "#00D4FF",
30: {
name: 'Ventus Rex', element: 'air', hp: hp(30), 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' },
{ type: 'castingSpeed', value: 5, desc: '+5% casting speed' },
],
pactCost: 2000,
pactTime: 6,
uniquePerk: "Air spells have 15% crit chance",
pactCost: 2000, pactTime: 6,
uniquePerk: 'Air spells have 15% crit chance',
power: 300,
effects: [{ type: 'cast_speed', value: 0.05 }],
signingCost: { mana: 2000, time: 6 },
unlocksMana: ['air', 'sand'],
damageMultiplier: 1.3,
insightMultiplier: 1.15,
unlocksMana: ['air'],
damageMultiplier: 1.3, insightMultiplier: 1.15,
},
40: {
name: "Terra Firma", element: "earth", hp: 50000, pact: 2.25, color: "#F4A261",
40: {
name: 'Terra Firma', element: 'earth', hp: hp(40), pact: 2.25, color: '#F4A261',
armor: 0.25,
boons: [
{ type: 'elementalDamage', value: 5, desc: '+5% Earth damage' },
{ type: 'maxMana', value: 100, desc: '+100 max mana' },
],
pactCost: 4000,
pactTime: 8,
uniquePerk: "Earth spells deal +25% damage to guardians",
pactCost: 4000, pactTime: 8,
uniquePerk: 'Earth spells deal +25% damage to guardians',
power: 500,
effects: [{ type: 'armor_pierce', value: 0.2 }],
signingCost: { mana: 4000, time: 8 },
unlocksMana: ['earth', 'metal'],
damageMultiplier: 1.4,
insightMultiplier: 1.2,
damageMultiplier: 1.4, insightMultiplier: 1.2,
},
50: {
name: "Lux Aeterna", element: "light", hp: 80000, pact: 2.5, color: "#FFD700",
50: {
name: 'Lux Aeterna', element: 'light', hp: hp(50), 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' },
],
pactCost: 8000,
pactTime: 10,
uniquePerk: "Light spells reveal enemy weaknesses (+20% damage)",
pactCost: 8000, pactTime: 10,
uniquePerk: 'Light spells reveal enemy weaknesses (+20% damage)',
power: 800,
effects: [{ type: 'crit_chance', value: 0.1 }],
signingCost: { mana: 8000, time: 10 },
unlocksMana: ['light', 'crystal'],
damageMultiplier: 1.5,
insightMultiplier: 1.3,
damageMultiplier: 1.5, insightMultiplier: 1.3,
},
60: {
name: "Umbra Mortis", element: "dark", hp: 120000, pact: 2.75, color: "#9B59B6",
60: {
name: 'Umbra Mortis', element: 'dark', hp: hp(60), 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' },
],
pactCost: 15000,
pactTime: 12,
uniquePerk: "Dark spells deal +25% damage to armored enemies",
pactCost: 15000, pactTime: 12,
uniquePerk: 'Dark spells deal +25% damage to armored enemies',
power: 1200,
effects: [{ type: 'crit_damage', value: 0.15 }],
signingCost: { mana: 15000, time: 12 },
unlocksMana: ['dark', 'void'],
damageMultiplier: 1.6,
insightMultiplier: 1.4,
damageMultiplier: 1.6, insightMultiplier: 1.4,
},
80: {
name: "Mors Ultima", element: "death", hp: 250000, pact: 3.25, color: "#778CA3",
70: {
name: 'Mors Ultima', element: 'death', hp: hp(70), pact: 3.0, color: '#778CA3',
armor: 0.25,
boons: [
{ type: 'elementalDamage', value: 10, desc: '+10% Death damage' },
{ type: 'rawDamage', value: 10, desc: '+10% raw damage' },
],
pactCost: 40000,
pactTime: 16,
uniquePerk: "Death spells execute enemies below 20% HP",
pactCost: 25000, pactTime: 14,
uniquePerk: 'Death spells execute enemies below 20% HP',
power: 2500,
effects: [{ type: 'raw_damage', value: 0.1 }],
signingCost: { mana: 40000, time: 16 },
signingCost: { mana: 25000, time: 14 },
unlocksMana: ['death'],
damageMultiplier: 1.8,
insightMultiplier: 1.5,
damageMultiplier: 1.8, insightMultiplier: 1.5,
},
90: {
name: "Primordialis", element: "void", hp: 400000, pact: 4.0, color: "#4A235A",
// -- Utility element --
80: {
name: 'Vinculum Arcana', element: 'transference', hp: hp(80), pact: 3.25, color: '#1ABC9C',
armor: 0.20,
boons: [
{ type: 'maxMana', value: 150, desc: '+150 max mana' },
{ type: 'manaRegen', value: 1.0, desc: '+1.0 mana regen' },
],
pactCost: 35000, pactTime: 16,
uniquePerk: 'Transference spells have 25% reduced cost',
power: 3500,
effects: [{ type: 'cost_reduction', value: 0.25 }],
signingCost: { mana: 35000, time: 16 },
unlocksMana: ['transference'],
damageMultiplier: 1.85, insightMultiplier: 1.55,
},
// -- Compound Elements (Floors 90110) ───────────────────────────────────────
90: {
name: '', element: 'metal', hp: hp(90), pact: 3.5, color: '#BDC3C7',
armor: 0.30,
boons: [
{ type: 'elementalDamage', value: 15, desc: '+15% Void damage' },
{ type: 'maxMana', value: 200, desc: '+200 max mana' },
{ type: 'manaRegen', value: 1, desc: '+1 mana regen' },
{ type: 'elementalDamage', value: 15, desc: '+15% Metal damage' },
{ type: 'maxMana', value: 150, desc: '+150 max mana' },
],
pactCost: 75000,
pactTime: 20,
uniquePerk: "Void spells ignore 30% of enemy resistance",
power: 4000,
effects: [{ type: 'void_resist', value: 0.3 }],
signingCost: { mana: 75000, time: 20 },
unlocksMana: ['void', 'stellar'],
damageMultiplier: 2.0,
insightMultiplier: 1.7,
pactCost: 60000, pactTime: 18,
uniquePerk: 'Metal spells pierce 20% armor',
power: 6000,
effects: [{ type: 'armor_pierce', value: 0.2 }],
signingCost: { mana: 60000, time: 18 },
unlocksMana: ['metal'],
damageMultiplier: 1.9, insightMultiplier: 1.6,
},
100: {
name: "The Awakened One", element: "stellar", hp: 1000000, pact: 5.0, color: "#F0E68C",
name: '', element: 'sand', hp: hp(100), pact: 3.75, color: '#D4AC0D',
armor: 0.25,
boons: [
{ type: 'elementalDamage', value: 15, desc: '+15% Sand damage' },
{ type: 'manaRegen', value: 1.5, desc: '+1.5 mana regen' },
],
pactCost: 80000, pactTime: 20,
uniquePerk: 'Sand spells slow enemies by 25%',
power: 8000,
effects: [{ type: 'slow', value: 0.25 }],
signingCost: { mana: 80000, time: 20 },
unlocksMana: ['sand'],
damageMultiplier: 2.0, insightMultiplier: 1.7,
},
110: {
name: '', element: 'lightning', hp: hp(110), pact: 4.0, color: '#FFEB3B',
armor: 0.22,
boons: [
{ type: 'elementalDamage', value: 15, desc: '+15% Lightning damage' },
{ type: 'castingSpeed', value: 15, desc: '+15% casting speed' },
],
pactCost: 100000, pactTime: 22,
uniquePerk: 'Lightning spells chain to 2 additional targets',
power: 10000,
effects: [{ type: 'chain', value: 2 }],
signingCost: { mana: 100000, time: 22 },
unlocksMana: ['lightning'],
damageMultiplier: 2.1, insightMultiplier: 1.8,
},
// -- Exotic Elements (Floors 120140) ────────────────────────────────────────
120: {
name: '', element: 'crystal', hp: hp(120), pact: 4.5, color: '#85C1E9',
armor: 0.35,
boons: [
{ type: 'elementalDamage', value: 20, desc: '+20% Stellar damage' },
{ type: 'maxMana', value: 500, desc: '+500 max mana' },
{ type: 'elementalDamage', value: 20, desc: '+20% Crystal damage' },
{ type: 'maxMana', value: 300, desc: '+300 max mana' },
{ type: 'manaRegen', value: 2, desc: '+2 mana regen' },
{ type: 'insightGain', value: 25, desc: '+25% insight gain' },
],
pactCost: 150000,
pactTime: 24,
uniquePerk: "All spells deal +50% damage and cast 25% faster",
power: 10000,
effects: [{ type: 'all_damage', value: 0.5 }],
signingCost: { mana: 150000, time: 24 },
pactCost: 150000, pactTime: 26,
uniquePerk: 'Crystal spells reflect 15% damage back to attackers',
power: 15000,
effects: [{ type: 'reflect', value: 0.15 }],
signingCost: { mana: 150000, time: 26 },
unlocksMana: ['crystal'],
damageMultiplier: 2.3, insightMultiplier: 1.9,
},
130: {
name: '', element: 'stellar', hp: hp(130), pact: 5.0, color: '#F0E68C',
armor: 0.30,
boons: [
{ type: 'elementalDamage', value: 25, desc: '+25% Stellar damage' },
{ type: 'insightGain', value: 20, desc: '+20% insight gain' },
],
pactCost: 200000, pactTime: 30,
uniquePerk: 'Stellar spells deal +30% damage at night',
power: 20000,
effects: [{ type: 'night_bonus', value: 0.3 }],
signingCost: { mana: 200000, time: 30 },
unlocksMana: ['stellar'],
damageMultiplier: 2.5,
insightMultiplier: 2.0,
damageMultiplier: 2.5, insightMultiplier: 2.0,
},
140: {
name: '', element: 'void', hp: hp(140), pact: 5.5, color: '#4A235A',
armor: 0.35,
boons: [
{ type: 'elementalDamage', value: 25, desc: '+25% Void damage' },
{ type: 'rawDamage', value: 15, desc: '+15% raw damage' },
{ type: 'maxMana', value: 400, desc: '+400 max mana' },
],
pactCost: 300000, pactTime: 34,
uniquePerk: 'Void spells ignore 40% of all resistances',
power: 30000,
effects: [{ type: 'resist_ignore', value: 0.4 }],
signingCost: { mana: 300000, time: 34 },
unlocksMana: ['void'],
damageMultiplier: 2.8, insightMultiplier: 2.2,
},
};
export { BASE_GUARDIANS };