- {Object.entries(ELEMENTS).map(([id, def]) => {
- const elem = store.elements[id];
- const isUnlocked = elem?.unlocked;
-
+ {Object.entries(store.elements).map(([id, elem]) => {
+ const def = ELEMENTS[id];
return (
-
-
-
{def.sym}
- {!isUnlocked && (
-
- )}
+
{def?.sym}
+
{def?.name}
+
+ {elem.current}/{elem.max}
-
{def.name}
- {isUnlocked && (
-
- {elem.current.toFixed(0)}/{elem.max}
-
- )}
- {isUnlocked && (
+ {!elem.unlocked && (
+ )}
+ {elem.unlocked && (
+
)}
diff --git a/src/components/game/debug/GameStateDebug.tsx b/src/components/game/debug/GameStateDebug.tsx
index c35e692..87c3cb5 100644
--- a/src/components/game/debug/GameStateDebug.tsx
+++ b/src/components/game/debug/GameStateDebug.tsx
@@ -8,23 +8,20 @@ import { Switch } from '@/components/ui/switch';
import { Label } from '@/components/ui/label';
import {
RotateCcw, AlertTriangle, Zap, Clock, Settings, Eye,
- Plus
} from 'lucide-react';
-import type { GameStore } from '@/lib/game/store';
-import { fmt } from '@/lib/game/store';
import { useDebug } from '@/lib/game/debug-context';
+import { useGameStore } from '@/lib/game/store';
-interface GameStateDebugProps {
- store: GameStore;
-}
-
-export function GameStateDebug({ store }: GameStateDebugProps) {
+export function GameStateDebug() {
const [confirmReset, setConfirmReset] = useState(false);
const { showComponentNames, toggleComponentNames } = useDebug();
+ // Get state from store
+ const store = useGameStore((s) => s);
+
const handleReset = () => {
if (confirmReset) {
- store.resetGame();
+ useGameStore.getState().resetGame();
setConfirmReset(false);
} else {
setConfirmReset(true);
@@ -34,17 +31,19 @@ export function GameStateDebug({ store }: GameStateDebugProps) {
const handleAddMana = (amount: number) => {
// Use gatherMana multiple times to add mana
+ const state = useGameStore.getState();
for (let i = 0; i < amount; i++) {
- store.gatherMana();
+ state.gatherMana();
}
};
const handleSetTime = (day: number, hour: number) => {
- if (store.debugSetTime) {
- store.debugSetTime(day, hour);
+ const state = useGameStore.getState();
+ if (state.debugSetTime) {
+ state.debugSetTime(day, hour);
}
};
-
+
return (
{/* Warning Banner */}
@@ -127,20 +126,20 @@ export function GameStateDebug({ store }: GameStateDebugProps) {
- Current: {fmt(store.rawMana)} / {fmt(store.getMaxMana())}
+ Current: {store.rawMana} / {store.getMaxMana?.() || '?'}
@@ -149,7 +148,7 @@ export function GameStateDebug({ store }: GameStateDebugProps) {
size="sm"
className="w-full bg-blue-600 hover:bg-blue-700"
onClick={() => {
- const max = store.getMaxMana();
+ const max = store.getMaxMana?.() || 100;
const current = store.rawMana;
for (let i = 0; i < Math.floor(max - current); i++) {
store.gatherMana();
@@ -192,7 +191,7 @@ export function GameStateDebug({ store }: GameStateDebugProps) {
@@ -217,7 +216,7 @@ export function GameStateDebug({ store }: GameStateDebugProps) {
// Unlock all base elements
['fire', 'water', 'air', 'earth', 'light', 'dark', 'death'].forEach(e => {
if (!store.elements[e]?.unlocked) {
- store.unlockElement(e);
+ useGameStore.getState().unlockElement(e);
}
});
}}
@@ -228,10 +227,10 @@ export function GameStateDebug({ store }: GameStateDebugProps) {
size="sm"
variant="outline"
onClick={() => {
- // Unlock utility elements (only transference remains)
+ // Unlock utility elements
['transference'].forEach(e => {
if (!store.elements[e]?.unlocked) {
- store.unlockElement(e);
+ useGameStore.getState().unlockElement(e);
}
});
}}
@@ -244,7 +243,7 @@ export function GameStateDebug({ store }: GameStateDebugProps) {
onClick={() => {
// Max floor
if (store.debugSetFloor) {
- store.debugSetFloor(100);
+ useGameStore.getState().debugSetFloor(100);
}
}}
>
@@ -256,7 +255,7 @@ export function GameStateDebug({ store }: GameStateDebugProps) {
onClick={() => {
// Reset floor HP
if (store.resetFloorHP) {
- store.resetFloorHP();
+ useGameStore.getState().resetFloorHP();
}
}}
>
diff --git a/src/components/game/debug/GolemDebug.tsx b/src/components/game/debug/GolemDebug.tsx
index b913b54..23789c0 100644
--- a/src/components/game/debug/GolemDebug.tsx
+++ b/src/components/game/debug/GolemDebug.tsx
@@ -2,13 +2,8 @@
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Bug } from 'lucide-react';
-import type { GameStore } from '@/lib/game/store';
-interface GolemDebugProps {
- store: GameStore;
-}
-
-export function GolemDebug({ store }: GolemDebugProps) {
+export function GolemDebug() {
return (
diff --git a/src/components/game/debug/SkillDebug.tsx b/src/components/game/debug/SkillDebug.tsx
index 52277e8..5084956 100644
--- a/src/components/game/debug/SkillDebug.tsx
+++ b/src/components/game/debug/SkillDebug.tsx
@@ -4,13 +4,11 @@ import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Separator } from '@/components/ui/separator';
import { BookOpen } from 'lucide-react';
-import type { GameStore } from '@/lib/game/store';
+import { useGameStore } from '@/lib/game/store';
-interface SkillDebugProps {
- store: GameStore;
-}
-
-export function SkillDebug({ store }: SkillDebugProps) {
+export function SkillDebug() {
+ const store = useGameStore((s) => s);
+
return (
@@ -32,11 +30,9 @@ export function SkillDebug({ store }: SkillDebugProps) {
// Level up all enchanting skills by 1
const enchantSkills = ['enchanting', 'efficientEnchant', 'enchantSpeed','essenceRefining'];
enchantSkills.forEach(skillId => {
- if (store.skills[skillId] !== undefined) {
- store.skills[skillId] = Math.min((store.skills[skillId] || 0) + 1, 10);
- } else {
- store.skills[skillId] = 1;
- }
+ store.skills[skillId] = Math.min((store.skills[skillId] || 0) + 1, 10);
+ // Force update
+ useGameStore.setState({ skills: { ...store.skills } });
});
}}
>
@@ -51,6 +47,7 @@ export function SkillDebug({ store }: SkillDebugProps) {
enchantSkills.forEach(skillId => {
store.skills[skillId] = 10;
});
+ useGameStore.setState({ skills: { ...store.skills } });
}}
>
Max All Enchanting
@@ -68,12 +65,9 @@ export function SkillDebug({ store }: SkillDebugProps) {
onClick={() => {
const manaSkills = ['manaWell', 'manaFlow', 'manaOverflow', 'fireManaCap', 'waterManaCap', 'airManaCap', 'earthManaCap', 'lightManaCap', 'darkManaCap', 'deathManaCap', 'metalManaCap', 'sandManaCap', 'lightningManaCap', 'transferenceManaCap'];
manaSkills.forEach(skillId => {
- if (store.skills[skillId] !== undefined) {
- store.skills[skillId] = Math.min((store.skills[skillId] || 0) + 1, 10);
- } else {
- store.skills[skillId] = 1;
- }
+ store.skills[skillId] = Math.min((store.skills[skillId] || 0) + 1, 10);
});
+ useGameStore.setState({ skills: { ...store.skills } });
}}
>
+1 All Mana
@@ -86,6 +80,7 @@ export function SkillDebug({ store }: SkillDebugProps) {
manaSkills.forEach(skillId => {
store.skills[skillId] = 10;
});
+ useGameStore.setState({ skills: { ...store.skills } });
}}
>
Max All Mana
@@ -103,12 +98,9 @@ export function SkillDebug({ store }: SkillDebugProps) {
onClick={() => {
const studySkills = ['quickLearner', 'focusedMind', 'meditation', 'knowledgeRetention'];
studySkills.forEach(skillId => {
- if (store.skills[skillId] !== undefined) {
- store.skills[skillId] = Math.min((store.skills[skillId] || 0) + 1, 10);
- } else {
- store.skills[skillId] = 1;
- }
+ store.skills[skillId] = Math.min((store.skills[skillId] || 0) + 1, 10);
});
+ useGameStore.setState({ skills: { ...store.skills } });
}}
>
+1 All Study
@@ -121,6 +113,7 @@ export function SkillDebug({ store }: SkillDebugProps) {
studySkills.forEach(skillId => {
store.skills[skillId] = 10;
});
+ useGameStore.setState({ skills: { ...store.skills } });
}}
>
Max All Study
@@ -138,12 +131,9 @@ export function SkillDebug({ store }: SkillDebugProps) {
onClick={() => {
const craftSkills = ['effCrafting', 'fieldRepair', 'elemCrafting'];
craftSkills.forEach(skillId => {
- if (store.skills[skillId] !== undefined) {
- store.skills[skillId] = Math.min((store.skills[skillId] || 0) + 1, 10);
- } else {
- store.skills[skillId] = 1;
- }
+ store.skills[skillId] = Math.min((store.skills[skillId] || 0) + 1, 10);
});
+ useGameStore.setState({ skills: { ...store.skills } });
}}
>
+1 All Crafting
@@ -156,6 +146,7 @@ export function SkillDebug({ store }: SkillDebugProps) {
craftSkills.forEach(skillId => {
store.skills[skillId] = 10;
});
+ useGameStore.setState({ skills: { ...store.skills } });
}}
>
Max All Crafting
@@ -178,13 +169,14 @@ export function SkillDebug({ store }: SkillDebugProps) {
'researchDarkSpells', 'researchLifeDeathSpells',
'researchAdvancedFire', 'researchAdvancedWater', 'researchAdvancedAir',
'researchAdvancedEarth', 'researchAdvancedLight', 'researchAdvancedDark',
- 'researchMasterFire', 'researchMasterWater', 'researchMasterEarth',
- 'researchDamageEffects', 'researchCombatEffects',
- 'researchManaEffects', 'researchAdvancedManaEffects', 'researchUtilityEffects'
+ 'researchMasterFire', 'researchMasterWater', 'researchMasterEarth',
+ 'researchDamageEffects', 'researchCombatEffects', 'researchManaEffects',
+ 'researchAdvancedManaEffects', 'researchUtilityEffects'
];
researchSkills.forEach(skillId => {
store.skills[skillId] = 1;
});
+ useGameStore.setState({ skills: { ...store.skills } });
}}
>
Unlock All Research
@@ -194,9 +186,7 @@ export function SkillDebug({ store }: SkillDebugProps) {
variant="outline"
onClick={() => {
// Add all unlocked effects to unlockedEffects
- const effectIds = Object.keys(store.unlockedEffects || {});
- // Add spell effects, mana effects, combat effects, utility effects
- const allEffectIds = [
+ const effectIds = [
// Spell effects
'spell_manaBolt', 'spell_manaStrike', 'spell_fireball', 'spell_emberShot',
'spell_waterJet', 'spell_iceShard', 'spell_gust', 'spell_windSlash',
@@ -229,11 +219,13 @@ export function SkillDebug({ store }: SkillDebugProps) {
// Sword enchants
'sword_fire', 'sword_frost', 'sword_lightning', 'sword_void'
];
- allEffectIds.forEach(id => {
- if (!store.unlockedEffects.includes(id)) {
- store.unlockedEffects.push(id);
+ const currentEffects = store.unlockedEffects || [];
+ effectIds.forEach(id => {
+ if (!currentEffects.includes(id)) {
+ currentEffects.push(id);
}
});
+ useGameStore.setState({ unlockedEffects: currentEffects });
}}
>
Unlock All Effects
@@ -260,27 +252,22 @@ export function SkillDebug({ store }: SkillDebugProps) {
'spell_manaBolt', 'spell_manaStrike', 'spell_fireball', 'spell_emberShot',
'spell_waterJet', 'spell_iceShard', 'spell_gust', 'spell_windSlash',
'spell_stoneBullet', 'spell_rockSpike', 'spell_lightLance', 'spell_radiance',
- 'spell_shadowBolt', 'spell_darkPulse', 'spell_drain', 'spell_inferno',
- 'spell_flameWave', 'spell_tidalWave', 'spell_iceStorm', 'spell_hurricane',
- 'spell_windBlade', 'spell_earthquake', 'spell_stoneBarrage', 'spell_solarFlare',
- 'spell_divineSmite', 'spell_voidRift', 'spell_shadowStorm', 'spell_pyroclasm',
- 'spell_tsunami', 'spell_meteorStrike', 'spell_spark', 'spell_lightningBolt',
- 'spell_chainLightning', 'spell_stormCall', 'spell_thunderStrike', 'spell_metalShard',
- 'spell_ironFist', 'spell_steelTempest', 'spell_furnaceBlast', 'spell_sandBlast',
- 'spell_sandstorm', 'spell_desertWind', 'spell_duneCollapse',
+ 'spell_shadowBolt', 'spell_darkPulse', 'spell_drain',
'mana_cap_50', 'mana_cap_100', 'mana_regen_1', 'mana_regen_2', 'mana_regen_5',
'click_mana_1', 'click_mana_3', 'damage_5', 'damage_10', 'damage_pct_10',
'crit_5', 'attack_speed_10', 'meditate_10', 'study_10', 'insight_5',
- 'spell_echo_10', 'guardian_dmg_10', 'overpower_80',
- 'weapon_mana_cap_20', 'weapon_mana_cap_50', 'weapon_mana_cap_100',
- 'weapon_mana_regen_1', 'weapon_mana_regen_2', 'weapon_mana_regen_5',
- 'sword_fire', 'sword_frost', 'sword_lightning', 'sword_void'
+ 'spell_echo_10', 'guardian_dmg_10', 'overpower_80'
];
+ const currentEffects = store.unlockedEffects || [];
allEffectIds.forEach(id => {
- if (!store.unlockedEffects.includes(id)) {
- store.unlockedEffects.push(id);
+ if (!currentEffects.includes(id)) {
+ currentEffects.push(id);
}
});
+ useGameStore.setState({
+ skills: { ...store.skills },
+ unlockedEffects: currentEffects
+ });
}}
>
🚀 Max Everything
diff --git a/src/components/game/stats/CombatStatsSection.tsx b/src/components/game/stats/CombatStatsSection.tsx
index 47d2be6..d03a343 100644
--- a/src/components/game/stats/CombatStatsSection.tsx
+++ b/src/components/game/stats/CombatStatsSection.tsx
@@ -1,20 +1,21 @@
'use client';
-import { GUARDIANS } from '@/lib/game/constants';
-import { fmtDec } from '@/lib/game/store';
-import type { GameStore } from '@/lib/game/types';
+import { fmtDec } from '@/lib/game/stores';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Swords } from 'lucide-react';
-export interface CombatStatsSectionProps {
- store: GameStore;
-}
+// Modular stores
+import { useSkillStore, useCombatStore } from '@/lib/game/stores';
+
+export function CombatStatsSection() {
+ // Get state from modular stores
+ const skills = useSkillStore((s) => s.skills);
+ const signedPacts = useCombatStore((s) => s.signedPacts);
-export function CombatStatsSection({ store }: CombatStatsSectionProps) {
return (
-
+
Combat Stats
@@ -24,25 +25,25 @@ export function CombatStatsSection({ store }: CombatStatsSectionProps) {
Combat Training Bonus:
- +{(store.skills.combatTrain || 0) * 5}
+ +{(skills.combatTrain || 0) * 5}
Arcane Fury Multiplier:
- ×{fmtDec(1 + (store.skills.arcaneFury || 0) * 0.1, 2)}
+ ×{fmtDec(1 + (skills.arcaneFury || 0) * 0.1, 2)}
Elemental Mastery:
- ×{fmtDec(1 + (store.skills.elementalMastery || 0) * 0.15, 2)}
+ ×{fmtDec(1 + (skills.elementalMastery || 0) * 0.15, 2)}
Guardian Bane:
- ×{fmtDec(1 + (store.skills.guardianBane || 0) * 0.2, 2)} (vs guardians)
+ ×{fmtDec(1 + (skills.guardianBane || 0) * 0.2, 2)} (vs guardians)
Critical Hit Chance:
- {((store.skills.precision || 0) * 5)}%
+ {(skills.precision || 0) * 5}%
Critical Multiplier:
@@ -50,11 +51,10 @@ export function CombatStatsSection({ store }: CombatStatsSectionProps) {
Spell Echo Chance:
- {((store.skills.spellEcho || 0) * 10)}%
+ {(skills.spellEcho || 0) * 10}%
- Pact Multiplier:
- ×{fmtDec(store.signedPacts.reduce((m, f) => m * (GUARDIANS[f]?.pact || 1), 1), 2)}
+ ×{fmtDec(signedPacts.reduce((m, f) => m * (GUARDIANS[f]?.pact || 1), 1), 2)}
diff --git a/src/components/game/stats/ManaStatsSection.tsx b/src/components/game/stats/ManaStatsSection.tsx
index 60c04f0..d83cebe 100644
--- a/src/components/game/stats/ManaStatsSection.tsx
+++ b/src/components/game/stats/ManaStatsSection.tsx
@@ -2,14 +2,16 @@
import { getTierMultiplier } from '@/lib/game/skill-evolution';
import { hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects';
-import { fmt, fmtDec } from '@/lib/game/store';
-import type { GameStore, UnifiedEffects } from '@/lib/game/types';
+import { fmt, fmtDec } from '@/lib/game/stores';
+import type { UnifiedEffects } from '@/lib/game/types';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Separator } from '@/components/ui/separator';
import { Droplet } from 'lucide-react';
+// Modular stores
+import { useSkillStore, usePrestigeStore, useManaStore } from '@/lib/game/stores';
+
export interface ManaStatsSectionProps {
- store: GameStore;
upgradeEffects: UnifiedEffects;
maxMana: number;
baseRegen: number;
@@ -26,7 +28,6 @@ export interface ManaStatsSectionProps {
}
export function ManaStatsSection({
- store,
upgradeEffects,
maxMana,
baseRegen,
@@ -41,6 +42,12 @@ export function ManaStatsSection({
hasManaOverflow,
hasEternalFlow,
}: ManaStatsSectionProps) {
+ // Get state from modular stores
+ const skills = useSkillStore((s) => s.skills);
+ const skillTiers = useSkillStore((s) => s.skillTiers);
+ const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
+ const rawMana = useManaStore((s) => s.rawMana);
+
return (
@@ -60,9 +67,9 @@ export function ManaStatsSection({
Mana Well Bonus:
{(() => {
- const mw = store.skillTiers?.manaWell || 1;
+ const mw = skillTiers?.manaWell || 1;
const tieredSkillId = mw > 1 ? `manaWell_t${mw}` : 'manaWell';
- const level = store.skills[tieredSkillId] || store.skills.manaWell || 0;
+ const level = skills[tieredSkillId] || skills.manaWell || 0;
const tierMult = getTierMultiplier(tieredSkillId);
return `+${fmt(level * 100 * tierMult)} (${level} lvl × 100 × ${tierMult}x tier)`;
})()}
@@ -70,7 +77,7 @@ export function ManaStatsSection({
Prestige Mana Well:
- +{fmt((store.prestigeUpgrades.manaWell || 0) * 500)}
+ +{fmt((prestigeUpgrades.manaWell || 0) * 500)}
{upgradeEffects.maxManaBonus > 0 && (
@@ -98,9 +105,9 @@ export function ManaStatsSection({
Mana Flow Bonus:
{(() => {
- const mf = store.skillTiers?.manaFlow || 1;
+ const mf = skillTiers?.manaFlow || 1;
const tieredSkillId = mf > 1 ? `manaFlow_t${mf}` : 'manaFlow';
- const level = store.skills[tieredSkillId] || store.skills.manaFlow || 0;
+ const level = skills[tieredSkillId] || skills.manaFlow || 0;
const tierMult = getTierMultiplier(tieredSkillId);
return `+${fmtDec(level * 1 * tierMult)}/hr (${level} lvl × 1 × ${tierMult}x tier)`;
})()}
@@ -108,15 +115,15 @@ export function ManaStatsSection({
Mana Spring Bonus:
- +{(store.skills.manaSpring || 0) * 2}/hr
+ +{(skills.manaSpring || 0) * 2}/hr
Prestige Mana Flow:
- +{fmtDec((store.prestigeUpgrades.manaFlow || 0) * 0.5)}/hr
+ +{fmtDec((prestigeUpgrades.manaFlow || 0) * 0.5)}/hr
Temporal Echo:
- ×{fmtDec(1 + (store.prestigeUpgrades.temporalEcho || 0) * 0.1, 2)}
+ ×{fmtDec(1 + (prestigeUpgrades.temporalEcho || 0) * 0.1, 2)}
Base Regen:
@@ -167,26 +174,28 @@ export function ManaStatsSection({
Mana Tap Bonus:
- +{store.skills.manaTap || 0}
+ +{skills.manaTap || 0}
Mana Surge Bonus:
- +{(store.skills.manaSurge || 0) * 3}
+ +{(skills.manaSurge || 0) * 3}
Mana Overflow:
- ×{fmtDec(1 + (store.skills.manaOverflow || 0) * 0.25, 2)}
+ ×{fmtDec(1 + (skills.manaOverflow || 0) * 0.25, 2)}
- Meditation Multiplier:
+ 1.5 ? 'text-purple-400' : 'text-gray-300'}`}>
+ Meditation Multiplier:
+
1.5 ? 'text-purple-400' : 'text-gray-300'}`}>
{fmtDec(meditationMultiplier, 2)}x
- Effective Regen:
+ Effective Regen:
{fmtDec(effectiveRegen, 2)}/hr
{incursionStrength > 0 && !hasSpecial(upgradeEffects, SPECIAL_EFFECTS.STEADY_STREAM) && (
@@ -237,13 +246,13 @@ export function ManaStatsSection({
Regen immune to ALL penalties
)}
- {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_TORRENT) && store.rawMana > maxMana * 0.75 && (
+ {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_TORRENT) && rawMana > maxMana * 0.75 && (
Mana Torrent:
+50% regen (high mana)
)}
- {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.DESPERATE_WELLS) && store.rawMana < maxMana * 0.25 && (
+ {hasSpecial(upgradeEffects, SPECIAL_EFFECTS.DESPERATE_WELLS) && rawMana < maxMana * 0.25 && (
Desperate Wells:
+50% regen (low mana)
diff --git a/src/components/game/stats/ManaTypeBreakdown.tsx b/src/components/game/stats/ManaTypeBreakdown.tsx
index 5e6b716..1a9aec2 100644
--- a/src/components/game/stats/ManaTypeBreakdown.tsx
+++ b/src/components/game/stats/ManaTypeBreakdown.tsx
@@ -1,37 +1,68 @@
'use client';
import { ELEMENTS } from '@/lib/game/constants';
-import { fmt, fmtDec } from '@/lib/game/store';
-import type { GameStore } from '@/lib/game/types';
-import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
+import { fmt, fmtDec } from '@/lib/game/stores';
import { ATTUNEMENTS_DEF, getAttunementConversionRate } from '@/lib/game/data/attunements';
-import { computeMaxMana, computeElementMax } from '@/lib/game/store';
+import { computeMaxMana, computeElementMax } from '@/lib/game/stores';
import { computeEffectiveRegenForDisplay } from '@/lib/game/store-modules/computed-stats';
import { getUnifiedEffects } from '@/lib/game/effects';
+import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Droplet } from 'lucide-react';
import { Separator } from '@/components/ui/separator';
-export interface ManaTypeBreakdownProps {
- store: GameStore;
-}
+// Modular stores
+import { useCombatStore, useManaStore, useSkillStore, usePrestigeStore } from '@/lib/game/stores';
-export function ManaTypeBreakdown({ store }: ManaTypeBreakdownProps) {
+export function ManaTypeBreakdown() {
+ // Get state from modular stores
+ const skills = useSkillStore((s) => s.skills);
+ const skillTiers = useSkillStore((s) => s.skillTiers);
+ const skillUpgrades = useSkillStore((s) => s.skillUpgrades);
+
+ const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
+ const elements = useManaStore((s) => s.elements);
+ const rawMana = useManaStore((s) => s.rawMana);
+ const attunements = useCombatStore((s) => s.attunements);
+
// Compute unified effects for regen calculations
- const effects = getUnifiedEffects(store);
+ const effects = getUnifiedEffects({
+ skillUpgrades,
+ skillTiers,
+ equippedInstances: {},
+ equipmentInstances: {}
+ });
// Get effective regen info for raw mana
- const regenInfo = computeEffectiveRegenForDisplay(store, effects);
+ const regenInfo = computeEffectiveRegenForDisplay({
+ skills,
+ prestigeUpgrades,
+ skillUpgrades,
+ skillTiers,
+ elements,
+ rawMana,
+ attunements
+ } as any, effects);
// Compute max mana
- const maxMana = computeMaxMana(store, effects);
+ const maxMana = computeMaxMana({
+ skills,
+ prestigeUpgrades,
+ skillUpgrades,
+ skillTiers
+ }, effects);
// Get unlocked elements sorted by category then name
- const unlockedElements = Object.entries(store.elements)
+ const unlockedElements = Object.entries(elements)
.filter(([, state]) => state.unlocked)
.map(([id, state]) => {
const def = ELEMENTS[id];
if (!def) return null;
- const elemMax = computeElementMax(store, effects, id);
+ const elemMax = computeElementMax({
+ skills,
+ prestigeUpgrades,
+ skillUpgrades,
+ skillTiers
+ } as any, effects, id);
return {
id,
name: def.name,
@@ -69,7 +100,7 @@ export function ManaTypeBreakdown({ store }: ManaTypeBreakdownProps) {
(base)
- {fmt(store.rawMana)}
+ {fmt(rawMana)}
/
{fmt(maxMana)}
@@ -79,7 +110,7 @@ export function ManaTypeBreakdown({ store }: ManaTypeBreakdownProps) {
@@ -102,13 +133,15 @@ export function ManaTypeBreakdown({ store }: ManaTypeBreakdownProps) {
{/* Show conversion drains by attunement */}
- {store.conversionDrains && Object.keys(store.conversionDrains).length > 0 && (
+ {attunements && Object.keys(attunements).length > 0 && (
<>
Conversion Drains:
- {Object.entries(store.conversionDrains).map(([attId, rate]) => {
+ {Object.entries(attunements).map(([attId, attState]) => {
const attDef = ATTUNEMENTS_DEF[attId];
- if (!attDef || rate <= 0) return null;
+ if (!attDef || attState.level === 0) return null;
+ const rate = getAttunementConversionRate(attId, attState.level);
+ if (rate <= 0) return null;
return (
{attDef.name}:
@@ -128,7 +161,7 @@ export function ManaTypeBreakdown({ store }: ManaTypeBreakdownProps) {
if (!elem) return null;
// Find attunements that convert TO this element
- const convertingAttunements = Object.entries(store.attunements || {})
+ const convertingAttunements = Object.entries(attunements || {})
.filter(([attId, attState]) => {
if (!attState.active) return false;
const attDef = ATTUNEMENTS_DEF[attId];
@@ -177,7 +210,7 @@ export function ManaTypeBreakdown({ store }: ManaTypeBreakdownProps) {
Source: {convertingAttunements.map(([attId]) => {
const attDef = ATTUNEMENTS_DEF[attId];
- const level = store.attunements[attId]?.level || 1;
+ const level = attunements[attId]?.level || 1;
return `${attDef?.name} (Lv.${level})`;
}).join(', ')}
diff --git a/src/components/game/stats/StudyStatsSection.tsx b/src/components/game/stats/StudyStatsSection.tsx
index 6631b9d..c7908dd 100644
--- a/src/components/game/stats/StudyStatsSection.tsx
+++ b/src/components/game/stats/StudyStatsSection.tsx
@@ -1,17 +1,22 @@
'use client';
-import { fmtDec } from '@/lib/game/store';
-import type { GameStore } from '@/lib/game/types';
+import { fmtDec } from '@/lib/game/stores';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { BookOpen } from 'lucide-react';
+// Modular stores
+import { useSkillStore, usePrestigeStore } from '@/lib/game/stores';
+
export interface StudyStatsSectionProps {
- store: GameStore;
studySpeedMult: number;
studyCostMult: number;
}
-export function StudyStatsSection({ store, studySpeedMult, studyCostMult }: StudyStatsSectionProps) {
+export function StudyStatsSection({ studySpeedMult, studyCostMult }: StudyStatsSectionProps) {
+ // Get state from modular stores
+ const skills = useSkillStore((s) => s.skills);
+ const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
+
return (
@@ -29,7 +34,7 @@ export function StudyStatsSection({ store, studySpeedMult, studyCostMult }: Stud
Quick Learner Bonus:
- +{((store.skills.quickLearner || 0) * 10)}%
+ +{((skills.quickLearner || 0) * 10)}%
@@ -39,13 +44,13 @@ export function StudyStatsSection({ store, studySpeedMult, studyCostMult }: Stud
Focused Mind Bonus:
- -{((store.skills.focusedMind || 0) * 5)}%
+ -{((skills.focusedMind || 0) * 5)}%
Progress Retention:
- {Math.round((1 + (store.skills.knowledgeRetention || 0) * 0.2) * 100)}%
+ {Math.round((1 + (skills.knowledgeRetention || 0) * 0.2) * 100)}%
diff --git a/src/components/game/stats/UpgradeEffectsSection.tsx b/src/components/game/stats/UpgradeEffectsSection.tsx
index 629e9a8..84d561c 100644
--- a/src/components/game/stats/UpgradeEffectsSection.tsx
+++ b/src/components/game/stats/UpgradeEffectsSection.tsx
@@ -1,44 +1,46 @@
'use client';
-import { SKILL_EVOLUTION_PATHS, getTierMultiplier } from '@/lib/game/skill-evolution';
+import { SKILL_EVOLUTION_PATHS } from '@/lib/game/skill-evolution';
import { SKILLS_DEF } from '@/lib/game/constants';
-import type { GameStore, SkillUpgradeChoice } from '@/lib/game/types';
+import type { SkillUpgradeChoice } from '@/lib/game/types';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Star } from 'lucide-react';
-export interface UpgradeEffectsSectionProps {
- store: GameStore;
-}
+// Modular stores
+import { useSkillStore } from '@/lib/game/stores';
-// Helper function to get all selected skill upgrades
-function getAllSelectedUpgrades(store: GameStore) {
- const upgrades: { skillId: string; upgrade: SkillUpgradeChoice }[] = [];
- for (const [skillId, selectedIds] of Object.entries(store.skillUpgrades)) {
- const baseSkillId = skillId.includes('_t') ? skillId.split('_t')[0] : skillId;
- const path = SKILL_EVOLUTION_PATHS[baseSkillId];
- if (!path) continue;
- for (const tier of path.tiers) {
- if (tier.skillId === skillId) {
- for (const upgradeId of selectedIds) {
- const upgrade = tier.upgrades.find(u => u.id === upgradeId);
- if (upgrade) {
- upgrades.push({ skillId, upgrade });
+export function UpgradeEffectsSection() {
+ // Get state from modular stores
+ const skillUpgrades = useSkillStore((s) => s.skillUpgrades);
+
+ // Helper function to get all selected skill upgrades
+ function getAllSelectedUpgrades() {
+ const upgrades = [];
+ for (const [skillId, selectedIds] of Object.entries(skillUpgrades)) {
+ const baseSkillId = skillId.includes('_t') ? skillId.split('_t')[0] : skillId;
+ const path = SKILL_EVOLUTION_PATHS[baseSkillId];
+ if (!path) continue;
+ for (const tier of path.tiers) {
+ if (tier.skillId === skillId) {
+ for (const upgradeId of selectedIds) {
+ const upgrade = tier.upgrades.find(u => u.id === upgradeId);
+ if (upgrade) {
+ upgrades.push({ skillId, upgrade });
+ }
}
}
}
}
+ return upgrades;
}
- return upgrades;
-}
-export function UpgradeEffectsSection({ store }: UpgradeEffectsSectionProps) {
- const selectedUpgrades = getAllSelectedUpgrades(store);
+ const selectedUpgrades = getAllSelectedUpgrades();
return (
-
+
Active Skill Upgrades ({selectedUpgrades.length})
@@ -57,17 +59,17 @@ export function UpgradeEffectsSection({ store }: UpgradeEffectsSectionProps) {
{upgrade.desc}
- {upgrade.effect.type === 'multiplier' && (
+ {upgrade.effect && upgrade.effect.type === 'multiplier' && (
- +{Math.round((upgrade.effect.value! - 1) * 100)}% {upgrade.effect.stat}
+ +{Math.round((upgrade.effect.value - 1) * 100)}% {upgrade.effect.stat}
)}
- {upgrade.effect.type === 'bonus' && (
+ {upgrade.effect && upgrade.effect.type === 'bonus' && (
+{upgrade.effect.value} {upgrade.effect.stat}
)}
- {upgrade.effect.type === 'special' && (
+ {upgrade.effect && upgrade.effect.type === 'special' && (
⚡ {upgrade.effect.specialDesc || 'Special effect active'}
diff --git a/src/components/game/tabs/DebugTab.tsx b/src/components/game/tabs/DebugTab.tsx
index 197f55d..34b3dfb 100755
--- a/src/components/game/tabs/DebugTab.tsx
+++ b/src/components/game/tabs/DebugTab.tsx
@@ -1,31 +1,26 @@
'use client';
-import type { GameStore } from '@/lib/game/store';
+import { GameStateDebug } from '@/components/game/debug/GameStateDebug';
import {
- GameStateDebug,
SkillDebug,
- ElementDebug,
AttunementDebug,
+ ElementDebug,
GolemDebug,
PactDebug
} from '@/components/game/debug';
-interface DebugTabProps {
- store: GameStore;
-}
-
-export function DebugTab({ store }: DebugTabProps) {
+export function DebugTab() {
return (
);
diff --git a/src/components/game/tabs/StatsTab.tsx b/src/components/game/tabs/StatsTab.tsx
old mode 100755
new mode 100644
index 6c87166..17903c6
--- a/src/components/game/tabs/StatsTab.tsx
+++ b/src/components/game/tabs/StatsTab.tsx
@@ -3,8 +3,9 @@
import { ELEMENTS, GUARDIANS } from '@/lib/game/constants';
import { getTierMultiplier } from '@/lib/game/skill-evolution';
import { hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects';
-import { fmt, fmtDec } from '@/lib/game/store';
-import type { GameStore, UnifiedEffects } from '@/lib/game/types';
+import { getUnifiedEffects } from '@/lib/game/effects';
+import { fmt, fmtDec, computeMaxMana, computeRegen, computeClickMana, getMeditationBonus, getIncursionStrength, getStudySpeedMultiplier, getStudyCostMultiplier } from '@/lib/game/stores';
+import type { UnifiedEffects } from '@/lib/game/types';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Separator } from '@/components/ui/separator';
@@ -15,57 +16,107 @@ import { CombatStatsSection } from '../stats/CombatStatsSection';
import { StudyStatsSection } from '../stats/StudyStatsSection';
import { UpgradeEffectsSection } from '../stats/UpgradeEffectsSection';
-export interface StatsTabProps {
- store: GameStore;
- upgradeEffects: UnifiedEffects;
- maxMana: number;
- baseRegen: number;
- clickMana: number;
- meditationMultiplier: number;
- effectiveRegen: number;
- incursionStrength: number;
- manaCascadeBonus: number;
- manaWaterfallBonus: number;
- hasManaWaterfall: boolean;
- hasFlowSurge: boolean;
- hasManaOverflow: boolean;
- hasEternalFlow: boolean;
- studySpeedMult: number;
- studyCostMult: number;
-}
+// Modular stores
+import { useCombatStore, useManaStore, useSkillStore, usePrestigeStore, useGameStore } from '@/lib/game/stores';
+
+export function StatsTab() {
+ // Get state from modular stores
+ const skills = useSkillStore((s) => s.skills);
+ const skillTiers = useSkillStore((s) => s.skillTiers);
+ const skillUpgrades = useSkillStore((s) => s.skillUpgrades);
+
+ const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
+ const loopCount = usePrestigeStore((s) => s.loopCount);
+ const insight = usePrestigeStore((s) => s.insight);
+ const totalInsight = usePrestigeStore((s) => s.totalInsight);
+ const memorySlots = usePrestigeStore((s) => s.memorySlots);
+
+ const elements = useManaStore((s) => s.elements);
+ const totalManaGathered = useManaStore((s) => s.totalManaGathered);
+ const rawMana = useManaStore((s) => s.rawMana);
+ const meditateTicks = useManaStore((s) => s.meditateTicks);
+
+ const signedPacts = useCombatStore((s) => s.signedPacts);
+ const maxFloorReached = useCombatStore((s) => s.maxFloorReached);
+ const spells = useCombatStore((s) => s.spells);
+
+ // Compute unified effects
+ const upgradeEffects = getUnifiedEffects({
+ skillUpgrades,
+ skillTiers,
+ equippedInstances: {},
+ equipmentInstances: {}
+ }) as UnifiedEffects;
+
+ // Compute derived stats
+ const maxMana = computeMaxMana({
+ skills,
+ prestigeUpgrades,
+ skillUpgrades,
+ skillTiers
+ }, upgradeEffects);
+
+ const baseRegen = computeRegen({
+ skills,
+ prestigeUpgrades,
+ skillUpgrades,
+ skillTiers
+ }, upgradeEffects);
+
+ const clickMana = computeClickMana({
+ skills,
+ prestigeUpgrades,
+ skillUpgrades,
+ skillTiers
+ });
+
+ // Get meditation multiplier
+ const meditationMultiplier = getMeditationBonus(meditateTicks, skills, upgradeEffects.meditationEfficiency);
+
+ // Get incursion strength
+ const day = useGameStore((s) => s.day);
+ const hour = useGameStore((s) => s.hour);
+ const incursionStrength = getIncursionStrength(day, hour);
+
+ // Effective regen with incursion penalty
+ const effectiveRegenWithSpecials = baseRegen * (1 - incursionStrength);
+
+ // Mana Cascade bonus
+ const manaCascadeBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_CASCADE)
+ ? Math.floor(maxMana / 100) * 0.1
+ : 0;
+
+ // Mana Waterfall bonus
+ const manaWaterfallBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_WATERFALL)
+ ? Math.floor(maxMana / 100) * 0.25
+ : 0;
+
+ // Effective regen
+ const effectiveRegen = (effectiveRegenWithSpecials + manaCascadeBonus + manaWaterfallBonus) * meditationMultiplier;
+
+ // Get study speed/cost multipliers
+ const studySpeedMult = getStudySpeedMultiplier(skills, skillUpgrades, skillTiers);
+ const studyCostMult = getStudyCostMultiplier(skills, skillUpgrades, skillTiers);
+
+ // Check special effects
+ const hasManaWaterfall = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_WATERFALL);
+ const hasFlowSurge = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.FLOW_SURGE);
+ const hasManaOverflow = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_OVERFLOW);
+ const hasEternalFlow = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.ETERNAL_FLOW);
-export function StatsTab({
- store,
- upgradeEffects,
- maxMana,
- baseRegen,
- clickMana,
- meditationMultiplier,
- effectiveRegen,
- incursionStrength,
- manaCascadeBonus,
- manaWaterfallBonus,
- hasManaWaterfall,
- hasFlowSurge,
- hasManaOverflow,
- hasEternalFlow,
- studySpeedMult,
- studyCostMult,
-}: StatsTabProps) {
// Compute element max
const elemMax = (() => {
- const ea = store.skillTiers?.elemAttune || 1;
+ const ea = skillTiers?.elemAttune || 1;
const tieredSkillId = ea > 1 ? `elemAttune_t${ea}` : 'elemAttune';
- const level = store.skills[tieredSkillId] || store.skills.elemAttune || 0;
+ const level = skills[tieredSkillId] || skills.elemAttune || 0;
const tierMult = getTierMultiplier(tieredSkillId);
- return 10 + level * 50 * tierMult + (store.prestigeUpgrades.elementalAttune || 0) * 25;
+ return 10 + level * 50 * tierMult + (prestigeUpgrades.elementalAttune || 0) * 25;
})();
return (
{/* Mana Stats */}
{/* Mana Type Breakdown */}
-
+
{/* Combat Stats */}
-
+
{/* Study Stats */}
@@ -113,9 +163,9 @@ export function StatsTab({
Elem. Attunement Bonus:
{(() => {
- const ea = store.skillTiers?.elemAttune || 1;
+ const ea = skillTiers?.elemAttune || 1;
const tieredSkillId = ea > 1 ? `elemAttune_t${ea}` : 'elemAttune';
- const level = store.skills[tieredSkillId] || store.skills.elemAttune || 0;
+ const level = skills[tieredSkillId] || skills.elemAttune || 0;
const tierMult = getTierMultiplier(tieredSkillId);
return `+${level * 50 * tierMult}`;
})()}
@@ -123,24 +173,24 @@ export function StatsTab({
Prestige Attunement:
- +{(store.prestigeUpgrades.elementalAttune || 0) * 25}
+ +{(prestigeUpgrades.elementalAttune || 0) * 25}
Unlocked Elements:
- {Object.values(store.elements).filter(e => e.unlocked).length} / {Object.keys(ELEMENTS).length}
+ {Object.values(elements).filter(e => e.unlocked).length} / {Object.keys(ELEMENTS).length}
Elem. Crafting Bonus:
- ×{fmtDec(1 + (store.skills.elemCrafting || 0) * 0.25, 2)}
+ ×{fmtDec(1 + (skills.elemCrafting || 0) * 0.25, 2)}
Elemental Mana Pools:
- {Object.entries(store.elements)
+ {Object.entries(elements)
.filter(([, state]) => state.unlocked)
.map(([id, state]) => {
const def = ELEMENTS[id];
@@ -156,9 +206,9 @@ export function StatsTab({
{/* Active Upgrades */}
-
+
- {/* Enchantment Power (placeholder for Task 5) */}
+ {/* Enchantment Power */}
@@ -183,15 +233,15 @@ export function StatsTab({
- Signed Pacts ({store.signedPacts.length}/10)
+ Signed Pacts ({signedPacts.length}/10)
- {store.signedPacts.length === 0 ? (
+ {signedPacts.length === 0 ? (
No pacts signed yet. Defeat guardians to earn pacts.
) : (
- {store.signedPacts.map((floor) => {
+ {signedPacts.map((floor) => {
const guardian = GUARDIANS[floor];
if (!guardian) return null;
return (
@@ -214,7 +264,7 @@ export function StatsTab({
})}
Combined Pact Multiplier:
- ×{fmtDec(store.signedPacts.reduce((m, f) => m * (GUARDIANS[f]?.pact || 1), 1), 2)}
+ ×{fmtDec(signedPacts.reduce((m, f) => m * (GUARDIANS[f]?.pact || 1), 1), 2)}
)}
@@ -232,38 +282,38 @@ export function StatsTab({
-
{store.loopCount}
+
{loopCount}
Loops Completed
-
{fmt(store.insight)}
+
{fmt(insight)}
Current Insight
-
{fmt(store.totalInsight)}
+
{fmt(totalInsight)}
Total Insight
-
{store.maxFloorReached}
+
{maxFloorReached}
Max Floor
-
{Object.values(store.spells).filter(s => s.learned).length}
+
{Object.values(spells).filter(s => s.learned).length}
Spells Learned
-
{Object.values(store.skills).reduce((a, b) => a + b, 0)}
+
{Object.values(skills).reduce((a, b) => a + b, 0)}
Total Skill Levels
-
{fmt(store.totalManaGathered)}
+
{fmt(totalManaGathered)}
Total Mana Gathered
-
{store.memorySlots}
+
{memorySlots}
Memory Slots
diff --git a/src/lib/game/stores/index.ts b/src/lib/game/stores/index.ts
index c382471..f2686a5 100755
--- a/src/lib/game/stores/index.ts
+++ b/src/lib/game/stores/index.ts
@@ -21,14 +21,13 @@ export { useGameStore } from './gameStore';
export { useGameLoop } from './gameHooks';
export type { GameCoordinatorState, GameCoordinatorStore } from './gameStore';
-// Re-export utilities from utils.ts
+// Re-export utilities from utils.ts and computed-stats
export {
fmt,
fmtDec,
getFloorMaxHP,
getFloorElement,
computeMaxMana,
- computeElementMax,
computeRegen,
computeEffectiveRegen,
computeClickMana,
@@ -41,3 +40,7 @@ export {
canAffordSpellCost,
deductSpellCost,
} from '../utils';
+
+export { computeElementMax } from '../store-modules/computed-stats';
+
+export { getStudySpeedMultiplier, getStudyCostMultiplier } from '../constants';