cleanup: delete computed-stats.ts shim and store/index.ts
Build and Publish Mana Loop Docker Image / build-and-publish (push) Failing after 57s
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:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
);
|
||||
|
||||
@@ -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';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user