Refine NPC interactions and runtime item generation

This commit is contained in:
2026-04-05 17:13:07 +08:00
parent c49c64896a
commit 89cecda7da
58 changed files with 4199 additions and 1562 deletions

View File

@@ -162,7 +162,21 @@ export function CustomWorldEntityCatalog({
const filteredPlayable = useMemo(
() => profile.playableNpcs.filter(role =>
!deferredSearch
|| matchText([role.name, role.title, role.description, role.backstory, role.personality, ...role.tags].join(' '), deferredSearch),
|| matchText(
[
role.name,
role.title,
role.role,
role.description,
role.backstory,
role.personality,
role.motivation,
role.combatStyle,
...role.relationshipHooks,
...role.tags,
].join(' '),
deferredSearch,
),
),
[deferredSearch, profile.playableNpcs],
);
@@ -170,7 +184,21 @@ export function CustomWorldEntityCatalog({
const filteredStory = useMemo(
() => profile.storyNpcs.filter(npc =>
!deferredSearch
|| matchText([npc.name, npc.role, npc.description, npc.motivation, ...npc.relationshipHooks].join(' '), deferredSearch),
|| matchText(
[
npc.name,
npc.title,
npc.role,
npc.description,
npc.backstory,
npc.personality,
npc.motivation,
npc.combatStyle,
...npc.relationshipHooks,
...npc.tags,
].join(' '),
deferredSearch,
),
),
[deferredSearch, profile.storyNpcs],
);
@@ -320,9 +348,12 @@ export function CustomWorldEntityCatalog({
<div className="text-sm leading-6 text-zinc-300">{role.description}</div>
<div className="mt-2 text-xs leading-6 text-zinc-400">{role.backstory}</div>
<div className="mt-3 grid gap-2 sm:grid-cols-2">
<div className="rounded-xl border border-white/8 bg-black/20 px-3 py-2 text-xs leading-6 text-zinc-300">{role.role}</div>
<div className="rounded-xl border border-white/8 bg-black/20 px-3 py-2 text-xs leading-6 text-zinc-300">{role.initialAffinity}</div>
<div className="rounded-xl border border-white/8 bg-black/20 px-3 py-2 text-xs leading-6 text-zinc-300">{role.personality}</div>
<div className="rounded-xl border border-white/8 bg-black/20 px-3 py-2 text-xs leading-6 text-zinc-300">{role.combatStyle}</div>
</div>
<div className="mt-3 rounded-xl border border-white/8 bg-black/20 px-3 py-2 text-xs leading-6 text-zinc-300">{role.motivation}</div>
<div className="mt-3 flex flex-wrap gap-2">
{role.tags.map(tag => (
<span key={`${role.id}-${tag}`} className="rounded-full border border-white/10 bg-black/20 px-2.5 py-1 text-[10px] text-zinc-300">
@@ -343,7 +374,7 @@ export function CustomWorldEntityCatalog({
{activeTab === 'story' ? (
<div className="space-y-3">
<div className="rounded-2xl border border-white/8 bg-black/20 px-4 py-3 text-sm text-zinc-300">
NPC
</div>
{filteredStory.length === 0 ? (
<EmptyState title="当前没有符合搜索条件的场景角色。" />
@@ -362,18 +393,22 @@ export function CustomWorldEntityCatalog({
>
<div className="grid gap-4 sm:grid-cols-[7rem_minmax(0,1fr)]">
<CustomWorldNpcPortrait
npc={{
id: npc.id,
name: npc.name,
role: npc.role,
description: npc.description,
}}
npc={npc}
visual={npc.visual}
className="aspect-square"
scale={2.18}
/>
<div className="min-w-0 space-y-3">
<div className="text-sm leading-6 text-zinc-300">{npc.description}</div>
<div className="grid gap-2 sm:grid-cols-2">
<div className="rounded-2xl border border-white/8 bg-black/20 px-3 py-3 text-sm leading-6 text-zinc-300">{npc.title}</div>
<div className="rounded-2xl border border-white/8 bg-black/20 px-3 py-3 text-sm leading-6 text-zinc-300">{npc.initialAffinity}</div>
<div className="rounded-2xl border border-white/8 bg-black/20 px-3 py-3 text-sm leading-6 text-zinc-300">{npc.personality || '未填写'}</div>
<div className="rounded-2xl border border-white/8 bg-black/20 px-3 py-3 text-sm leading-6 text-zinc-300">{npc.combatStyle || '未填写'}</div>
</div>
{npc.backstory ? (
<div className="rounded-2xl border border-white/8 bg-black/20 px-3 py-3 text-sm leading-6 text-zinc-300">{npc.backstory}</div>
) : null}
<div className="rounded-2xl border border-white/8 bg-black/20 px-3 py-3 text-sm leading-6 text-zinc-300">{npc.motivation}</div>
<div className="flex flex-wrap gap-2">
{npc.relationshipHooks.map(hook => (
@@ -381,6 +416,11 @@ export function CustomWorldEntityCatalog({
{hook}
</span>
))}
{npc.tags.map(tag => (
<span key={`${npc.id}-tag-${tag}`} className="rounded-full border border-sky-300/12 bg-sky-500/8 px-2.5 py-1 text-[10px] text-sky-100">
{tag}
</span>
))}
</div>
</div>
</div>