@@ -62,6 +62,8 @@ interface AdventurePanelProps {
|
||||
canRefreshOptions: boolean;
|
||||
onRefreshOptions: () => void;
|
||||
onChoice: (option: StoryOption) => void;
|
||||
onSubmitNpcChatInput?: (input: string) => boolean;
|
||||
onExitNpcChat?: () => boolean;
|
||||
onOpenCharacter: () => void;
|
||||
onOpenInventory: () => void;
|
||||
playerCharacter: Character;
|
||||
@@ -149,12 +151,22 @@ function getOptionActionTextClass(option: StoryOption) {
|
||||
function getDialogueTurnAlignmentClass(
|
||||
turn: NonNullable<StoryMoment['dialogue']>[number],
|
||||
) {
|
||||
if (turn.speaker === 'system') {
|
||||
return 'justify-center';
|
||||
}
|
||||
|
||||
return turn.speaker === 'player' ? 'justify-end' : 'justify-start';
|
||||
}
|
||||
|
||||
function getDialogueTurnBubbleClass(
|
||||
turn: NonNullable<StoryMoment['dialogue']>[number],
|
||||
) {
|
||||
if (turn.speaker === 'system') {
|
||||
return turn.affinityDelta && turn.affinityDelta > 0
|
||||
? 'border-rose-400/30 bg-rose-500/12 text-rose-50'
|
||||
: 'border-white/12 bg-white/[0.06] text-zinc-100';
|
||||
}
|
||||
|
||||
if (turn.speaker === 'player') {
|
||||
return 'border-sky-400/20 bg-sky-500/10 text-sky-50';
|
||||
}
|
||||
@@ -169,6 +181,10 @@ function getDialogueTurnBubbleClass(
|
||||
function getDialogueTurnBubbleShapeClass(
|
||||
turn: NonNullable<StoryMoment['dialogue']>[number],
|
||||
) {
|
||||
if (turn.speaker === 'system') {
|
||||
return 'rounded-full';
|
||||
}
|
||||
|
||||
if (turn.speaker === 'player') {
|
||||
return 'rounded-2xl rounded-br-none';
|
||||
}
|
||||
@@ -183,6 +199,10 @@ function getDialogueTurnBubbleShapeClass(
|
||||
function getDialogueTurnLabel(
|
||||
turn: NonNullable<StoryMoment['dialogue']>[number],
|
||||
) {
|
||||
if (turn.speaker === 'system') {
|
||||
return turn.affinityDelta && turn.affinityDelta > 0 ? '关系变化' : '系统';
|
||||
}
|
||||
|
||||
if (turn.speaker === 'player') {
|
||||
return '\u4f60';
|
||||
}
|
||||
@@ -597,6 +617,8 @@ export function AdventurePanel({
|
||||
canRefreshOptions,
|
||||
onRefreshOptions,
|
||||
onChoice,
|
||||
onSubmitNpcChatInput,
|
||||
onExitNpcChat,
|
||||
onOpenCharacter,
|
||||
onOpenInventory,
|
||||
playerCharacter,
|
||||
@@ -622,6 +644,8 @@ export function AdventurePanel({
|
||||
}: AdventurePanelProps) {
|
||||
const isDialogueStory = currentStory.displayMode === 'dialogue';
|
||||
const dialogueTurns = currentStory.dialogue ?? [];
|
||||
const npcChatState = currentStory.npcChatState ?? null;
|
||||
const isNpcChatMode = Boolean(npcChatState);
|
||||
const isStoryStreaming = Boolean(currentStory.streaming);
|
||||
const shouldHideChoiceUi = hideOptions;
|
||||
const storyScrollContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
@@ -656,6 +680,7 @@ export function AdventurePanel({
|
||||
const [selectedBattleRewardItemId, setSelectedBattleRewardItemId] = useState<
|
||||
string | null
|
||||
>(null);
|
||||
const [npcChatDraft, setNpcChatDraft] = useState('');
|
||||
const lastAutoOpenedGoalRef = useRef<string | null>(null);
|
||||
const lastAutoOpenedPulseRef = useRef<string | null>(null);
|
||||
const battleReward = battleRewardUi.reward;
|
||||
@@ -734,6 +759,10 @@ export function AdventurePanel({
|
||||
setSelectedBattleRewardItemId(null);
|
||||
}, [battleReward]);
|
||||
|
||||
useEffect(() => {
|
||||
setNpcChatDraft('');
|
||||
}, [npcChatState?.npcId, npcChatState?.turnCount]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!primaryQuestGoal) {
|
||||
return;
|
||||
@@ -887,6 +916,18 @@ export function AdventurePanel({
|
||||
onDismissGoalPulse();
|
||||
};
|
||||
|
||||
const submitNpcChatDraft = () => {
|
||||
const nextInput = npcChatDraft.trim();
|
||||
if (!nextInput || !onSubmitNpcChatInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
const submitted = onSubmitNpcChatInput(nextInput);
|
||||
if (submitted) {
|
||||
setNpcChatDraft('');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative flex min-h-0 flex-1 flex-col">
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user