1
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import type {
|
||||
RuntimeStoryEquipmentSlotView,
|
||||
RuntimeStoryForgeRecipeView,
|
||||
RuntimeStoryInventoryItemView,
|
||||
} from '../../packages/shared/src/contracts/rpgRuntimeStoryState';
|
||||
import { formatCurrency } from '../data/economy';
|
||||
import { type ForgeRecipeView } from '../data/forgeSystem';
|
||||
import { buildInitialPlayerInventory } from '../data/npcInteractions';
|
||||
import {
|
||||
Character,
|
||||
@@ -25,9 +29,12 @@ interface InventoryPanelProps {
|
||||
playerMana: number;
|
||||
playerMaxMana: number;
|
||||
inBattle: boolean;
|
||||
currencyText?: string | null;
|
||||
backpackItems?: RuntimeStoryInventoryItemView[];
|
||||
equipmentSlots?: RuntimeStoryEquipmentSlotView[];
|
||||
onUseItem: (itemId: string) => Promise<boolean>;
|
||||
onEquipItem: (itemId: string) => Promise<boolean>;
|
||||
forgeRecipes: ForgeRecipeView[];
|
||||
forgeRecipes: RuntimeStoryForgeRecipeView[];
|
||||
onCraftRecipe: (recipeId: string) => Promise<boolean>;
|
||||
onDismantleItem: (itemId: string) => Promise<boolean>;
|
||||
onReforgeItem: (itemId: string) => Promise<boolean>;
|
||||
@@ -42,8 +49,15 @@ export function InventoryPanel({
|
||||
playerInventory,
|
||||
playerCurrency,
|
||||
inBattle,
|
||||
currencyText = null,
|
||||
backpackItems = [],
|
||||
equipmentSlots: _equipmentSlots = [],
|
||||
onUseItem: _onUseItem,
|
||||
onEquipItem: _onEquipItem,
|
||||
forgeRecipes,
|
||||
onCraftRecipe,
|
||||
onDismantleItem: _onDismantleItem,
|
||||
onReforgeItem: _onReforgeItem,
|
||||
continueGameDigest = null,
|
||||
narrativeCodex = [],
|
||||
narrativeQaReport = null,
|
||||
@@ -51,12 +65,24 @@ export function InventoryPanel({
|
||||
const [selectedItem, setSelectedItem] = useState<InventoryItem | null>(null);
|
||||
const [forgeActionKey, setForgeActionKey] = useState<string | null>(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(
|
||||
() =>
|
||||
playerInventory.length > 0
|
||||
? playerInventory
|
||||
: buildInitialPlayerInventory(playerCharacter, worldType),
|
||||
[playerCharacter, playerInventory, worldType],
|
||||
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')),
|
||||
@@ -141,7 +167,7 @@ export function InventoryPanel({
|
||||
<div className="mb-2 flex items-center justify-between gap-3 text-xs uppercase tracking-[0.2em] text-zinc-500">
|
||||
<span>工坊</span>
|
||||
<span className="text-emerald-200/80">
|
||||
{formatCurrency(playerCurrency, worldType)}
|
||||
{currencyText ?? formatCurrency(playerCurrency, worldType)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-3">
|
||||
@@ -169,6 +195,7 @@ export function InventoryPanel({
|
||||
type="button"
|
||||
disabled={
|
||||
!recipe.canCraft ||
|
||||
!recipe.action.enabled ||
|
||||
inBattle ||
|
||||
forgeActionKey === recipe.id
|
||||
}
|
||||
@@ -181,7 +208,7 @@ export function InventoryPanel({
|
||||
}
|
||||
}}
|
||||
className={`rounded-lg border px-3 py-1.5 text-xs transition ${
|
||||
recipe.canCraft && !inBattle
|
||||
recipe.canCraft && recipe.action.enabled && !inBattle
|
||||
? 'border-emerald-400/30 bg-emerald-500/10 text-emerald-100 hover:bg-emerald-500/20'
|
||||
: 'border-white/8 bg-black/20 text-zinc-500'
|
||||
}`}
|
||||
@@ -208,6 +235,12 @@ export function InventoryPanel({
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
{(!recipe.canCraft || !recipe.action.enabled) &&
|
||||
(recipe.disabledReason || recipe.action.reason) && (
|
||||
<div className="mt-2 text-[11px] text-zinc-500">
|
||||
{recipe.disabledReason ?? recipe.action.reason}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user