fix: resolve priority 4 issues — discipline mutation, skill→discipline migration, uiStore persistence, game loop interval, toast listener leak, page re-renders
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m21s

- Issue 70: Fix discipline-slice.ts nested element mutation (use immutable spread)
- Issue 71: Add persist middleware to uiStore for paused/gameOver/victory
- Issue 72: Wire discipline effects into calcDamage (spell-casting, void-manipulation)
- Issue 73: Fix useGameLoop interval recreation (use getState() + empty deps)
- Issue 74: Fix use-toast.ts listener leak (change [state] dep to [])
- Issue 75: Reduce page.tsx re-renders with useShallow for multi-field subscriptions
- Issue 76: Fix createGatherMana hardcoded click mana (use computeClickMana with discipline effects)
- Issue 77: Pass discipline effects to computeMaxMana/computeRegen/calcInsight in tick()
- Export DisciplineBonuses type and useDisciplineStore from barrel exports
- Update tests to match new function signatures
This commit is contained in:
2026-05-19 13:53:33 +02:00
parent ebcaab62bf
commit 50a9a62060
17 changed files with 215 additions and 154 deletions
+26 -17
View File
@@ -5,7 +5,9 @@ import { usePrestigeStore } from './prestigeStore';
import { useCombatStore } from './combatStore';
import { useUIStore } from './uiStore';
import { useCraftingStore } from './craftingStore';
import { useDisciplineStore } from './discipline-slice';
import { getUnifiedEffects } from '../effects';
import { computeDisciplineEffects } from '../effects/discipline-effects';
import {
computeMaxMana,
computeRegen,
@@ -16,12 +18,10 @@ import {
import { TICK_MS } from '../constants';
export function useGameLoop() {
const tick = useGameStore((s) => s.tick);
useEffect(() => {
const interval = setInterval(tick, TICK_MS);
const interval = setInterval(() => useGameStore.getState().tick(), TICK_MS);
return () => clearInterval(interval);
}, [tick]);
}, []);
}
// ─── Shared Selector Hooks for Common Derived State ────────────────────────────
@@ -32,13 +32,18 @@ export function useGameLoop() {
export function useUnifiedEffects() {
const equippedInstances = useCraftingStore((s) => s.equippedInstances);
const equipmentInstances = useCraftingStore((s) => s.equipmentInstances);
const disciplineStoreState = useDisciplineStore();
const disciplineEffects = computeDisciplineEffects(disciplineStoreState as any);
return getUnifiedEffects({
skillUpgrades: {},
skillTiers: {},
equippedInstances,
equipmentInstances,
});
return {
...getUnifiedEffects({
skillUpgrades: {},
skillTiers: {},
equippedInstances,
equipmentInstances,
}),
disciplineEffects,
};
}
/**
@@ -51,6 +56,8 @@ export function useManaStats() {
const hour = useGameStore((s) => s.hour);
const equippedInstances = useCraftingStore((s) => s.equippedInstances);
const equipmentInstances = useCraftingStore((s) => s.equipmentInstances);
const disciplineStoreState = useDisciplineStore();
const disciplineEffects = computeDisciplineEffects(disciplineStoreState as any);
const upgradeEffects = getUnifiedEffects({
skillUpgrades: {},
@@ -61,29 +68,31 @@ export function useManaStats() {
const maxMana = computeMaxMana(
{ skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {} },
upgradeEffects
upgradeEffects as any,
disciplineEffects,
);
const baseRegen = computeRegen(
{ skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {} },
upgradeEffects
{ skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {}, attunements: {} },
upgradeEffects as any,
disciplineEffects,
);
const clickMana = computeClickMana({
skills: {},
});
}, disciplineEffects);
const meditationMultiplier = getMeditationBonus(meditateTicks, {}, upgradeEffects.meditationEfficiency);
const meditationMultiplier = getMeditationBonus(meditateTicks, {}, (upgradeEffects as any).meditationEfficiency);
const incursionStrength = getIncursionStrength(day, hour);
const effectiveRegenWithSpecials = baseRegen * (1 - incursionStrength);
// Mana Cascade bonus
const manaCascadeBonus = upgradeEffects.specials.has('mana_cascade')
const manaCascadeBonus = (upgradeEffects as any).specials.has('mana_cascade')
? Math.floor(maxMana /100) * 0.1
: 0;
// Mana Waterfall bonus
const manaWaterfallBonus = upgradeEffects.specials.has('mana_waterfall')
const manaWaterfallBonus = (upgradeEffects as any).specials.has('mana_waterfall')
? Math.floor(maxMana /100) * 0.25
: 0;