Fix multiple bugs and add debug features
All checks were successful
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m56s

- Add debug option to show component names at top of each component
- Fix mana lists to hide empty elemental mana types in ManaDisplay and LabTab
- Fix enchantment designing getting stuck at 99% by auto-saving design on completion
- Add resetFloorHP function and debug button to fix stuck floor HP issues
- Store design data in DesignProgress for proper completion handling
This commit is contained in:
Z User
2026-03-29 13:14:26 +00:00
parent 6dc301bd7b
commit 300e43f8be
13 changed files with 321 additions and 153 deletions

View File

@@ -289,24 +289,20 @@ export function createCraftingSlice(
const efficiencyBonus = (state.skills.efficientEnchant || 0) * 0.05;
const totalCapacityCost = calculateDesignCapacityCost(effects, efficiencyBonus);
// Create design
// Create design ID
const designId = `design_${Date.now()}`;
const designTime = calculateDesignTime(effects);
const design: EnchantmentDesign = {
id: `design_${Date.now()}`,
name,
equipmentType: equipmentTypeId,
effects,
totalCapacityUsed: totalCapacityCost,
designTime,
created: Date.now(),
};
// Store design data in progress
set(() => ({
currentAction: 'design',
designProgress: {
designId: design.id,
designId,
progress: 0,
required: designTime,
name,
equipmentType: equipmentTypeId,
effects,
},
}));
@@ -616,11 +612,27 @@ export function processCraftingTick(
if (state.currentAction === 'design' && state.designProgress) {
const progress = state.designProgress.progress + 0.04; // HOURS_PER_TICK
if (progress >= state.designProgress.required) {
// Design complete - but we need the design data to save it
// This will be handled by the UI calling saveDesign
// Design complete - auto-save the design using stored data
const dp = state.designProgress;
const efficiencyBonus = (state.skills.efficientEnchant || 0) * 0.05;
const totalCapacityCost = calculateDesignCapacityCost(dp.effects, efficiencyBonus);
const completedDesign: EnchantmentDesign = {
id: dp.designId,
name: dp.name,
equipmentType: dp.equipmentType,
effects: dp.effects,
totalCapacityUsed: totalCapacityCost,
designTime: dp.required,
created: Date.now(),
};
updates = {
...updates,
log: ['✅ Enchantment design complete!', ...log],
designProgress: null,
currentAction: 'meditate',
enchantmentDesigns: [...state.enchantmentDesigns, completedDesign],
log: [`✅ Enchantment design "${dp.name}" complete!`, ...log],
};
} else {
updates = {

View File

@@ -0,0 +1,67 @@
'use client';
import { createContext, useContext, useState, useEffect, type ReactNode } from 'react';
interface DebugContextType {
showComponentNames: boolean;
toggleComponentNames: () => void;
}
const DebugContext = createContext<DebugContextType | null>(null);
export function DebugProvider({ children }: { children: ReactNode }) {
// Initialize from localStorage if available
const [showComponentNames, setShowComponentNames] = useState(() => {
if (typeof window !== 'undefined') {
const saved = localStorage.getItem('debug-show-component-names');
return saved === 'true';
}
return false;
});
const toggleComponentNames = () => {
setShowComponentNames(prev => {
const newValue = !prev;
localStorage.setItem('debug-show-component-names', String(newValue));
return newValue;
});
};
return (
<DebugContext.Provider value={{ showComponentNames, toggleComponentNames }}>
{children}
</DebugContext.Provider>
);
}
export function useDebug() {
const context = useContext(DebugContext);
if (!context) {
// Return default values if used outside provider
return { showComponentNames: false, toggleComponentNames: () => {} };
}
return context;
}
// Wrapper component to show component name in debug mode
interface DebugNameProps {
name: string;
children: ReactNode;
}
export function DebugName({ name, children }: DebugNameProps) {
const { showComponentNames } = useDebug();
if (!showComponentNames) {
return <>{children}</>;
}
return (
<div className="relative">
<div className="absolute -top-5 left-0 text-[10px] font-mono text-yellow-400 bg-yellow-900/50 px-1 rounded z-50">
{name}
</div>
{children}
</div>
);
}

View File

@@ -10,6 +10,7 @@ export interface NavigationActions {
// Floor Navigation
setClimbDirection: (direction: 'up' | 'down') => void;
changeFloor: (direction: 'up' | 'down') => void;
resetFloorHP: () => void;
}
// ─── Navigation Slice Factory ─────────────────────────────────────────────────
@@ -59,5 +60,16 @@ export function createNavigationSlice(
log: [`🚶 Moved to floor ${nextFloor}${nextFloorCleared ? ' (respawned)' : ''}.`, ...state.log.slice(0, 49)],
});
},
// Reset current floor HP to max (useful when floor HP gets stuck)
resetFloorHP: () => {
const state = get();
const maxHP = getFloorMaxHP(state.currentFloor);
set({
floorMaxHP: maxHP,
floorHP: maxHP,
log: [`🔄 Floor ${state.currentFloor} HP reset to full.`, ...state.log.slice(0, 49)],
});
},
};
}

View File

@@ -578,6 +578,7 @@ interface GameStore extends GameState, CraftingActions {
debugSetTime: (day: number, hour: number) => void;
debugAddAttunementXP: (attunementId: string, amount: number) => void;
debugSetFloor: (floor: number) => void;
resetFloorHP: () => void;
// Computed getters
getMaxMana: () => number;
@@ -1463,26 +1464,26 @@ export const useGameStore = create<GameStore>()(
if (eff.stacks > effectDef.maxStacks) return false;
}
// Calculate capacity cost
const efficiencyBonus = (state.skills.efficientEnchant || 0) * 0.05;
const totalCapacityCost = effects.reduce((total, eff) =>
total + calculateEffectCapacityCost(eff.effectId, eff.stacks, efficiencyBonus), 0);
// Calculate design time
let designTime = 1;
for (const eff of effects) {
designTime += 0.5 * eff.stacks;
}
// Store pending design in designProgress
// Create design ID
const designId = `design_${Date.now()}`;
// Store design data in progress
set(() => ({
currentAction: 'design',
designProgress: {
designId: `design_${Date.now()}`,
designId,
progress: 0,
required: designTime,
name,
equipmentType: equipmentTypeId,
effects,
},
// Store design data temporarily
log: [`🔮 Designing enchantment: ${name}...`, ...state.log.slice(0, 49)],
}));
@@ -1816,6 +1817,16 @@ export const useGameStore = create<GameStore>()(
maxFloorReached: Math.max(state.maxFloorReached, floor),
});
},
resetFloorHP: () => {
const state = get();
const maxHP = getFloorMaxHP(state.currentFloor);
set({
floorMaxHP: maxHP,
floorHP: maxHP,
log: [`🔄 Floor ${state.currentFloor} HP reset to full.`, ...state.log.slice(0, 49)],
});
},
}),
{
name: 'mana-loop-storage',

View File

@@ -213,6 +213,10 @@ export interface DesignProgress {
designId: string;
progress: number; // Hours spent designing
required: number; // Total hours needed
// Design data stored during progress
name: string;
equipmentType: string;
effects: DesignEffect[];
}
export interface PreparationProgress {