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
@@ -28,24 +28,42 @@ describe('Tab barrel export', () => {
// ─── Test: Guardian data ───────────────────────────────────────────────────────
describe('Guardian data', () => {
it('has 9 static guardians plus extended guardians', async () => {
it('has 14 static guardians plus combo guardians', async () => {
const { getAllGuardianFloors } = await import('@/lib/game/data/guardian-encounters');
const floors = getAllGuardianFloors();
// 9 static + compound (110) + exotic (120,130,140) + combo (150-240) = 23 total
expect(floors.length).toBeGreaterThanOrEqual(9);
// 14 static (10-140) + 10 combo (150-240) = 24 total
expect(floors.length).toBe(24);
});
it('guardians are at expected base floors', async () => {
it('guardians are at expected floors for all tiers', async () => {
const { getGuardianForFloor } = await import('@/lib/game/data/guardian-encounters');
const expectedFloors = [10, 20, 30, 40, 50, 60, 80, 90, 100];
for (const floor of expectedFloors) {
// Base: 10-70, Utility: 80, Compound: 90-110, Exotic: 120-140
for (const floor of [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140]) {
expect(getGuardianForFloor(floor)).not.toBeNull();
}
});
it('all base guardians have required fields', async () => {
it('follows elemental → compound → exotic progression', async () => {
const { getGuardianForFloor } = await import('@/lib/game/data/guardian-encounters');
for (const floor of [10, 20, 30, 40, 50, 60, 80, 90, 100]) {
expect(getGuardianForFloor(10)!.element).toBe('fire');
expect(getGuardianForFloor(20)!.element).toBe('water');
expect(getGuardianForFloor(30)!.element).toBe('air');
expect(getGuardianForFloor(40)!.element).toBe('earth');
expect(getGuardianForFloor(50)!.element).toBe('light');
expect(getGuardianForFloor(60)!.element).toBe('dark');
expect(getGuardianForFloor(70)!.element).toBe('death');
expect(getGuardianForFloor(80)!.element).toBe('transference');
expect(getGuardianForFloor(90)!.element).toBe('metal');
expect(getGuardianForFloor(100)!.element).toBe('sand');
expect(getGuardianForFloor(110)!.element).toBe('lightning');
expect(getGuardianForFloor(120)!.element).toBe('crystal');
expect(getGuardianForFloor(130)!.element).toBe('stellar');
expect(getGuardianForFloor(140)!.element).toBe('void');
});
it('all static guardians have required fields', async () => {
const { getGuardianForFloor } = await import('@/lib/game/data/guardian-encounters');
for (const floor of [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140]) {
const def = getGuardianForFloor(floor)!;
expect(def.name).toBeTruthy();
expect(def.element).toBeTruthy();
@@ -56,9 +74,10 @@ describe('Guardian data', () => {
}
});
it('all base guardians have unique elements', async () => {
it('all static guardians have unique elements', async () => {
const { getGuardianForFloor } = await import('@/lib/game/data/guardian-encounters');
const elements = [10, 20, 30, 40, 50, 60, 80, 90, 100].map((f) => getGuardianForFloor(f)!.element);
const floors = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140];
const elements = floors.map((f) => getGuardianForFloor(f)!.element);
const uniqueElements = new Set(elements);
expect(uniqueElements.size).toBe(elements.length);
});