fix(#170): wire fabricator crafting completion + bonus enchantments + remove dead code
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m22s
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m22s
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
// ─── Equipment Crafting Tick ─────────────────────────────────────────────────
|
||||
// Handles advancing equipment crafting progress and completing crafted items.
|
||||
// Extracted from craftingStore.ts to stay under the 400-line file limit.
|
||||
|
||||
import type { CraftingState } from './craftingStore.types';
|
||||
import * as CraftingEquipment from '../crafting-equipment';
|
||||
import { CRAFTING_RECIPES } from '../data/crafting-recipes';
|
||||
import { FABRICATOR_RECIPES } from '../data/fabricator-recipes';
|
||||
import { HOURS_PER_TICK } from '../constants';
|
||||
import type { AppliedEnchantment } from '../types/equipment';
|
||||
import { useCombatStore } from './combatStore';
|
||||
|
||||
export interface CraftingTickResult {
|
||||
completed: boolean;
|
||||
logMessage?: string;
|
||||
}
|
||||
|
||||
export function processEquipmentCraftingTick(
|
||||
state: CraftingState,
|
||||
set: (partial: Partial<CraftingState>) => void,
|
||||
): CraftingTickResult {
|
||||
const progress = state.equipmentCraftingProgress;
|
||||
if (!progress) return { completed: false };
|
||||
|
||||
const newProgress = progress.progress + HOURS_PER_TICK;
|
||||
|
||||
// Still in progress — just advance
|
||||
if (newProgress < progress.required) {
|
||||
set({ equipmentCraftingProgress: { ...progress, progress: newProgress } });
|
||||
return { completed: false };
|
||||
}
|
||||
|
||||
// Crafting complete — resolve the recipe and create instance
|
||||
const isFabricator = progress.blueprintId.startsWith('fabricator-');
|
||||
|
||||
if (isFabricator) {
|
||||
const recipeId = progress.blueprintId.replace('fabricator-', '');
|
||||
const recipe = FABRICATOR_RECIPES.find(r => r.id === recipeId);
|
||||
if (!recipe) {
|
||||
set({ equipmentCraftingProgress: null });
|
||||
useCombatStore.setState({ currentAction: 'meditate' });
|
||||
return { completed: false, logMessage: '🔨 Crafting failed: recipe not found.' };
|
||||
}
|
||||
const bonusEnchantments: AppliedEnchantment[] = recipe.bonusEnchantments
|
||||
? recipe.bonusEnchantments.map(e => ({ ...e }))
|
||||
: [];
|
||||
const result = CraftingEquipment.completeEquipmentCrafting(
|
||||
progress.blueprintId,
|
||||
recipe as any,
|
||||
bonusEnchantments,
|
||||
);
|
||||
if (result.success) {
|
||||
const { instanceId, instance, logMessage } = result.data;
|
||||
set({
|
||||
equipmentInstances: { ...state.equipmentInstances, [instanceId]: instance },
|
||||
equipmentCraftingProgress: null,
|
||||
});
|
||||
useCombatStore.setState({ currentAction: 'meditate' });
|
||||
return { completed: true, logMessage };
|
||||
} else {
|
||||
set({ equipmentCraftingProgress: null });
|
||||
useCombatStore.setState({ currentAction: 'meditate' });
|
||||
return { completed: false, logMessage: `🔨 Crafting failed: ${result.error}` };
|
||||
}
|
||||
} else {
|
||||
// Blueprint crafting
|
||||
const blueprint = CRAFTING_RECIPES[progress.blueprintId];
|
||||
if (!blueprint) {
|
||||
set({ equipmentCraftingProgress: null });
|
||||
useCombatStore.setState({ currentAction: 'meditate' });
|
||||
return { completed: false, logMessage: '🔨 Crafting failed: blueprint not found.' };
|
||||
}
|
||||
const result = CraftingEquipment.completeEquipmentCrafting(
|
||||
progress.blueprintId,
|
||||
blueprint,
|
||||
);
|
||||
if (result.success) {
|
||||
const { instanceId, instance, logMessage } = result.data;
|
||||
set({
|
||||
equipmentInstances: { ...state.equipmentInstances, [instanceId]: instance },
|
||||
equipmentCraftingProgress: null,
|
||||
});
|
||||
useCombatStore.setState({ currentAction: 'meditate' });
|
||||
return { completed: true, logMessage };
|
||||
} else {
|
||||
set({ equipmentCraftingProgress: null });
|
||||
useCombatStore.setState({ currentAction: 'meditate' });
|
||||
return { completed: false, logMessage: `🔨 Crafting failed: ${result.error}` };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
makeFabricatorProgress,
|
||||
} from '../crafting-fabricator';
|
||||
import { craftMaterial as craftMaterialAction } from '../crafting-actions/crafting-material-actions';
|
||||
import { processEquipmentCraftingTick } from './crafting-equipment-tick';
|
||||
|
||||
export const useCraftingStore = create<CraftingStore>()(
|
||||
persist(
|
||||
@@ -363,6 +364,11 @@ export const useCraftingStore = create<CraftingStore>()(
|
||||
return { unlockedEffects: Array.from(existing) };
|
||||
});
|
||||
},
|
||||
|
||||
processEquipmentCraftingTick: (): { completed: boolean; logMessage?: string } => {
|
||||
const state = get();
|
||||
return processEquipmentCraftingTick(state, set as unknown as (partial: Partial<CraftingState>) => void);
|
||||
},
|
||||
};
|
||||
},
|
||||
{
|
||||
|
||||
@@ -72,6 +72,7 @@ export interface CraftingActions {
|
||||
resetEnchantmentSelection: () => void;
|
||||
clearLastError: () => void;
|
||||
unlockEffects: (effectIds: string[]) => void;
|
||||
processEquipmentCraftingTick: () => { completed: boolean; logMessage?: string };
|
||||
}
|
||||
|
||||
export type CraftingStore = CraftingState & CraftingActions;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// ─── Game Store (Coordinator) ─────────────────────────────────────────────────
|
||||
// ─── Game Store (Coordinator) ──────────────────────────────────────
|
||||
// Manages: day, hour, incursionStrength, containmentWards
|
||||
// Orchestrates tick across all stores via a read → compute → write pipeline.
|
||||
// Orchestrates tick across all stores via read → compute → write pipeline.
|
||||
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
@@ -11,13 +11,7 @@ import { computeEquipmentEffects } from '../effects';
|
||||
import type { ComputedEffects } from '../effects/upgrade-effects.types';
|
||||
|
||||
import { computeDisciplineEffects } from '../effects/discipline-effects';
|
||||
import {
|
||||
computeMaxMana,
|
||||
computeRegen,
|
||||
getMeditationBonus,
|
||||
getIncursionStrength,
|
||||
calcInsight
|
||||
} from '../utils';
|
||||
import { computeMaxMana, computeRegen, getMeditationBonus, getIncursionStrength, calcInsight } from '../utils';
|
||||
import { useUIStore } from './uiStore';
|
||||
import { usePrestigeStore } from './prestigeStore';
|
||||
import { useManaStore } from './manaStore';
|
||||
@@ -161,7 +155,6 @@ export const useGameStore = create<GameCoordinatorStore>()(
|
||||
return;
|
||||
}
|
||||
|
||||
// Incursion
|
||||
const incursionStrength = getIncursionStrength(day, hour);
|
||||
|
||||
// Meditation bonus tracking
|
||||
@@ -208,7 +201,7 @@ export const useGameStore = create<GameCoordinatorStore>()(
|
||||
});
|
||||
let totalManaGathered = ctx.mana.totalManaGathered;
|
||||
|
||||
// Convert action — delegate to manaStore
|
||||
// Convert action
|
||||
if (ctx.combat.currentAction === 'convert') {
|
||||
const convertResult = useManaStore.getState().processConvertAction(rawMana);
|
||||
if (convertResult) {
|
||||
@@ -217,7 +210,7 @@ export const useGameStore = create<GameCoordinatorStore>()(
|
||||
}
|
||||
}
|
||||
|
||||
// Pact ritual progress
|
||||
// Pact ritual
|
||||
if (ctx.prestige.pactRitualFloor !== null) {
|
||||
const guardian = getGuardianForFloor(ctx.prestige.pactRitualFloor);
|
||||
if (guardian) {
|
||||
@@ -253,7 +246,7 @@ export const useGameStore = create<GameCoordinatorStore>()(
|
||||
}
|
||||
}
|
||||
|
||||
// Discipline tick — process active disciplines (XP accrual + mana drain)
|
||||
// Discipline tick
|
||||
const disciplineResult = useDisciplineStore.getState().processTick({
|
||||
rawMana,
|
||||
elements,
|
||||
@@ -355,6 +348,14 @@ export const useGameStore = create<GameCoordinatorStore>()(
|
||||
};
|
||||
}
|
||||
|
||||
// Equipment crafting tick — advance progress and complete when done
|
||||
if (ctx.combat.currentAction === 'craft') {
|
||||
const craftingResult = useCraftingStore.getState().processEquipmentCraftingTick();
|
||||
if (craftingResult.logMessage) {
|
||||
addLog(craftingResult.logMessage);
|
||||
}
|
||||
}
|
||||
|
||||
// ── Phase 3: Write — batch all state updates ─────────────────────────
|
||||
writes.game = { day, hour, incursionStrength };
|
||||
writes.mana = {
|
||||
|
||||
Reference in New Issue
Block a user