Add trigger field to dialogue source and update tests

This commit is contained in:
2026-04-14 21:19:30 +02:00
parent dfdffdda1c
commit 77eff081ac

View File

@@ -287,6 +287,7 @@ describe("RuntimeHost", () => {
kind: "interactionLink" | "npc" | "direct"; kind: "interactionLink" | "npc" | "direct";
sourceEntityId: string | null; sourceEntityId: string | null;
linkId: string | null; linkId: string | null;
trigger: "enter" | "exit" | "click" | null;
} }
): void; ): void;
}; };
@@ -297,7 +298,8 @@ describe("RuntimeHost", () => {
dispatcher.startDialogue("dialogue-warning", { dispatcher.startDialogue("dialogue-warning", {
kind: "interactionLink", kind: "interactionLink",
sourceEntityId: dialogueLink.sourceEntityId, sourceEntityId: dialogueLink.sourceEntityId,
linkId: dialogueLink.id linkId: dialogueLink.id,
trigger: "enter"
}); });
host.advanceRuntimeDialogue(); host.advanceRuntimeDialogue();
host.advanceRuntimeDialogue(); host.advanceRuntimeDialogue();
@@ -311,7 +313,8 @@ describe("RuntimeHost", () => {
source: { source: {
kind: "interactionLink", kind: "interactionLink",
sourceEntityId: triggerVolume.id, sourceEntityId: triggerVolume.id,
linkId: dialogueLink.id linkId: dialogueLink.id,
trigger: "enter"
} }
}), }),
expect.objectContaining({ expect.objectContaining({
@@ -322,7 +325,8 @@ describe("RuntimeHost", () => {
source: { source: {
kind: "interactionLink", kind: "interactionLink",
sourceEntityId: triggerVolume.id, sourceEntityId: triggerVolume.id,
linkId: dialogueLink.id linkId: dialogueLink.id,
trigger: "enter"
} }
}), }),
null null
@@ -377,6 +381,7 @@ describe("RuntimeHost", () => {
kind: "interactionLink" | "npc" | "direct"; kind: "interactionLink" | "npc" | "direct";
sourceEntityId: string | null; sourceEntityId: string | null;
linkId: string | null; linkId: string | null;
trigger: "enter" | "exit" | "click" | null;
} }
): void; ): void;
}; };
@@ -386,7 +391,8 @@ describe("RuntimeHost", () => {
dispatcher.startDialogue("dialogue-a", { dispatcher.startDialogue("dialogue-a", {
kind: "interactionLink", kind: "interactionLink",
sourceEntityId: "entity-trigger-a", sourceEntityId: "entity-trigger-a",
linkId: "link-dialogue-a" linkId: "link-dialogue-a",
trigger: "enter"
}); });
const dialogueStates: Array<RuntimeDialogueState | null> = []; const dialogueStates: Array<RuntimeDialogueState | null> = [];
@@ -397,12 +403,14 @@ describe("RuntimeHost", () => {
dispatcher.startDialogue("dialogue-a", { dispatcher.startDialogue("dialogue-a", {
kind: "interactionLink", kind: "interactionLink",
sourceEntityId: "entity-trigger-a", sourceEntityId: "entity-trigger-a",
linkId: "link-dialogue-a" linkId: "link-dialogue-a",
trigger: "enter"
}); });
dispatcher.startDialogue("dialogue-b", { dispatcher.startDialogue("dialogue-b", {
kind: "npc", kind: "npc",
sourceEntityId: "entity-npc-merchant", sourceEntityId: "entity-npc-merchant",
linkId: null linkId: null,
trigger: "click"
}); });
expect(dialogueStates).toEqual([ expect(dialogueStates).toEqual([
@@ -412,7 +420,8 @@ describe("RuntimeHost", () => {
source: { source: {
kind: "interactionLink", kind: "interactionLink",
sourceEntityId: "entity-trigger-a", sourceEntityId: "entity-trigger-a",
linkId: "link-dialogue-a" linkId: "link-dialogue-a",
trigger: "enter"
} }
}), }),
expect.objectContaining({ expect.objectContaining({
@@ -421,7 +430,8 @@ describe("RuntimeHost", () => {
source: { source: {
kind: "npc", kind: "npc",
sourceEntityId: "entity-npc-merchant", sourceEntityId: "entity-npc-merchant",
linkId: null linkId: null,
trigger: "click"
} }
}) })
]); ]);
@@ -429,6 +439,76 @@ describe("RuntimeHost", () => {
host.dispose(); host.dispose();
}); });
it("does not consume a trigger-started one-line dialogue on the immediate next click", () => {
vi.spyOn(console, "warn").mockImplementation(() => undefined);
vi.spyOn(RapierCollisionWorld, "create").mockResolvedValue({
dispose: vi.fn(),
resolveThirdPersonCameraCollision: vi.fn(
(_pivot, desiredCameraPosition) => desiredCameraPosition
)
} as unknown as RapierCollisionWorld);
const document = createEmptySceneDocument();
document.dialogues.dialogues["dialogue-trigger"] = {
id: "dialogue-trigger",
title: "Trigger",
lines: [
{
id: "dialogue-line-trigger-1",
speakerName: null,
text: "Triggered."
}
]
};
const host = new RuntimeHost({
enableRendering: false
});
host.loadScene(buildRuntimeSceneFromDocument(document));
const hostInternals = host as unknown as {
createInteractionDispatcher(): {
startDialogue(
dialogueId: string,
source?: {
kind: "interactionLink" | "npc" | "direct";
sourceEntityId: string | null;
linkId: string | null;
trigger: "enter" | "exit" | "click" | null;
}
): void;
};
sceneReady: boolean;
runtimeScene: unknown;
activeController: unknown;
thirdPersonController: unknown;
handleRuntimeClick(): void;
currentDialogue: RuntimeDialogueState | null;
};
hostInternals.sceneReady = true;
hostInternals.activeController = hostInternals.thirdPersonController;
const dispatcher = hostInternals.createInteractionDispatcher();
dispatcher.startDialogue("dialogue-trigger", {
kind: "interactionLink",
sourceEntityId: "entity-trigger-main",
linkId: "link-trigger-dialogue",
trigger: "enter"
});
hostInternals.handleRuntimeClick();
expect(hostInternals.currentDialogue).toEqual(
expect.objectContaining({
dialogueId: "dialogue-trigger"
})
);
hostInternals.handleRuntimeClick();
expect(hostInternals.currentDialogue).toBeNull();
host.dispose();
});
it("applies expanded typed control effects for model, sound, and scene lighting", () => { it("applies expanded typed control effects for model, sound, and scene lighting", () => {
vi.spyOn(console, "warn").mockImplementation(() => undefined); vi.spyOn(console, "warn").mockImplementation(() => undefined);
vi.spyOn(RapierCollisionWorld, "create").mockResolvedValue({ vi.spyOn(RapierCollisionWorld, "create").mockResolvedValue({