Update dialogue tests to use NPC entities

This commit is contained in:
2026-04-15 09:57:42 +02:00
parent 35b9b33d65
commit 9cbe4dfbfa

View File

@@ -37,7 +37,6 @@ import {
} from "../../src/entities/entity-instances"; } from "../../src/entities/entity-instances";
import { import {
createControlInteractionLink, createControlInteractionLink,
createStartDialogueInteractionLink,
type InteractionLink type InteractionLink
} from "../../src/interactions/interaction-links"; } from "../../src/interactions/interaction-links";
import { createProjectScheduleRoutine } from "../../src/scheduler/project-scheduler"; import { createProjectScheduleRoutine } from "../../src/scheduler/project-scheduler";
@@ -317,7 +316,7 @@ describe("RuntimeHost", () => {
host.dispose(); host.dispose();
}); });
it("opens, advances, and closes project dialogues through the runtime host", () => { it("opens, advances, and closes NPC dialogues through the runtime host", () => {
vi.spyOn(console, "warn").mockImplementation(() => undefined); vi.spyOn(console, "warn").mockImplementation(() => undefined);
vi.spyOn(RapierCollisionWorld, "create").mockResolvedValue({ vi.spyOn(RapierCollisionWorld, "create").mockResolvedValue({
dispose: vi.fn(), dispose: vi.fn(),
@@ -326,34 +325,30 @@ describe("RuntimeHost", () => {
) )
} as unknown as RapierCollisionWorld); } as unknown as RapierCollisionWorld);
const triggerVolume = createTriggerVolumeEntity({
id: "entity-trigger-main"
});
const document = createEmptySceneDocument(); const document = createEmptySceneDocument();
document.entities[triggerVolume.id] = triggerVolume; const npc = createNpcEntity({
document.dialogues.dialogues["dialogue-warning"] = { id: "entity-npc-operator",
id: "dialogue-warning", dialogues: [
title: "Generator Warning",
lines: [
{ {
id: "dialogue-line-warning-1", id: "dialogue-warning",
speakerName: "Operator", title: "Generator Warning",
text: "The generator is unstable." lines: [
}, {
{ id: "dialogue-line-warning-1",
id: "dialogue-line-warning-2", speakerName: "Operator",
speakerName: null, text: "The generator is unstable."
text: "A low hum fills the room." },
{
id: "dialogue-line-warning-2",
speakerName: null,
text: "A low hum fills the room."
}
]
} }
] ],
}; defaultDialogueId: "dialogue-warning"
document.interactionLinks["link-start-dialogue"] = });
createStartDialogueInteractionLink({ document.entities[npc.id] = npc;
id: "link-start-dialogue",
sourceEntityId: triggerVolume.id,
trigger: "enter",
dialogueId: "dialogue-warning"
});
const runtimeScene = buildRuntimeSceneFromDocument(document); const runtimeScene = buildRuntimeSceneFromDocument(document);
const host = new RuntimeHost({ const host = new RuntimeHost({
@@ -367,8 +362,9 @@ describe("RuntimeHost", () => {
const hostInternals = host as unknown as { const hostInternals = host as unknown as {
createInteractionDispatcher(): { createInteractionDispatcher(): {
startDialogue( startNpcDialogue(
dialogueId: string, npcEntityId: string,
dialogueId: string | null,
source?: { source?: {
kind: "interactionLink" | "npc" | "direct"; kind: "interactionLink" | "npc" | "direct";
sourceEntityId: string | null; sourceEntityId: string | null;
@@ -379,13 +375,12 @@ describe("RuntimeHost", () => {
}; };
}; };
const dispatcher = hostInternals.createInteractionDispatcher(); const dispatcher = hostInternals.createInteractionDispatcher();
const dialogueLink = document.interactionLinks["link-start-dialogue"]!;
dispatcher.startDialogue("dialogue-warning", { dispatcher.startNpcDialogue(npc.id, "dialogue-warning", {
kind: "interactionLink", kind: "npc",
sourceEntityId: dialogueLink.sourceEntityId, sourceEntityId: npc.id,
linkId: dialogueLink.id, linkId: null,
trigger: "enter" trigger: "click"
}); });
host.advanceRuntimeDialogue(); host.advanceRuntimeDialogue();
host.advanceRuntimeDialogue(); host.advanceRuntimeDialogue();
@@ -393,26 +388,28 @@ describe("RuntimeHost", () => {
expect(dialogueStates).toEqual([ expect(dialogueStates).toEqual([
expect.objectContaining({ expect.objectContaining({
dialogueId: "dialogue-warning", dialogueId: "dialogue-warning",
npcEntityId: npc.id,
lineIndex: 0, lineIndex: 0,
speakerName: "Operator", speakerName: "Operator",
text: "The generator is unstable.", text: "The generator is unstable.",
source: { source: {
kind: "interactionLink", kind: "npc",
sourceEntityId: triggerVolume.id, sourceEntityId: npc.id,
linkId: dialogueLink.id, linkId: null,
trigger: "enter" trigger: "click"
} }
}), }),
expect.objectContaining({ expect.objectContaining({
dialogueId: "dialogue-warning", dialogueId: "dialogue-warning",
npcEntityId: npc.id,
lineIndex: 1, lineIndex: 1,
speakerName: null, speakerName: null,
text: "A low hum fills the room.", text: "A low hum fills the room.",
source: { source: {
kind: "interactionLink", kind: "npc",
sourceEntityId: triggerVolume.id, sourceEntityId: npc.id,
linkId: dialogueLink.id, linkId: null,
trigger: "enter" trigger: "click"
} }
}), }),
null null
@@ -421,7 +418,7 @@ describe("RuntimeHost", () => {
host.dispose(); host.dispose();
}); });
it("publishes late dialogue handlers, ignores repeated same-dialogue starts, and replaces with a different dialogue", () => { it("publishes late dialogue handlers, ignores repeated same-NPC dialogue starts, and replaces with a different NPC dialogue", () => {
vi.spyOn(console, "warn").mockImplementation(() => undefined); vi.spyOn(console, "warn").mockImplementation(() => undefined);
vi.spyOn(RapierCollisionWorld, "create").mockResolvedValue({ vi.spyOn(RapierCollisionWorld, "create").mockResolvedValue({
dispose: vi.fn(), dispose: vi.fn(),
@@ -431,28 +428,42 @@ describe("RuntimeHost", () => {
} as unknown as RapierCollisionWorld); } as unknown as RapierCollisionWorld);
const document = createEmptySceneDocument(); const document = createEmptySceneDocument();
document.dialogues.dialogues["dialogue-a"] = { const npcA = createNpcEntity({
id: "dialogue-a", id: "entity-npc-a",
title: "A", dialogues: [
lines: [
{ {
id: "dialogue-line-a-1", id: "dialogue-a",
speakerName: null, title: "A",
text: "First dialogue." lines: [
{
id: "dialogue-line-a-1",
speakerName: null,
text: "First dialogue."
}
]
} }
] ],
}; defaultDialogueId: "dialogue-a"
document.dialogues.dialogues["dialogue-b"] = { });
id: "dialogue-b", const npcB = createNpcEntity({
title: "B", id: "entity-npc-b",
lines: [ dialogues: [
{ {
id: "dialogue-line-b-1", id: "dialogue-b",
speakerName: "Merchant", title: "B",
text: "Second dialogue." lines: [
{
id: "dialogue-line-b-1",
speakerName: "Merchant",
text: "Second dialogue."
}
]
} }
] ],
}; defaultDialogueId: "dialogue-b"
});
document.entities[npcA.id] = npcA;
document.entities[npcB.id] = npcB;
const host = new RuntimeHost({ const host = new RuntimeHost({
enableRendering: false enableRendering: false
@@ -461,8 +472,9 @@ describe("RuntimeHost", () => {
const hostInternals = host as unknown as { const hostInternals = host as unknown as {
createInteractionDispatcher(): { createInteractionDispatcher(): {
startDialogue( startNpcDialogue(
dialogueId: string, npcEntityId: string,
dialogueId: string | null,
source?: { source?: {
kind: "interactionLink" | "npc" | "direct"; kind: "interactionLink" | "npc" | "direct";
sourceEntityId: string | null; sourceEntityId: string | null;
@@ -474,11 +486,11 @@ describe("RuntimeHost", () => {
}; };
const dispatcher = hostInternals.createInteractionDispatcher(); const dispatcher = hostInternals.createInteractionDispatcher();
dispatcher.startDialogue("dialogue-a", { dispatcher.startNpcDialogue(npcA.id, "dialogue-a", {
kind: "interactionLink", kind: "npc",
sourceEntityId: "entity-trigger-a", sourceEntityId: npcA.id,
linkId: "link-dialogue-a", linkId: null,
trigger: "enter" trigger: "click"
}); });
const dialogueStates: Array<RuntimeDialogueState | null> = []; const dialogueStates: Array<RuntimeDialogueState | null> = [];
@@ -486,15 +498,15 @@ describe("RuntimeHost", () => {
dialogueStates.push(dialogue); dialogueStates.push(dialogue);
}); });
dispatcher.startDialogue("dialogue-a", { dispatcher.startNpcDialogue(npcA.id, "dialogue-a", {
kind: "interactionLink",
sourceEntityId: "entity-trigger-a",
linkId: "link-dialogue-a",
trigger: "enter"
});
dispatcher.startDialogue("dialogue-b", {
kind: "npc", kind: "npc",
sourceEntityId: "entity-npc-merchant", sourceEntityId: npcA.id,
linkId: null,
trigger: "click"
});
dispatcher.startNpcDialogue(npcB.id, "dialogue-b", {
kind: "npc",
sourceEntityId: npcB.id,
linkId: null, linkId: null,
trigger: "click" trigger: "click"
}); });
@@ -502,20 +514,22 @@ describe("RuntimeHost", () => {
expect(dialogueStates).toEqual([ expect(dialogueStates).toEqual([
expect.objectContaining({ expect.objectContaining({
dialogueId: "dialogue-a", dialogueId: "dialogue-a",
npcEntityId: npcA.id,
text: "First dialogue.", text: "First dialogue.",
source: { source: {
kind: "interactionLink", kind: "npc",
sourceEntityId: "entity-trigger-a", sourceEntityId: npcA.id,
linkId: "link-dialogue-a", linkId: null,
trigger: "enter" trigger: "click"
} }
}), }),
expect.objectContaining({ expect.objectContaining({
dialogueId: "dialogue-b", dialogueId: "dialogue-b",
npcEntityId: npcB.id,
text: "Second dialogue.", text: "Second dialogue.",
source: { source: {
kind: "npc", kind: "npc",
sourceEntityId: "entity-npc-merchant", sourceEntityId: npcB.id,
linkId: null, linkId: null,
trigger: "click" trigger: "click"
} }