Refactor large files into modular components
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 1m9s

- Refactored page.tsx (613→252 lines) with GameOverScreen and LeftPanel extracted
- Refactored StatsTab.tsx (584→92 lines) with section components
- Refactored SkillsTab.tsx (434→54 lines) with sub-components
- Created modular structure for GameContext, LootInventory, and other components
- All extracted components organized into feature directories
This commit is contained in:
Refactoring Agent
2026-05-02 17:35:03 +02:00
parent c9ae2576f4
commit d2d28887b1
194 changed files with 16862 additions and 15729 deletions
+7 -149
View File
@@ -1,6 +1,6 @@
// ─── Game Store (Coordinator) ─────────────────────────────────────────────────
// Manages: day, hour, incursionStrength, containmentWards
// Coordinates tick function across all stores
// Coordinate tick function across all stores
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
@@ -24,6 +24,8 @@ import { usePrestigeStore } from './prestigeStore';
import { useManaStore } from './manaStore';
import { useSkillStore } from './skillStore';
import { useCombatStore, makeInitialSpells } from './combatStore';
import { createResetGame, createGatherMana } from './gameActions';
import { createStartNewLoop } from './gameLoopActions';
export interface GameCoordinatorState {
day: number;
@@ -39,6 +41,7 @@ export interface GameCoordinatorStore extends GameCoordinatorState {
togglePause: () => void;
startNewLoop: () => void;
initGame: () => void;
gatherMana: () => void;
}
const initialState: GameCoordinatorState = {
@@ -265,145 +268,12 @@ export const useGameStore = create<GameCoordinatorStore>()(
});
},
resetGame: () => {
// Clear all persisted state
localStorage.removeItem('mana-loop-ui-storage');
localStorage.removeItem('mana-loop-prestige-storage');
localStorage.removeItem('mana-loop-mana-storage');
localStorage.removeItem('mana-loop-skill-storage');
localStorage.removeItem('mana-loop-combat-storage');
localStorage.removeItem('mana-loop-game-storage');
const startFloor = 1;
useUIStore.getState().resetUI();
usePrestigeStore.getState().resetPrestige();
useManaStore.getState().resetMana({}, {}, {}, {});
useSkillStore.getState().resetSkills();
useCombatStore.getState().resetCombat(startFloor);
set({
...initialState,
initialized: true,
});
},
resetGame: createResetGame(set, initialState),
togglePause: () => {
useUIStore.getState().togglePause();
},
gatherMana: () => {
const skillState = useSkillStore.getState();
const manaState = useManaStore.getState();
const prestigeState = usePrestigeStore.getState();
// Compute click mana
let cm = 1 +
(skillState.skills.manaTap || 0) * 1 +
(skillState.skills.manaSurge || 0) * 3;
// Mana overflow bonus
const overflowBonus = 1 + (skillState.skills.manaOverflow || 0) * 0.25;
cm = Math.floor(cm * overflowBonus);
const effects = computeEffects(skillState.skillUpgrades || {}, skillState.skillTiers || {});
const max = computeMaxMana(
{ skills: skillState.skills, prestigeUpgrades: prestigeState.prestigeUpgrades, skillUpgrades: skillState.skillUpgrades, skillTiers: skillState.skillTiers },
effects
);
useManaStore.getState().gatherMana(cm, max);
},
startNewLoop: () => {
const prestigeState = usePrestigeStore.getState();
const combatState = useCombatStore.getState();
const manaState = useManaStore.getState();
const skillState = useSkillStore.getState();
const insightGained = prestigeState.loopInsight || calcInsight({
maxFloorReached: combatState.maxFloorReached,
totalManaGathered: manaState.totalManaGathered,
signedPacts: prestigeState.signedPacts,
prestigeUpgrades: prestigeState.prestigeUpgrades,
skills: skillState.skills,
});
const total = prestigeState.insight + insightGained;
// Spell preservation is only through prestige upgrade "spellMemory" (purchased with insight)
// Not through a skill - that would undermine the insight economy
const pu = prestigeState.prestigeUpgrades;
const startFloor = 1 + (pu.spireKey || 0) * 2;
// Apply saved memories - restore skill levels, tiers, and upgrades
const memories = prestigeState.memories || [];
const newSkills: Record<string, number> = {};
const newSkillTiers: Record<string, number> = {};
const newSkillUpgrades: Record<string, string[]> = {};
if (memories.length > 0) {
for (const memory of memories) {
const tieredSkillId = memory.tier > 1 ? `${memory.skillId}_t${memory.tier}` : memory.skillId;
newSkills[tieredSkillId] = memory.level;
if (memory.tier > 1) {
newSkillTiers[memory.skillId] = memory.tier;
}
newSkillUpgrades[tieredSkillId] = memory.upgrades || [];
}
}
// Reset and update all stores for new loop
useUIStore.setState({
gameOver: false,
victory: false,
paused: false,
logs: ['✨ The loop begins. You start with Mana Bolt. Gather your strength, mage.'],
});
usePrestigeStore.getState().resetPrestigeForNewLoop(
total,
pu,
prestigeState.memories,
3 + (pu.deepMemory || 0)
);
usePrestigeStore.getState().incrementLoopCount();
useManaStore.getState().resetMana(pu, newSkills, newSkillUpgrades, newSkillTiers);
useSkillStore.getState().resetSkills(newSkills, newSkillUpgrades, newSkillTiers);
// Reset combat with starting floor and any spells from prestige upgrades
const startSpells = makeInitialSpells();
if (pu.spellMemory) {
const availableSpells = Object.keys(SPELLS_DEF).filter(s => s !== 'manaBolt');
const shuffled = availableSpells.sort(() => Math.random() - 0.5);
for (let i = 0; i < Math.min(pu.spellMemory, shuffled.length); i++) {
startSpells[shuffled[i]] = { learned: true, level: 1, studyProgress: 0 };
}
}
useCombatStore.setState({
currentFloor: startFloor,
floorHP: getFloorMaxHP(startFloor),
floorMaxHP: getFloorMaxHP(startFloor),
maxFloorReached: startFloor,
activeSpell: 'manaBolt',
currentAction: 'meditate',
castProgress: 0,
spells: startSpells,
});
set({
day: 1,
hour: 0,
incursionStrength: 0,
containmentWards: 0,
});
},
startNewLoop: createStartNewLoop(set),
gatherMana: createGatherMana(),
}),
{
name: 'mana-loop-game-storage',
@@ -416,15 +286,3 @@ export const useGameStore = create<GameCoordinatorStore>()(
}
)
);
// Re-export the game loop hook for convenience
export function useGameLoop() {
const tick = useGameStore((s) => s.tick);
return {
start: () => {
const interval = setInterval(tick, TICK_MS);
return () => clearInterval(interval);
},
};
}