import { useMemo, type Dispatch, type SetStateAction } from 'react'; import { EQUIPMENT_EQUIP_FUNCTION, EQUIPMENT_UNEQUIP_FUNCTION, FORGE_CRAFT_FUNCTION, FORGE_DISMANTLE_FUNCTION, FORGE_REFORGE_FUNCTION, INVENTORY_USE_FUNCTION, } from '../../data/functionCatalog'; import { getForgeRecipeViews } from '../../data/forgeSystem'; import type { Character, GameState, StoryMoment } from '../../types'; import { resolveServerRuntimeChoice } from './runtimeStoryCoordinator'; import type { InventoryFlowUi } from './uiTypes'; type BuildFallbackStoryForState = ( state: GameState, character: Character, fallbackText?: string, ) => StoryMoment; export function useStoryInventoryActions({ gameState, runtime, }: { gameState: GameState; runtime: { currentStory: StoryMoment | null; setGameState: Dispatch>; setCurrentStory: Dispatch>; setAiError: Dispatch>; setIsLoading: Dispatch>; buildFallbackStoryForState: BuildFallbackStoryForState; }; }) { const { currentStory, setGameState, setCurrentStory, setAiError, setIsLoading, buildFallbackStoryForState, } = runtime; const forgeRecipes = useMemo( () => getForgeRecipeViews( gameState.playerInventory, gameState.playerCurrency, gameState.worldType, ), [gameState.playerCurrency, gameState.playerInventory, gameState.worldType], ); const resolveServerInventoryAction = async (params: { functionId: string; actionText: string; payload: Record; }) => { const character = gameState.playerCharacter; if ( !character || !gameState.worldType || gameState.currentScene !== 'Story' ) { return false; } setAiError(null); setIsLoading(true); try { const { hydratedSnapshot, nextStory } = await resolveServerRuntimeChoice({ gameState, currentStory, option: { functionId: params.functionId, actionText: params.actionText, }, payload: params.payload, }); setGameState(hydratedSnapshot.gameState); setCurrentStory(nextStory); return true; } catch (error) { console.error('Failed to resolve inventory runtime action on the server:', error); setAiError(error instanceof Error ? error.message : '背包动作执行失败'); if (!currentStory) { setCurrentStory(buildFallbackStoryForState(gameState, character)); } return false; } finally { setIsLoading(false); } }; const useInventoryItem = async (itemId: string) => { const item = gameState.playerInventory.find( (candidate) => candidate.id === itemId, ); if (!item) { return false; } return resolveServerInventoryAction({ functionId: INVENTORY_USE_FUNCTION.id, actionText: `使用${item.name}`, payload: { itemId }, }); }; const equipInventoryItem = async (itemId: string) => { const item = gameState.playerInventory.find( (candidate) => candidate.id === itemId, ); if (!item) { return false; } return resolveServerInventoryAction({ functionId: EQUIPMENT_EQUIP_FUNCTION.id, actionText: `装备${item.name}`, payload: { itemId }, }); }; const unequipItem = async (slot: 'weapon' | 'armor' | 'relic') => { const equippedItem = gameState.playerEquipment[slot]; if (!equippedItem) { return false; } return resolveServerInventoryAction({ functionId: EQUIPMENT_UNEQUIP_FUNCTION.id, actionText: `卸下${equippedItem.name}`, payload: { slotId: slot }, }); }; const craftRecipe = async (recipeId: string) => { const recipe = forgeRecipes.find( (candidate) => candidate.id === recipeId, ); if (!recipe) { return false; } return resolveServerInventoryAction({ functionId: FORGE_CRAFT_FUNCTION.id, actionText: `制作${recipe.resultLabel}`, payload: { recipeId }, }); }; const dismantleItem = async (itemId: string) => { const item = gameState.playerInventory.find( (candidate) => candidate.id === itemId, ); if (!item) { return false; } return resolveServerInventoryAction({ functionId: FORGE_DISMANTLE_FUNCTION.id, actionText: `拆解${item.name}`, payload: { itemId }, }); }; const reforgeItem = async (itemId: string) => { const item = gameState.playerInventory.find( (candidate) => candidate.id === itemId, ); if (!item) { return false; } return resolveServerInventoryAction({ functionId: FORGE_REFORGE_FUNCTION.id, actionText: `重铸${item.name}`, payload: { itemId }, }); }; return { inventoryUi: { useInventoryItem, equipInventoryItem, unequipItem, forgeRecipes, craftRecipe, dismantleItem, reforgeItem, } satisfies InventoryFlowUi, }; }