fix: Golemancy enchantment capacity, design persistence, and UI selectors
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m19s

- Fix enchantment capacity formula: multiply magicAffinity by 100 (spec treats it as percentage)
- Fix enterSpireMode preserving golemDesigns (only reset loadout/activeGolems per spec §9)
- Add mana type selector UI for Intermediate/Advanced/Guardian cores
- Add spell selector UI for circuits with spell slots

Fixes #310, #311, #312
This commit is contained in:
2026-06-08 10:30:59 +02:00
parent 1e99a57496
commit 411c355a15
8 changed files with 163 additions and 20 deletions
@@ -136,7 +136,7 @@ describe('Computed stats', () => {
expect(stats.magicAffinity).toBe(0.3);
expect(stats.aoeTargets).toBe(1);
expect(stats.spellSlots).toBe(0);
expect(stats.enchantmentCapacity).toBeCloseTo(0.3);
expect(stats.enchantmentCapacity).toBeCloseTo(30); // Earth Frame 30% × Basic Core 1.0
expect(stats.specialEffect).toBe('none');
expect(stats.availableManaTypes).toEqual(['earth']);
});
@@ -153,7 +153,7 @@ describe('Computed stats', () => {
expect(stats.armorPierce).toBe(0.5);
expect(stats.magicAffinity).toBe(0.5);
expect(stats.spellSlots).toBe(2);
expect(stats.enchantmentCapacity).toBeCloseTo(1.0);
expect(stats.enchantmentCapacity).toBeCloseTo(100); // Steel Frame 50% × Advanced Core 2.0
});
it('guardian crystalSteelHybrid golem with guardian circuit', () => {
@@ -168,7 +168,7 @@ describe('Computed stats', () => {
expect(stats.armorPierce).toBe(0.7);
expect(stats.magicAffinity).toBe(1.0);
expect(stats.spellSlots).toBe(4);
expect(stats.enchantmentCapacity).toBeCloseTo(3.0);
expect(stats.enchantmentCapacity).toBeCloseTo(300); // Crystal-Steel Hybrid 100% × Guardian Core 3.0
expect(stats.specialEffect).toBe('guardianConstruct');
});
+3 -2
View File
@@ -90,8 +90,9 @@ export function computeGolemStats(design: GolemDesign): ComputedGolemStats {
},
];
// Enchantment capacity = Frame.MagicAffinity × Core.TierMultiplier
const enchantmentCapacity = frame.magicAffinity * core.tierMultiplier;
// Enchantment capacity = Frame.MagicAffinity(%) × Core.TierMultiplier
// magicAffinity is stored as decimal (0.3 = 30%) per spec §5.1, so multiply by 100
const enchantmentCapacity = Math.round(frame.magicAffinity * 100) * core.tierMultiplier;
return {
maxRoomDuration: core.maxRoomDuration,
@@ -253,7 +253,7 @@ export function createEnterSpireMode(get: GetFn, set: SetFn) {
roomResetState: {},
descentPeak: null,
isDescentComplete: false,
golemancy: { activeGolems: [], lastSummonFloor: 0, golemDesigns: {}, golemLoadout: [] },
golemancy: { activeGolems: [], lastSummonFloor: 0, golemDesigns: s.golemancy?.golemDesigns ?? {}, golemLoadout: [] },
});
get().addActivityLog('floor_transition',