fix: 6 priority-3 bug fixes with regression tests
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m24s

- Issue 83: Mana Tide pulse factor now ranges 0.5x-1.5x (was 0.5x-1.0x)
- Issue 82: SteadyStream no longer returns early like EternalFlow; only skips incursion penalty
- Issue 81: Prestige store partialize now includes defeatedGuardians, signedPacts, signedPactDetails, pactRitualFloor, pactRitualProgress, loopInsight, pactSlots
- Issue 80: Combat store partialize now includes floorHP, floorMaxHP, castProgress, spireMode, clearedFloors, golemancy, equipmentSpellStates, activityLog, achievements
- Issue 78: cancelDesign now always cancels designProgress first, then designProgress2
- Issue 79: startDesigningEnchantment now uses designProgress2 when designProgress is occupied

Added 13 regression tests in src/lib/game/__tests__/regression-fixes.test.ts
Refactored craftingStore types to craftingStore.types.ts to stay under 400-line limit
This commit is contained in:
2026-05-19 11:19:10 +02:00
parent c3a5f333da
commit 48a5ad1855
13 changed files with 387 additions and 1046 deletions
+17 -85
View File
@@ -1,7 +1,8 @@
// ─── Crafting Store ─────────────────────────────────────────────────────
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { DesignProgress, PreparationProgress, ApplicationProgress, EquipmentCraftingProgress, EnchantmentDesign, EquipmentInstance, DesignEffect } from '../types';
import type { DesignProgress, EnchantmentDesign, DesignEffect } from '../types';
import type { CraftingStore, CraftingState } from './craftingStore.types';
import * as CraftingUtils from '../crafting-utils';
import * as CraftingDesign from '../crafting-design';
import { useManaStore } from './manaStore';
@@ -12,87 +13,6 @@ import * as ApplicationActions from '../crafting-actions/application-actions';
import * as PreparationActions from '../crafting-actions/preparation-actions';
import * as CraftingEquipment from '../crafting-equipment';
export interface CraftingState {
// Crafting progress
designProgress: DesignProgress | null;
designProgress2: DesignProgress | null; // For ENCHANT_MASTERY (2 concurrent designs)
preparationProgress: PreparationProgress | null;
applicationProgress: ApplicationProgress | null;
equipmentCraftingProgress: EquipmentCraftingProgress | null;
// Enchantment designs
enchantmentDesigns: EnchantmentDesign[];
// Unlocked enchantment effects
unlockedEffects: string[];
// Equipment instances (instanceId -> instance)
equipmentInstances: Record<string, EquipmentInstance>;
// Equipped instances (slot -> instanceId or null)
equippedInstances: Record<string, string | null>;
// Loot inventory
lootInventory: {
materials: Record<string, number>;
blueprints: string[];
};
// Enchantment selection state (single source of truth for enchanting UI)
enchantmentSelection: {
selectedEquipmentType: string | null;
selectedEffects: DesignEffect[];
designName: string;
selectedDesign: string | null;
selectedEquipmentInstance: string | null;
};
}
export interface CraftingActions {
// Actions for design progress
setDesignProgress: (progress: DesignProgress | null) => void;
setDesignProgress2: (progress: DesignProgress | null) => void;
// Actions for preparation progress
setPreparationProgress: (progress: PreparationProgress | null) => void;
// Actions for application progress
setApplicationProgress: (progress: ApplicationProgress | null) => void;
// Actions for equipment crafting progress
setEquipmentCraftingProgress: (progress: EquipmentCraftingProgress | null) => void;
// Enchantment design actions
startDesigningEnchantment: (name: string, equipmentTypeId: string, effects: DesignEffect[]) => boolean;
cancelDesign: () => void;
saveDesign: (design: EnchantmentDesign) => void;
deleteDesign: (designId: string) => void;
// Enchantment application actions
startApplying: (equipmentInstanceId: string, designId: string) => boolean;
pauseApplication: () => void;
resumeApplication: () => void;
cancelApplication: () => void;
// Enchantment preparation actions
startPreparing: (equipmentInstanceId: string) => boolean;
cancelPreparation: () => void;
// Loot inventory actions
deleteMaterial: (materialId: string, amount: number) => void;
deleteEquipmentInstance: (instanceId: string) => void;
// Equipment crafting actions
startCraftingEquipment: (blueprintId: string) => boolean;
cancelEquipmentCrafting: () => void;
// Enchantment selection actions (store as source of truth)
setSelectedEquipmentType: (type: string | null) => void;
setSelectedEffects: (effects: DesignEffect[]) => void;
setDesignName: (name: string) => void;
setSelectedDesign: (id: string | null) => void;
setSelectedEquipmentInstance: (id: string | null) => void;
resetEnchantmentSelection: () => void;
}
export type CraftingStore = CraftingState & CraftingActions;
export const useCraftingStore = create<CraftingStore>()(
persist(
(set, get) => {
@@ -155,6 +75,18 @@ export const useCraftingStore = create<CraftingStore>()(
};
// Update currentAction in combatStore
useCombatStore.setState({ currentAction: 'design' });
} else if (!state.designProgress2) {
updates = {
designProgress2: {
designId: CraftingUtils.generateDesignId(),
progress: 0,
required: CraftingDesign.calculateDesignTime(effects),
name,
equipmentType: equipmentTypeId,
effects,
},
};
useCombatStore.setState({ currentAction: 'design' });
} else {
return false;
}
@@ -165,11 +97,11 @@ export const useCraftingStore = create<CraftingStore>()(
cancelDesign: () => {
const state = get();
if (state.designProgress2 && !state.designProgress) {
set({ designProgress2: null });
} else {
if (state.designProgress) {
set({ designProgress: null });
useCombatStore.setState({ currentAction: 'meditate' });
} else if (state.designProgress2) {
set({ designProgress2: null });
}
},