diff --git a/docs/project-structure.txt b/docs/project-structure.txt index 19ce6a2..12e3e4a 100644 --- a/docs/project-structure.txt +++ b/docs/project-structure.txt @@ -191,15 +191,24 @@ Mana-Loop/ │ │ ├── __tests__/ │ │ │ ├── store-method-tests/ │ │ │ ├── achievements.test.ts +│ │ │ ├── activity-log.test.ts │ │ │ ├── bug-fixes.test.ts │ │ │ ├── combat-utils.test.ts │ │ │ ├── computed-stats.test.ts +│ │ │ ├── crafting-utils-basic.test.ts +│ │ │ ├── crafting-utils-equipment.test.ts +│ │ │ ├── crafting-utils-recipe.test.ts +│ │ │ ├── crafting-utils-time.test.ts │ │ │ ├── discipline-math.test.ts │ │ │ ├── enemy-generator.test.ts +│ │ │ ├── enemy-utils.test.ts │ │ │ ├── floor-utils.test.ts +│ │ │ ├── floor-utils.upgraded.test.ts │ │ │ ├── formatting.test.ts │ │ │ ├── mana-utils.test.ts +│ │ │ ├── pact-utils.test.ts │ │ │ ├── regression-fixes.test.ts +│ │ │ ├── room-utils.test.ts │ │ │ ├── spire-utils.test.ts │ │ │ ├── store-actions-combat-prestige.test.ts │ │ │ ├── store-actions-discipline.test.ts @@ -302,6 +311,7 @@ Mana-Loop/ │ │ │ ├── combat-actions.ts │ │ │ ├── combat-state.types.ts │ │ │ ├── combatStore.ts +│ │ │ ├── crafting-initial-state.ts │ │ │ ├── craftingStore.ts │ │ │ ├── craftingStore.types.ts │ │ │ ├── discipline-slice.ts @@ -357,6 +367,7 @@ Mana-Loop/ ├── Caddyfile ├── Dockerfile ├── README.md +├── STATS_TAB_INVESTIGATION_REPORT.md ├── bun.lock ├── bunfig.toml ├── components.json diff --git a/src/components/game/tabs/EquipmentTab.tsx b/src/components/game/tabs/EquipmentTab.tsx index 599d2d0..b91d2da 100644 --- a/src/components/game/tabs/EquipmentTab.tsx +++ b/src/components/game/tabs/EquipmentTab.tsx @@ -22,8 +22,8 @@ export function EquipmentTab() { }, []); const handleEquip = useCallback( - (instanceId: string, slot: EquipmentSlot) => { - storeEquipItem(instanceId, slot); + (instanceId: string, slot: EquipmentSlot): boolean => { + return storeEquipItem(instanceId, slot); }, [storeEquipItem] ); diff --git a/src/components/game/tabs/SpireCombatPage/RoomDisplay.tsx b/src/components/game/tabs/SpireCombatPage/RoomDisplay.tsx index c191aa3..a9ddd4c 100644 --- a/src/components/game/tabs/SpireCombatPage/RoomDisplay.tsx +++ b/src/components/game/tabs/SpireCombatPage/RoomDisplay.tsx @@ -90,8 +90,8 @@ export function RoomDisplay({ floorState, floor }: RoomDisplayProps) { const rt = floorState.roomType as string; if (rt === 'recovery') { - const progress = floorState.puzzleProgress || 0; - const required = floorState.puzzleRequired || 1; + const progress = floorState.recoveryProgress || 0; + const required = floorState.recoveryRequired || 1; return ( diff --git a/src/components/game/tabs/StatsTab.tsx b/src/components/game/tabs/StatsTab.tsx index 056881b..8242ec8 100755 --- a/src/components/game/tabs/StatsTab.tsx +++ b/src/components/game/tabs/StatsTab.tsx @@ -28,20 +28,18 @@ export function StatsTab() { effectiveRegen={manaStats.effectiveRegen} clickMana={manaStats.clickMana} meditationMultiplier={manaStats.meditationMultiplier} - upgradeEffects={{ - ...manaStats.upgradeEffects, - incursionStrength: manaStats.incursionStrength, - rawMana: manaStats.maxMana, - hasSteadyStream: manaStats.hasSteadyStream, - hasManaTorrent: manaStats.hasManaTorrent, - hasDesperateWells: manaStats.hasDesperateWells, - manaCascadeBonus: manaStats.manaCascadeBonus, - manaWaterfallBonus: manaStats.manaWaterfallBonus, - hasFlowSurge: manaStats.hasFlowSurge, - hasManaOverflow: manaStats.hasManaOverflow, - hasEternalFlow: manaStats.hasEternalFlow, - }} + upgradeEffects={manaStats.upgradeEffects} elemMax={elemMax} + incursionStrength={manaStats.incursionStrength} + rawMana={manaStats.maxMana} + hasSteadyStream={manaStats.hasSteadyStream} + hasManaTorrent={manaStats.hasManaTorrent} + hasDesperateWells={manaStats.hasDesperateWells} + manaCascadeBonus={manaStats.manaCascadeBonus} + manaWaterfallBonus={manaStats.manaWaterfallBonus} + hasFlowSurge={manaStats.hasFlowSurge} + hasManaOverflow={manaStats.hasManaOverflow} + hasEternalFlow={manaStats.hasEternalFlow} /> @@ -114,7 +124,7 @@ export function ManaStatsSection({
Incursion Strength: - {Math.round(upgradeEffects.incursionStrength * 100)}% + {Math.round(incursionStrength * 100)}%
Effective Regen: @@ -123,55 +133,55 @@ export function ManaStatsSection({
{/* Special Effects */} - {(upgradeEffects.hasSteadyStream || upgradeEffects.hasManaTorrent || - upgradeEffects.hasDesperateWells || upgradeEffects.manaCascadeBonus > 0 || - upgradeEffects.manaWaterfallBonus > 0) && ( + {(hasSteadyStream || hasManaTorrent || + hasDesperateWells || manaCascadeBonus > 0 || + manaWaterfallBonus > 0) && ( <>
Special Effects
- {upgradeEffects.hasSteadyStream && ( + {hasSteadyStream && (
Steady Stream: Immune to incursion
)} - {upgradeEffects.manaCascadeBonus > 0 && ( + {manaCascadeBonus > 0 && (
Mana Cascade: - +{fmtDec(upgradeEffects.manaCascadeBonus, 2)}/hr + +{fmtDec(manaCascadeBonus, 2)}/hr
)} - {upgradeEffects.manaWaterfallBonus > 0 && ( + {manaWaterfallBonus > 0 && (
Mana Waterfall: - +{fmtDec(upgradeEffects.manaWaterfallBonus, 2)}/hr + +{fmtDec(manaWaterfallBonus, 2)}/hr
)} - {upgradeEffects.hasFlowSurge && ( + {hasFlowSurge && (
Flow Surge: Clicks +100% regen for 1hr
)} - {upgradeEffects.hasManaOverflow && ( + {hasManaOverflow && (
Mana Overflow: Raw can exceed max by 20%
)} - {upgradeEffects.hasEternalFlow && ( + {hasEternalFlow && (
Eternal Flow: Regen immune to ALL penalties
)} - {upgradeEffects.hasManaTorrent && upgradeEffects.rawMana > maxMana * 0.75 && ( + {hasManaTorrent && rawMana > maxMana * 0.75 && (
Mana Torrent: +50% regen (high mana)
)} - {upgradeEffects.hasDesperateWells && upgradeEffects.rawMana < maxMana * 0.25 && ( + {hasDesperateWells && rawMana < maxMana * 0.25 && (
Desperate Wells: +50% regen (low mana) diff --git a/src/lib/game/stores/craftingStore.ts b/src/lib/game/stores/craftingStore.ts index 8e269ed..fcd2a15 100644 --- a/src/lib/game/stores/craftingStore.ts +++ b/src/lib/game/stores/craftingStore.ts @@ -13,6 +13,7 @@ import { useUIStore } from './uiStore'; import * as ApplicationActions from '../crafting-actions/application-actions'; import * as PreparationActions from '../crafting-actions/preparation-actions'; import * as CraftingEquipment from '../crafting-equipment'; +import { equipItem as equipItemAction, unequipItem as unequipItemAction } from '../crafting-actions/equipment-actions'; import { ErrorCode } from '../utils/result'; import { createSafeStorage } from '../utils/safe-persist'; import type { Result } from '../utils/result'; @@ -376,6 +377,14 @@ export const useCraftingStore = create()( }; }); }, + + equipItem: (instanceId: string, slot: EquipmentSlot) => { + return equipItemAction(instanceId, slot, get, set); + }, + + unequipItem: (slot: EquipmentSlot) => { + unequipItemAction(slot, set); + }, }; }, { diff --git a/src/lib/game/stores/craftingStore.types.ts b/src/lib/game/stores/craftingStore.types.ts index e1af7c6..944631f 100644 --- a/src/lib/game/stores/craftingStore.types.ts +++ b/src/lib/game/stores/craftingStore.types.ts @@ -8,6 +8,7 @@ import type { EquipmentInstance, DesignEffect, } from '../types'; +import type { EquipmentSlot } from '../types/equipmentSlot'; export interface CraftingError { code: string; @@ -57,6 +58,8 @@ export interface CraftingActions { cancelPreparation: () => void; deleteMaterial: (materialId: string, amount: number) => void; deleteEquipmentInstance: (instanceId: string) => void; + equipItem: (instanceId: string, slot: EquipmentSlot) => boolean; + unequipItem: (slot: EquipmentSlot) => void; startCraftingEquipment: (blueprintId: string) => boolean; cancelEquipmentCrafting: () => void; setSelectedEquipmentType: (type: string | null) => void; diff --git a/src/lib/game/stores/discipline-slice.ts b/src/lib/game/stores/discipline-slice.ts index 54128c2..239b497 100644 --- a/src/lib/game/stores/discipline-slice.ts +++ b/src/lib/game/stores/discipline-slice.ts @@ -52,19 +52,29 @@ export const useDisciplineStore = create()( set((s) => { const def = DISCIPLINE_MAP[id]; if (!def) return s; - if (s.activeIds.includes(id)) return s; + + // Allow re-activation if discipline exists but is paused + const existing = s.disciplines[id]; + if (s.activeIds.includes(id)) { + // If already active and paused, un-pause it + if (existing?.paused) { + return { + disciplines: { ...s.disciplines, [id]: { ...existing, paused: false } }, + }; + } + return s; + } const nonPaused = s.activeIds.filter((aid) => { const d = s.disciplines[aid]; return d && !d.paused; }).length; if (nonPaused >= s.concurrentLimit) return s; - const discState = s.disciplines[id]; - if (!canProceedDiscipline(def, discState, gameState)) return s; + if (!canProceedDiscipline(def, existing, gameState)) return s; - const existing = s.disciplines[id] || { id, xp: 0, paused: false }; + const discState = existing || { id, xp: 0, paused: false }; return { - disciplines: { ...s.disciplines, [id]: { ...existing, paused: false } }, + disciplines: { ...s.disciplines, [id]: { ...discState, paused: false } }, activeIds: [...s.activeIds, id], }; }); @@ -73,6 +83,9 @@ export const useDisciplineStore = create()( deactivate(id) { set((s) => ({ activeIds: s.activeIds.filter((aid) => aid !== id), + disciplines: s.disciplines[id] + ? { ...s.disciplines, [id]: { ...s.disciplines[id], paused: true } } + : s.disciplines, })); },