Update dialogue tests to use NPC entities
This commit is contained in:
@@ -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"
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user