import { useMemo, useState } from 'react'; import type { RuntimeStoryEquipmentSlotView, RuntimeStoryForgeRecipeView, RuntimeStoryInventoryItemView, } from '../../packages/shared/src/contracts/rpgRuntimeStoryState'; import { formatCurrency } from '../data/economy'; import { buildInitialPlayerInventory } from '../data/npcInteractions'; import { Character, InventoryItem, NarrativeCodexSection, NarrativeQaReport, WorldType, } from '../types'; import { PlatformPillBadge } from './common/PlatformPillBadge'; import { PlatformActionButton } from './common/PlatformActionButton'; import { PlatformStatusMessage } from './common/PlatformStatusMessage'; import { PlatformSubpanel } from './common/PlatformSubpanel'; import { InventoryItemDetailModal, InventoryItemGrid, } from './InventoryItemViews'; interface InventoryPanelProps { playerCharacter: Character; worldType: WorldType | null; playerInventory: InventoryItem[]; playerCurrency: number; playerHp: number; playerMaxHp: number; playerMana: number; playerMaxMana: number; inBattle: boolean; currencyText?: string | null; backpackItems?: RuntimeStoryInventoryItemView[]; equipmentSlots?: RuntimeStoryEquipmentSlotView[]; onUseItem: (itemId: string) => Promise; onEquipItem: (itemId: string) => Promise; forgeRecipes: RuntimeStoryForgeRecipeView[]; onCraftRecipe: (recipeId: string) => Promise; onDismantleItem: (itemId: string) => Promise; onReforgeItem: (itemId: string) => Promise; narrativeCodex?: NarrativeCodexSection[]; narrativeQaReport?: NarrativeQaReport | null; } export function InventoryPanel({ playerCharacter, worldType, playerInventory, playerCurrency, inBattle, currencyText = null, backpackItems = [], equipmentSlots: _equipmentSlots = [], onUseItem: _onUseItem, onEquipItem: _onEquipItem, forgeRecipes, onCraftRecipe, onDismantleItem: _onDismantleItem, onReforgeItem: _onReforgeItem, narrativeCodex = [], narrativeQaReport = null, }: InventoryPanelProps) { const [selectedItem, setSelectedItem] = useState(null); const [forgeActionKey, setForgeActionKey] = useState(null); const serverInventoryItems = useMemo( () => backpackItems .map((view) => view.item as unknown as InventoryItem) .filter( (item) => typeof item.id === 'string' && typeof item.name === 'string', ), [backpackItems], ); const inventoryItems = useMemo( () => serverInventoryItems.length > 0 ? serverInventoryItems : playerInventory.length > 0 ? playerInventory : buildInitialPlayerInventory(playerCharacter, worldType), [playerCharacter, playerInventory, serverInventoryItems, worldType], ); const documentItems = useMemo( () => inventoryItems.filter( (item) => item.category === '文书' || item.tags.includes('document'), ), [inventoryItems], ); return (
{documentItems.length > 0 && (
文书与证据
{documentItems.map((item) => ( setSelectedItem(item)} surface="dark" radius="xs" padding="row" className="w-full text-left transition hover:border-white/15" >
{item.name}
{item.description || '记录着当前线程的阶段性线索。'}
))}
)} {(narrativeCodex.length > 0 || narrativeQaReport) && (
故事档案
{narrativeQaReport && ( QA:{narrativeQaReport.summary} )}
{narrativeCodex.slice(0, 3).map((section) => (
{section.title}
{section.entries.slice(0, 3).map((entry) => (
{entry.title} {':'} {entry.summary}
))}
))}
)}
工坊 {currencyText ?? formatCurrency(playerCurrency, worldType)}
{forgeRecipes.map((recipe) => (
{recipe.name}
{recipe.description}
产物:{recipe.resultLabel}
花费:{recipe.currencyText}
{ setForgeActionKey(recipe.id); const crafted = await onCraftRecipe(recipe.id); setForgeActionKey(null); if (crafted && selectedItem) { setSelectedItem(null); } }} className="rounded-lg disabled:border-white/8 disabled:bg-black/20 disabled:text-zinc-500 disabled:opacity-100" > {forgeActionKey === recipe.id ? '制作中...' : recipe.kind === 'forge' ? '锻造' : '合成'}
{recipe.requirements.map((requirement) => { const isRequirementMet = requirement.owned >= requirement.quantity; return ( {requirement.label} {requirement.owned}/ {requirement.quantity} ); })}
{(!recipe.canCraft || !recipe.action.enabled) && (recipe.disabledReason || recipe.action.reason) && (
{recipe.disabledReason ?? recipe.action.reason}
)}
))}
setSelectedItem(null)} />
); }