feat(golemancy): Phase 1 - Component-based construction system data definitions
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m18s

- Add new golem component types (Core, Frame, MindCircuit, Enchantment)
- Create 4 Core tiers, 7 Frames, 4 Mind Circuits, 8 Enchantments
- Rewrite golem utils for component-based stat computation
- Update GolemancyState with new fields (golemDesigns, golemLoadout, activeGolems)
- Update combat store, actions, and pipelines for new golem system
- Rewrite GolemancyTab with component selection UI
- Update fabricator discipline perks for new system
- Add comprehensive tests for component registries and utilities
- All files under 400 lines, all 743 tests passing
This commit is contained in:
2026-06-06 16:50:26 +02:00
parent c40e4ee940
commit 4b7aa82953
43 changed files with 2763 additions and 944 deletions
+20 -19
View File
@@ -4,7 +4,7 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { createSafeStorage } from '../utils/safe-persist';
import type { GameAction, SpellState, FloorState, GolemancyState, ActivityLogEntry, AchievementState, EquipmentSpellState, ActivityEventType, ActiveGolem, EnemyState, EquipmentInstance } from '../types';
import type { GameAction, SpellState, FloorState, GolemancyState, ActivityLogEntry, AchievementState, EquipmentSpellState, ActivityEventType, ActiveGolem, RuntimeActiveGolem, EnemyState, EquipmentInstance } from '../types';
import { getFloorMaxHP } from '../utils';
import { generateSpireFloorState, getRoomsForFloor } from '../utils/spire-utils';
import { addActivityLogEntry } from '../utils/activity-log';
@@ -17,6 +17,9 @@ import {
import {
onEnterLibraryRoom, tickNonCombatRoom, skipNonCombatRoom, stayLongerInRoom,
} from './non-combat-room-actions';
import {
addGolemDesign, removeGolemDesign, toggleGolemLoadoutEntry,
} from './golemancy-actions';
export const useCombatStore = create<CombatStore>()(
persist(
@@ -50,12 +53,17 @@ export const useCombatStore = create<CombatStore>()(
clearedRooms: {},
isDescentComplete: false,
// Golemancy
// Golemancy (component-based)
golemancy: {
// New component-based fields
golemDesigns: {},
golemLoadout: [],
activeGolems: [] as RuntimeActiveGolem[],
lastSummonFloor: 0,
// Legacy fields (deprecated)
enabledGolems: [],
summonedGolems: [],
activeGolems: [],
lastSummonFloor: 0,
legacyActiveGolems: [],
},
// Equipment spell states
@@ -196,24 +204,15 @@ export const useCombatStore = create<CombatStore>()(
currentRoomIndex: 0,
roomsPerFloor: 1,
maxFloorReached: Math.max(s.maxFloorReached, 1),
golemancy: { ...s.golemancy, activeGolems: [], summonedGolems: [] },
golemancy: { ...s.golemancy, activeGolems: [] as RuntimeActiveGolem[], summonedGolems: [], legacyActiveGolems: [] },
};
});
},
startClimbUp: () => set({ climbDirection: 'up', currentAction: 'climb' }),
startClimbDown: () => set({ climbDirection: 'down', currentAction: 'climb' }),
startPracticing: () => set((s) => {
if (s.currentAction !== 'meditate') return s;
return { currentAction: 'practicing' };
}),
stopPracticing: () => set((s) => {
if (s.currentAction !== 'practicing') return s;
return { currentAction: 'meditate' };
}),
startPracticing: () => set((s) => s.currentAction !== 'meditate' ? s : { currentAction: 'practicing' }),
stopPracticing: () => set((s) => s.currentAction !== 'practicing' ? s : { currentAction: 'meditate' }),
// ─── Spec: Descent actions (delegated to combat-descent-actions.ts) ────
enterDescentMode: () => enterDescentMode(get, set),
@@ -246,6 +245,10 @@ export const useCombatStore = create<CombatStore>()(
}));
},
addGolemDesign: (d) => addGolemDesign(set, d),
removeGolemDesign: (id) => removeGolemDesign(set, id),
toggleGolemLoadoutEntry: (id) => toggleGolemLoadoutEntry(set, id),
enterSpireMode: createEnterSpireMode(get, set),
learnSpell: (spellId: string) => {
@@ -310,7 +313,7 @@ export const useCombatStore = create<CombatStore>()(
onFloorCleared: (floor: number, wasGuardian: boolean) => void,
onDamageDealt: (damage: number) => { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> },
signedPacts: number[],
golemancyState: { activeGolems: ActiveGolem[] },
golemancyState: { activeGolems: RuntimeActiveGolem[] },
golemApplyDamageToRoom: (dmg: number) => { floorHP: number; floorMaxHP: number; roomCleared: boolean },
applyEnemyDefenses: (
dmg: number,
@@ -390,6 +393,4 @@ export const useCombatStore = create<CombatStore>()(
)
);
// makeInitialSpells is now in combat-actions.ts
// Re-export for backward compatibility
export { makeInitialSpells } from './combat-actions';