cleanup: delete computed-stats.ts shim and store/index.ts
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 57s

- Delete src/lib/game/computed-stats.ts (root-level re-export shim)
- Delete src/lib/game/store/index.ts (nothing imports from it)
- Update __tests__/computed-stats.test.ts to import from ../utils instead
- Clean up craftingStore.ts imports (remove unused useGameStore, CraftingApply)

Typecheck and lint pass (pre-existing DisciplinesTab.tsx errors unchanged)
This commit is contained in:
2026-05-18 12:08:38 +02:00
parent 20c2ebd7b5
commit 2805f75f5e
54 changed files with 333 additions and 2936 deletions
+7 -9
View File
@@ -10,7 +10,6 @@ import { usePrestigeStore } from './prestigeStore';
export function processCombatTick(
get: () => CombatState,
set: (state: Partial<CombatState>) => void,
skills: Record<string, number>,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
maxMana: number,
@@ -36,9 +35,8 @@ export function processCombatTick(
return { rawMana, elements, logMessages, totalManaGathered };
}
// Calculate cast speed
const baseAttackSpeed = 1 + (skills.quickCast || 0) * 0.05;
const totalAttackSpeed = baseAttackSpeed * attackSpeedMult;
// Calculate cast speed (no skill bonus)
const totalAttackSpeed = attackSpeedMult;
const spellCastSpeed = spellDef.castSpeed || 1;
const progressPerTick = HOURS_PER_TICK * spellCastSpeed * totalAttackSpeed;
@@ -58,12 +56,12 @@ export function processCombatTick(
// Calculate base damage
const floorElement = getFloorElement(currentFloor);
const damage = calcDamage(
{ skills, signedPacts: usePrestigeStore.getState().signedPacts },
{ skills: {}, signedPacts: usePrestigeStore.getState().signedPacts },
spellId,
floorElement,
);
// Let gameStore apply damage modifiers (executioner, berserker, spell echo)
// Let gameStore apply damage modifiers (executioner, berserker)
const result = onDamageDealt(damage);
rawMana = result.rawMana;
elements = result.elements;
@@ -114,7 +112,7 @@ export function processCombatTick(
// Calculate damage
const eFloorElement = getFloorElement(currentFloor);
const eDamage = calcDamage(
{ skills, signedPacts: usePrestigeStore.getState().signedPacts },
{ skills: {}, signedPacts: usePrestigeStore.getState().signedPacts },
eSpell.spellId,
eFloorElement,
);
@@ -151,11 +149,11 @@ export function makeInitialSpells(spellsToKeep: string[] = []): Record<string, S
const startSpells: Record<string, SpellState> = {
manaBolt: { learned: true, level: 1, studyProgress: 0 },
};
// Add kept spells
for (const spellId of spellsToKeep) {
startSpells[spellId] = { learned: true, level: 1, studyProgress: 0 };
}
return startSpells;
}
+68 -71
View File
@@ -17,60 +17,60 @@ export interface CombatState {
floorHP: number;
floorMaxHP: number;
maxFloorReached: number;
// Action state
activeSpell: string;
currentAction: GameAction;
castProgress: number;
// Spire mode
spireMode: boolean;
// Room system for special floors
currentRoom: FloorState;
// Spire climbing state
clearedFloors: Record<number, boolean>;
climbDirection: 'up' | 'down' | null;
isDescending: boolean;
// Golemancy (summoned golems)
golemancy: GolemancyState;
// Equipment spell states for multi-casting
equipmentSpellStates: EquipmentSpellState[];
// Combat special effect tracking
comboHitCount: number;
floorHitCount: number;
// Spells
spells: Record<string, SpellState>;
// Activity Log (for Spire Mode UI)
activityLog: ActivityLogEntry[];
// Achievements
achievements: AchievementState;
// Stats tracking
totalSpellsCast: number;
totalDamageDealt: number;
totalCraftsCompleted: number;
// Actions
setCurrentFloor: (floor: number) => void;
advanceFloor: () => void;
setFloorHP: (hp: number) => void;
setMaxFloorReached: (floor: number) => void;
setAction: (action: GameAction) => void;
setSpell: (spellId: string) => void;
setCastProgress: (progress: number) => void;
// Room state
setCurrentRoom: (room: FloorState) => void;
// Spire climbing
setClimbDirection: (direction: 'up' | 'down' | null) => void;
setClearedFloor: (floor: number, cleared: boolean) => void;
@@ -79,29 +79,28 @@ export interface CombatState {
exitSpireMode: () => void;
startClimbUp: () => void;
startClimbDown: () => void;
// Golemancy
toggleGolem: (golemId: string) => void;
setEnabledGolems: (golemIds: string[]) => void;
// Spells
learnSpell: (spellId: string) => void;
setSpellState: (spellId: string, state: Partial<SpellState>) => void;
// Activity Log
addActivityLog: (eventType: ActivityEventType, message: string, details?: ActivityLogEntry['details']) => void;
// Stats
incrementSpellsCast: () => void;
addDamageDealt: (damage: number) => void;
incrementCraftsCompleted: () => void;
// Spire mode
enterSpireMode: () => void;
// Combat tick
processCombatTick: (
skills: Record<string, number>,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
maxMana: number,
@@ -109,10 +108,10 @@ export interface CombatState {
onFloorCleared: (floor: number, wasGuardian: boolean) => void,
onDamageDealt: (damage: number) => { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> },
) => { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }>; logMessages: string[]; totalManaGathered: number };
// Reset
resetCombat: (startFloor: number, spellsToKeep?: string[]) => void;
// Debug helpers
debugSetFloor: (floor: number) => void;
resetFloorHP: () => void;
@@ -130,48 +129,48 @@ export const useCombatStore = create<CombatState>()(
currentAction: 'meditate',
castProgress: 0,
spireMode: false,
// Room system
currentRoom: generateFloorState(1),
// Spire climbing state
clearedFloors: {},
climbDirection: null,
isDescending: false,
// Golemancy
golemancy: {
enabledGolems: [],
summonedGolems: [],
lastSummonFloor: 0,
},
// Equipment spell states
equipmentSpellStates: [],
// Combat tracking
comboHitCount: 0,
floorHitCount: 0,
// Spells
spells: {
manaBolt: { learned: true, level: 1, studyProgress: 0 },
},
// Activity Log
activityLog: [],
// Achievements
achievements: {
unlocked: [],
progress: {},
},
// Stats tracking
totalSpellsCast: 0,
totalDamageDealt: 0,
totalCraftsCompleted: 0,
setCurrentFloor: (floor: number) => {
set({
currentFloor: floor,
@@ -179,7 +178,7 @@ export const useCombatStore = create<CombatState>()(
floorMaxHP: getFloorMaxHP(floor),
});
},
advanceFloor: () => {
set((state) => {
const newFloor = Math.min(state.currentFloor + 1, 100);
@@ -192,52 +191,52 @@ export const useCombatStore = create<CombatState>()(
};
});
},
setFloorHP: (hp: number) => {
set({ floorHP: Math.max(0, hp) });
},
setMaxFloorReached: (floor: number) => {
set((state) => ({
maxFloorReached: Math.max(state.maxFloorReached, floor),
}));
},
setAction: (action: GameAction) => {
set({ currentAction: action });
},
setSpell: (spellId: string) => {
const state = get();
if (state.spells[spellId]?.learned) {
set({ activeSpell: spellId });
}
},
setCastProgress: (progress: number) => {
set({ castProgress: progress });
},
// Room state
setCurrentRoom: (room: FloorState) => {
set({ currentRoom: room });
},
// Spire climbing
setClimbDirection: (direction: 'up' | 'down' | null) => {
set({ climbDirection: direction });
},
setClearedFloor: (floor: number, cleared: boolean) => {
set((state) => ({
clearedFloors: { ...state.clearedFloors, [floor]: cleared },
}));
},
setIsDescending: (descending: boolean) => {
set({ isDescending: descending });
},
climbDownFloor: () => {
set((s) => {
if (s.currentFloor <= 1) return s;
@@ -251,41 +250,41 @@ export const useCombatStore = create<CombatState>()(
};
});
},
exitSpireMode: () => {
set({ spireMode: false, currentAction: 'meditate', climbDirection: null, isDescending: false });
},
startClimbUp: () => set({ climbDirection: 'up', currentAction: 'climb' }),
startClimbDown: () => set({ climbDirection: 'down', currentAction: 'climb' }),
// Golemancy
toggleGolem: (golemId: string) => {
set((s) => {
const enabledGolems = s.golemancy?.enabledGolems || [];
const isEnabled = enabledGolems.includes(golemId);
return {
golemancy: {
...s.golemancy,
enabledGolems: isEnabled
? enabledGolems.filter(id => id !== golemId)
: [...enabledGolems, golemId]
golemancy: {
...s.golemancy,
enabledGolems: isEnabled
? enabledGolems.filter(id => id !== golemId)
: [...enabledGolems, golemId]
},
};
});
},
setEnabledGolems: (golemIds: string[]) => {
set((s) => ({
golemancy: { ...s.golemancy, enabledGolems: golemIds },
}));
},
enterSpireMode: () => {
set({ spireMode: true });
},
learnSpell: (spellId: string) => {
set((state) => ({
spells: {
@@ -294,7 +293,7 @@ export const useCombatStore = create<CombatState>()(
},
}));
},
setSpellState: (spellId: string, spellState: Partial<SpellState>) => {
set((state) => ({
spells: {
@@ -303,29 +302,28 @@ export const useCombatStore = create<CombatState>()(
},
}));
},
// Activity Log
addActivityLog: (eventType: ActivityEventType, message: string, details?: ActivityLogEntry['details']) => {
set((state) => ({
activityLog: addActivityLogEntry(state, eventType, message, details),
}));
},
// Stats
incrementSpellsCast: () => {
set((state) => ({ totalSpellsCast: state.totalSpellsCast + 1 }));
},
addDamageDealt: (damage: number) => {
set((state) => ({ totalDamageDealt: state.totalDamageDealt + damage }));
},
incrementCraftsCompleted: () => {
set((state) => ({ totalCraftsCompleted: state.totalCraftsCompleted + 1 }));
},
processCombatTick: (
skills: Record<string, number>,
rawMana: number,
elements: Record<string, { current: number; max: number; unlocked: boolean }>,
maxMana: number,
@@ -336,7 +334,6 @@ export const useCombatStore = create<CombatState>()(
return processCombatTick(
get,
set,
skills,
rawMana,
elements,
maxMana,
@@ -345,10 +342,10 @@ export const useCombatStore = create<CombatState>()(
onDamageDealt,
);
},
resetCombat: (startFloor: number, spellsToKeep: string[] = []) => {
const startSpells = makeInitialSpells(spellsToKeep);
set({
currentFloor: startFloor,
floorHP: getFloorMaxHP(startFloor),
@@ -360,7 +357,7 @@ export const useCombatStore = create<CombatState>()(
spells: startSpells,
});
},
// Debug helpers
debugSetFloor: (floor: number) => {
set({
@@ -369,13 +366,13 @@ export const useCombatStore = create<CombatState>()(
floorMaxHP: getFloorMaxHP(floor),
});
},
resetFloorHP: () => {
set((state) => ({
floorHP: state.floorMaxHP,
}));
},
debugSetTime: (day: number, hour: number) => {
useGameStore.setState({ day, hour });
},
@@ -386,7 +383,7 @@ export const useCombatStore = create<CombatState>()(
currentFloor: state.currentFloor,
maxFloorReached: state.maxFloorReached,
spells: state.spells,
activeSpell: state.activeSpell,
activeSpell: state.activeAction,
}),
}
)
+3 -35
View File
@@ -1,28 +1,14 @@
// ─── Crafting Store ─────────────────────────────────────────────────────
// Handles equipment crafting, enchantment design, and crafting progress
// This is a modular store that manages all crafting-related state
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { DesignProgress, PreparationProgress, ApplicationProgress, EquipmentCraftingProgress, EnchantmentDesign, EquipmentInstance, DesignEffect } from '../types';
// Import crafting modules for action logic
import * as CraftingUtils from '../crafting-utils';
import * as CraftingDesign from '../crafting-design';
import { computeEffects } from '../upgrade-effects';
import { hasSpecial, SPECIAL_EFFECTS } from '../special-effects';
// Import other stores to access required state
import { useSkillStore } from './skillStore';
import { useGameStore } from './gameStore';
import { useManaStore } from './manaStore';
import { useCombatStore } from './combatStore';
import { createStartingEquipment } from '../store/crafting-modules/starting-equipment';
import { createStartingEquipment } from '../crafting-slice';
import { useUIStore } from './uiStore';
// Import action modules
import * as ApplicationActions from '../crafting-actions/application-actions';
import * as CraftingApply from '../crafting-apply';
import * as PreparationActions from '../crafting-actions/preparation-actions';
import * as CraftingEquipment from '../crafting-equipment';
@@ -142,25 +128,18 @@ export const useCraftingStore = create<CraftingStore>()(
// Enchantment design actions
startDesigningEnchantment: (name, equipmentTypeId, effects) => {
// Get state from other stores
const skillState = useSkillStore.getState();
const state = get(); // crafting state
const enchantingLevel = skillState.skills?.enchanting || 0;
const validation = CraftingDesign.validateDesignEffects(effects, equipmentTypeId, enchantingLevel);
const validation = CraftingDesign.validateDesignEffects(effects, equipmentTypeId, 0);
if (!validation.valid) return false;
const equipType = CraftingUtils.getEquipmentType(equipmentTypeId);
if (!equipType) return false;
const efficiencyBonus = (skillState.skillUpgrades?.['efficientEnchant'] || []).length * 0.05 || 0;
const totalCapacityCost = CraftingDesign.calculateDesignCapacityCost(effects, efficiencyBonus);
const totalCapacityCost = CraftingDesign.calculateDesignCapacityCost(effects, 0);
if (totalCapacityCost > equipType.baseCapacity) return false;
const computedEffects = computeEffects(skillState.skillUpgrades || {}, skillState.skillTiers || {});
const hasEnchantMastery = hasSpecial(computedEffects, SPECIAL_EFFECTS.ENCHANT_MASTERY);
let updates: Partial<CraftingState> = {};
if (!state.designProgress) {
@@ -176,17 +155,6 @@ export const useCraftingStore = create<CraftingStore>()(
};
// Update currentAction in combatStore
useCombatStore.setState({ currentAction: 'design' });
} else if (hasEnchantMastery && !state.designProgress2) {
updates = {
designProgress2: {
designId: CraftingUtils.generateDesignId(),
progress: 0,
required: CraftingDesign.calculateDesignTime(effects),
name,
equipmentType: equipmentTypeId,
effects,
},
};
} else {
return false;
}
+8 -20
View File
@@ -1,9 +1,7 @@
import { computeMaxMana } from '../utils';
import { computeEffects } from '../upgrade-effects';
import { useUIStore } from './uiStore';
import { usePrestigeStore } from './prestigeStore';
import { useManaStore } from './manaStore';
import { useSkillStore } from './skillStore';
import { useCombatStore } from './combatStore';
export const createResetGame = (set: (state: any) => void, initialState: any) => () => {
@@ -12,7 +10,6 @@ export const createResetGame = (set: (state: any) => void, initialState: any) =>
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');
localStorage.removeItem('mana-loop-crafting-storage');
@@ -24,7 +21,6 @@ export const createResetGame = (set: (state: any) => void, initialState: any) =>
useUIStore.getState().resetUI();
usePrestigeStore.getState().resetPrestige();
useManaStore.getState().resetMana({}, {}, {}, {});
useSkillStore.getState().resetSkills();
useCombatStore.getState().resetCombat(startFloor);
set({
@@ -34,28 +30,20 @@ export const createResetGame = (set: (state: any) => void, initialState: any) =>
};
export const createGatherMana = () => () => {
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;
// Base click mana (no skill bonuses)
const cm = 1;
// 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
{
skills: {},
prestigeUpgrades: prestigeState.prestigeUpgrades,
skillUpgrades: {},
skillTiers: {}
},
effects
undefined
);
useManaStore.getState().gatherMana(cm, max);
+11 -24
View File
@@ -1,7 +1,6 @@
import { useEffect } from 'react';
import { useGameStore } from './gameStore';
import { useManaStore } from './manaStore';
import { useSkillStore } from './skillStore';
import { usePrestigeStore } from './prestigeStore';
import { useCombatStore } from './combatStore';
import { useUIStore } from './uiStore';
@@ -28,17 +27,15 @@ export function useGameLoop() {
// ─── Shared Selector Hooks for Common Derived State ────────────────────────────
/**
* Get unified effects from all relevant stores
* Get unified effects from equipment only (skills removed)
*/
export function useUnifiedEffects() {
const skillUpgrades = useSkillStore((s) => s.skillUpgrades);
const skillTiers = useSkillStore((s) => s.skillTiers);
const equippedInstances = useCraftingStore((s) => s.equippedInstances);
const equipmentInstances = useCraftingStore((s) => s.equipmentInstances);
return getUnifiedEffects({
skillUpgrades,
skillTiers,
skillUpgrades: {},
skillTiers: {},
equippedInstances,
equipmentInstances,
});
@@ -48,10 +45,7 @@ export function useUnifiedEffects() {
* Get computed mana stats (maxMana, baseRegen, clickMana, meditationMultiplier, effectiveRegen)
*/
export function useManaStats() {
const skills = useSkillStore((s) => s.skills);
const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
const skillUpgrades = useSkillStore((s) => s.skillUpgrades);
const skillTiers = useSkillStore((s) => s.skillTiers);
const meditateTicks = useManaStore((s) => s.meditateTicks);
const day = useGameStore((s) => s.day);
const hour = useGameStore((s) => s.hour);
@@ -59,30 +53,27 @@ export function useManaStats() {
const equipmentInstances = useCraftingStore((s) => s.equipmentInstances);
const upgradeEffects = getUnifiedEffects({
skillUpgrades,
skillTiers,
skillUpgrades: {},
skillTiers: {},
equippedInstances,
equipmentInstances,
});
const maxMana = computeMaxMana(
{ skills, prestigeUpgrades, skillUpgrades, skillTiers },
{ skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {} },
upgradeEffects
);
const baseRegen = computeRegen(
{ skills, prestigeUpgrades, skillUpgrades, skillTiers },
{ skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {} },
upgradeEffects
);
const clickMana = computeClickMana({
skills,
prestigeUpgrades,
skillUpgrades,
skillTiers,
skills: {},
});
const meditationMultiplier = getMeditationBonus(meditateTicks, skills, upgradeEffects.meditationEfficiency);
const meditationMultiplier = getMeditationBonus(meditateTicks, {}, upgradeEffects.meditationEfficiency);
const incursionStrength = getIncursionStrength(day, hour);
const effectiveRegenWithSpecials = baseRegen * (1 - incursionStrength);
@@ -115,22 +106,18 @@ export function useManaStats() {
* Get combat-related derived state
*/
export function useCombatStats() {
const skills = useSkillStore((s) => s.skills);
const signedPacts = usePrestigeStore((s) => s.signedPacts);
const equippedInstances = useCraftingStore((s) => s.equippedInstances);
const equipmentInstances = useCraftingStore((s) => s.equipmentInstances);
const skillUpgrades = useSkillStore((s) => s.skillUpgrades);
const skillTiers = useSkillStore((s) => s.skillTiers);
const upgradeEffects = getUnifiedEffects({
skillUpgrades,
skillTiers,
skillUpgrades: {},
skillTiers: {},
equippedInstances,
equipmentInstances,
});
return {
skills,
signedPacts,
equippedInstances,
equipmentInstances,
+2 -25
View File
@@ -4,21 +4,19 @@ import { SPELLS_DEF } from '../constants';
import { useUIStore } from './uiStore';
import { usePrestigeStore } from './prestigeStore';
import { useManaStore } from './manaStore';
import { useSkillStore } from './skillStore';
import { useCombatStore } from './combatStore';
export const createStartNewLoop = (set: (state: any) => void) => () => {
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,
skills: {},
});
const total = prestigeState.insight + insightGained;
@@ -26,25 +24,6 @@ export const createStartNewLoop = (set: (state: any) => void) => () => {
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,
@@ -61,9 +40,7 @@ export const createStartNewLoop = (set: (state: any) => void) => () => {
);
usePrestigeStore.getState().incrementLoopCount();
useManaStore.getState().resetMana(pu, newSkills, newSkillUpgrades, newSkillTiers);
useSkillStore.getState().resetSkills(newSkills, newSkillUpgrades, newSkillTiers);
useManaStore.getState().resetMana(pu, {}, {}, {});
// Reset combat with starting floor and any spells from prestige upgrades
const startSpells = makeInitialSpells();
+20 -59
View File
@@ -5,7 +5,6 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import { TICK_MS, HOURS_PER_TICK, MAX_DAY, SPELLS_DEF, GUARDIANS, getStudySpeedMultiplier } from '../constants';
import { computeEffects } from '../upgrade-effects';
import { hasSpecial, SPECIAL_EFFECTS } from '../special-effects';
import {
computeMaxMana,
@@ -22,7 +21,6 @@ import {
import { useUIStore } from './uiStore';
import { usePrestigeStore } from './prestigeStore';
import { useManaStore } from './manaStore';
import { useSkillStore } from './skillStore';
import { useCombatStore, makeInitialSpells } from './combatStore';
import { useAttunementStore } from './attunementStore';
import { ATTUNEMENTS_DEF, getAttunementConversionRate } from '../data/attunements';
@@ -66,26 +64,22 @@ export const useGameStore = create<GameCoordinatorStore>()(
tick: () => {
const uiState = useUIStore.getState();
if (uiState.gameOver || uiState.paused) return;
// Helper for logging
const addLog = (msg: string) => useUIStore.getState().addLog(msg);
// Get all store states
const prestigeState = usePrestigeStore.getState();
const manaState = useManaStore.getState();
const skillState = useSkillStore.getState();
const combatState = useCombatStore.getState();
// Compute effects from upgrades
const effects = computeEffects(skillState.skillUpgrades || {}, skillState.skillTiers || {});
const maxMana = computeMaxMana(
{ skills: skillState.skills, prestigeUpgrades: prestigeState.prestigeUpgrades, skillUpgrades: skillState.skillUpgrades, skillTiers: skillState.skillTiers },
effects
{ skills: {}, prestigeUpgrades: prestigeState.prestigeUpgrades, skillUpgrades: {}, skillTiers: {} },
undefined
);
const baseRegen = computeRegen(
{ skills: skillState.skills, prestigeUpgrades: prestigeState.prestigeUpgrades, skillUpgrades: skillState.skillUpgrades, skillTiers: skillState.skillTiers },
effects
{ skills: {}, prestigeUpgrades: prestigeState.prestigeUpgrades, skillUpgrades: {}, skillTiers: {}, attunement: {} },
undefined
);
// Time progression
@@ -103,9 +97,9 @@ export const useGameStore = create<GameCoordinatorStore>()(
totalManaGathered: manaState.totalManaGathered,
signedPacts: prestigeState.signedPacts,
prestigeUpgrades: prestigeState.prestigeUpgrades,
skills: skillState.skills,
skills: {},
});
addLog(`⏰ The loop ends. Gained ${insightGained} Insight.`);
useUIStore.getState().setGameOver(true, false);
usePrestigeStore.getState().setLoopInsight(insightGained);
@@ -120,9 +114,9 @@ export const useGameStore = create<GameCoordinatorStore>()(
totalManaGathered: manaState.totalManaGathered,
signedPacts: prestigeState.signedPacts,
prestigeUpgrades: prestigeState.prestigeUpgrades,
skills: skillState.skills,
skills: {},
}) * 3;
addLog(`🏆 VICTORY! The Awakened One falls! Gained ${insightGained} Insight!`);
useUIStore.getState().setGameOver(true, true);
usePrestigeStore.getState().setLoopInsight(insightGained);
@@ -135,10 +129,10 @@ export const useGameStore = create<GameCoordinatorStore>()(
// Meditation bonus tracking and regen calculation
let meditateTicks = manaState.meditateTicks;
let meditationMultiplier = 1;
if (combatState.currentAction === 'meditate') {
meditateTicks++;
meditationMultiplier = getMeditationBonus(meditateTicks, skillState.skills, effects.meditationEfficiency);
meditationMultiplier = getMeditationBonus(meditateTicks, {}, 1);
} else {
meditateTicks = 0;
}
@@ -150,7 +144,7 @@ export const useGameStore = create<GameCoordinatorStore>()(
if (!state.active) return;
const def = ATTUNEMENTS_DEF[id];
if (!def || def.conversionRate <= 0 || !def.primaryManaType) return;
const scaledRate = getAttunementConversionRate(id, state.level || 1);
totalConversionPerTick += scaledRate * HOURS_PER_TICK;
});
@@ -167,10 +161,10 @@ export const useGameStore = create<GameCoordinatorStore>()(
if (!state.active) return;
const def = ATTUNEMENTS_DEF[id];
if (!def || def.conversionRate <= 0 || !def.primaryManaType) return;
const scaledRate = getAttunementConversionRate(id, state.level || 1);
const conversionThisTick = scaledRate * HOURS_PER_TICK; // per tick
const conversionThisTick = scaledRate * HOURS_PER_TICK;
// Add to primary mana type (cost already deducted from regen)
if (elements[def.primaryManaType]) {
elements[def.primaryManaType].current = Math.min(
@@ -181,32 +175,6 @@ export const useGameStore = create<GameCoordinatorStore>()(
});
let totalManaGathered = manaState.totalManaGathered;
// Study progress - handled by skillStore
if (combatState.currentAction === 'study' && skillState.currentStudyTarget) {
const studySpeedMult = getStudySpeedMultiplier(skillState.skills);
const progressGain = HOURS_PER_TICK * studySpeedMult;
const result = useSkillStore.getState().updateStudyProgress(progressGain);
if (result.completed && result.target) {
if (result.target.type === 'skill') {
const skillId = result.target.id;
const currentLevel = skillState.skills[skillId] || 0;
// Update skill level
useSkillStore.getState().incrementSkillLevel(skillId);
useSkillStore.getState().clearPaidStudySkill(skillId);
useCombatStore.getState().setAction('meditate');
addLog(`${skillId} Lv.${currentLevel + 1} mastered!`);
} else if (result.target.type === 'spell') {
const spellId = result.target.id;
useCombatStore.getState().learnSpell(spellId);
useSkillStore.getState().setCurrentStudyTarget(null);
useCombatStore.getState().setAction('meditate');
addLog(`📖 ${SPELLS_DEF[spellId]?.name || spellId} learned!`);
}
}
}
// Convert action - delegate to manaStore
if (combatState.currentAction === 'convert') {
const convertResult = useManaStore.getState().processConvertAction(rawMana);
@@ -238,11 +206,11 @@ export const useGameStore = create<GameCoordinatorStore>()(
// Combat - delegate to combatStore
if (combatState.currentAction === 'climb') {
const combatResult = useCombatStore.getState().processCombatTick(
skillState.skills,
{},
rawMana,
elements,
maxMana,
effects.attackSpeedMultiplier,
1,
(floor, wasGuardian) => {
if (wasGuardian) {
addLog(`⚔️ ${GUARDIANS[floor]?.name || 'Guardian'} defeated! Visit the Grimoire to sign a pact.`);
@@ -252,25 +220,18 @@ export const useGameStore = create<GameCoordinatorStore>()(
},
(damage) => {
// Apply upgrade damage multipliers and bonuses
let dmg = damage * effects.baseDamageMultiplier + effects.baseDamageBonus;
let dmg = damage;
// Executioner: +100% damage to enemies below 25% HP
if (hasSpecial(effects, SPECIAL_EFFECTS.EXECUTIONER) && combatState.floorHP / combatState.floorMaxHP < 0.25) {
if (hasSpecial({}, SPECIAL_EFFECTS.EXECUTIONER) && combatState.floorHP / combatState.floorMaxHP < 0.25) {
dmg *= 2;
}
// Berserker: +50% damage when below 50% mana
if (hasSpecial(effects, SPECIAL_EFFECTS.BERSERKER) && rawMana < maxMana * 0.5) {
if (hasSpecial({}, SPECIAL_EFFECTS.BERSERKER) && rawMana < maxMana * 0.5) {
dmg *= 1.5;
}
// Spell echo - chance to cast again
const echoChance = (skillState.skills.spellEcho || 0) * 0.1;
if (Math.random() < echoChance) {
dmg *= 2;
addLog(`✨ Spell Echo! Double damage!`);
}
return { rawMana, elements, modifiedDamage: dmg };
}
);
-3
View File
@@ -11,9 +11,6 @@ export type { PrestigeState } from './prestigeStore';
export { useManaStore, makeInitialElements } from './manaStore';
export type { ManaState } from './manaStore';
export { useSkillStore } from './skillStore';
export type { SkillState } from './skillStore';
export { useCombatStore, makeInitialSpells } from './combatStore';
export type { CombatState } from './combatStore';