fix(spire): reset currentAction to meditate on spire exit; fix(crafting): wire enchanting state hooks to EnchantmentDesigner/Preparer/Applier
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m53s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m53s
This commit is contained in:
@@ -397,6 +397,7 @@ Mana-Loop/
|
|||||||
│ │ │ │ ├── regen.test.ts
|
│ │ │ │ ├── regen.test.ts
|
||||||
│ │ │ │ ├── skill.test.ts
|
│ │ │ │ ├── skill.test.ts
|
||||||
│ │ │ │ ├── spell-cost.test.ts
|
│ │ │ │ ├── spell-cost.test.ts
|
||||||
|
│ │ │ │ ├── spire-exit-action.test.ts
|
||||||
│ │ │ │ └── spire-tab-refresh.test.ts
|
│ │ │ │ └── spire-tab-refresh.test.ts
|
||||||
│ │ │ ├── attunementStore.ts
|
│ │ │ ├── attunementStore.ts
|
||||||
│ │ │ ├── combat-actions.ts
|
│ │ │ ├── combat-actions.ts
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
import { useCombatStore, useCraftingStore } from '@/lib/game/stores';
|
import { useCombatStore, useCraftingStore } from '@/lib/game/stores';
|
||||||
import { DebugName } from '@/lib/game/debug-context';
|
import { DebugName } from '@/lib/game/debug-context';
|
||||||
import { useGameToast } from '@/components/game/GameToast';
|
import { useGameToast } from '@/components/game/GameToast';
|
||||||
|
import type { DesignEffect } from '@/lib/game/types';
|
||||||
|
|
||||||
export function CraftingTab() {
|
export function CraftingTab() {
|
||||||
const showToast = useGameToast();
|
const showToast = useGameToast();
|
||||||
@@ -30,6 +31,13 @@ export function CraftingTab() {
|
|||||||
const [activeTab, setActiveTab] = useState<'fabricate' | 'enchant'>('fabricate');
|
const [activeTab, setActiveTab] = useState<'fabricate' | 'enchant'>('fabricate');
|
||||||
const [enchantStage, setEnchantStage] = useState<'design' | 'prepare' | 'apply'>('design');
|
const [enchantStage, setEnchantStage] = useState<'design' | 'prepare' | 'apply'>('design');
|
||||||
|
|
||||||
|
// Enchant state
|
||||||
|
const [selectedEquipmentType, setSelectedEquipmentType] = useState<string | null>(null);
|
||||||
|
const [selectedEffects, setSelectedEffects] = useState<DesignEffect[]>([]);
|
||||||
|
const [designName, setDesignName] = useState('');
|
||||||
|
const [selectedDesign, setSelectedDesign] = useState<string | null>(null);
|
||||||
|
const [selectedEquipmentInstance, setSelectedEquipmentInstance] = useState<string | null>(null);
|
||||||
|
|
||||||
// Safe toFixed helper
|
// Safe toFixed helper
|
||||||
const safeToFixed = (value: number | undefined, decimals: number = 0): string => {
|
const safeToFixed = (value: number | undefined, decimals: number = 0): string => {
|
||||||
if (value === undefined || isNaN(value)) return '0';
|
if (value === undefined || isNaN(value)) return '0';
|
||||||
@@ -121,28 +129,28 @@ export function CraftingTab() {
|
|||||||
{/* Enchant Stage Content */}
|
{/* Enchant Stage Content */}
|
||||||
{enchantStage === 'design' && (
|
{enchantStage === 'design' && (
|
||||||
<EnchantmentDesigner
|
<EnchantmentDesigner
|
||||||
selectedEquipmentType={null}
|
selectedEquipmentType={selectedEquipmentType}
|
||||||
setSelectedEquipmentType={() => {}}
|
setSelectedEquipmentType={setSelectedEquipmentType}
|
||||||
selectedEffects={[]}
|
selectedEffects={selectedEffects}
|
||||||
setSelectedEffects={() => {}}
|
setSelectedEffects={setSelectedEffects}
|
||||||
designName={''}
|
designName={designName}
|
||||||
setDesignName={() => {}}
|
setDesignName={setDesignName}
|
||||||
selectedDesign={null}
|
selectedDesign={selectedDesign}
|
||||||
setSelectedDesign={() => {}}
|
setSelectedDesign={setSelectedDesign}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{enchantStage === 'prepare' && (
|
{enchantStage === 'prepare' && (
|
||||||
<EnchantmentPreparer
|
<EnchantmentPreparer
|
||||||
selectedEquipmentInstance={null}
|
selectedEquipmentInstance={selectedEquipmentInstance}
|
||||||
setSelectedEquipmentInstance={() => {}}
|
setSelectedEquipmentInstance={setSelectedEquipmentInstance}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{enchantStage === 'apply' && (
|
{enchantStage === 'apply' && (
|
||||||
<EnchantmentApplier
|
<EnchantmentApplier
|
||||||
selectedEquipmentInstance={null}
|
selectedEquipmentInstance={selectedEquipmentInstance}
|
||||||
setSelectedEquipmentInstance={() => {}}
|
setSelectedEquipmentInstance={setSelectedEquipmentInstance}
|
||||||
selectedDesign={null}
|
selectedDesign={selectedDesign}
|
||||||
setSelectedDesign={() => {}}
|
setSelectedDesign={setSelectedDesign}
|
||||||
onEnchantmentApplied={handleEnchantmentApplied}
|
onEnchantmentApplied={handleEnchantmentApplied}
|
||||||
onCapacityExceeded={handleCapacityExceeded}
|
onCapacityExceeded={handleCapacityExceeded}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||||
|
import { useCombatStore } from '../combatStore';
|
||||||
|
import { useUIStore } from '../uiStore';
|
||||||
|
|
||||||
|
describe('Spire Exit Action — Bug 1 Fix', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// Reset combat store to a known state
|
||||||
|
useCombatStore.setState({
|
||||||
|
currentFloor: 5,
|
||||||
|
floorHP: 100,
|
||||||
|
floorMaxHP: 100,
|
||||||
|
maxFloorReached: 5,
|
||||||
|
activeSpell: 'manaBolt',
|
||||||
|
currentAction: 'climb' as const,
|
||||||
|
castProgress: 0,
|
||||||
|
spireMode: true,
|
||||||
|
climbDirection: 'down' as const,
|
||||||
|
isDescending: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
useCombatStore.setState({
|
||||||
|
currentFloor: 1,
|
||||||
|
floorHP: 100,
|
||||||
|
floorMaxHP: 100,
|
||||||
|
maxFloorReached: 1,
|
||||||
|
activeSpell: 'manaBolt',
|
||||||
|
currentAction: 'meditate',
|
||||||
|
castProgress: 0,
|
||||||
|
spireMode: false,
|
||||||
|
climbDirection: null,
|
||||||
|
isDescending: false,
|
||||||
|
});
|
||||||
|
useUIStore.setState({ logs: [] });
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reset currentAction to "meditate" when exitSpireMode is called', () => {
|
||||||
|
// Pre-condition: action is "climb" while in spire
|
||||||
|
expect(useCombatStore.getState().currentAction).toBe('climb');
|
||||||
|
expect(useCombatStore.getState().spireMode).toBe(true);
|
||||||
|
|
||||||
|
// Exit spire mode
|
||||||
|
useCombatStore.getState().exitSpireMode();
|
||||||
|
|
||||||
|
// Post-condition: currentAction must be "meditate"
|
||||||
|
expect(useCombatStore.getState().currentAction).toBe('meditate');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set spireMode to false when exitSpireMode is called', () => {
|
||||||
|
useCombatStore.getState().exitSpireMode();
|
||||||
|
expect(useCombatStore.getState().spireMode).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear climbDirection when exitSpireMode is called', () => {
|
||||||
|
useCombatStore.getState().exitSpireMode();
|
||||||
|
expect(useCombatStore.getState().climbDirection).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should clear isDescending when exitSpireMode is called', () => {
|
||||||
|
useCombatStore.getState().exitSpireMode();
|
||||||
|
expect(useCombatStore.getState().isDescending).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -253,7 +253,7 @@ export const useCombatStore = create<CombatState>()(
|
|||||||
},
|
},
|
||||||
|
|
||||||
exitSpireMode: () => {
|
exitSpireMode: () => {
|
||||||
set({ spireMode: false, climbDirection: null, isDescending: false });
|
set({ spireMode: false, currentAction: 'meditate', climbDirection: null, isDescending: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
startClimbUp: () => set({ climbDirection: 'up', currentAction: 'climb' }),
|
startClimbUp: () => set({ climbDirection: 'up', currentAction: 'climb' }),
|
||||||
|
|||||||
Reference in New Issue
Block a user