102 lines
2.4 KiB
JavaScript
102 lines
2.4 KiB
JavaScript
/**
|
|
* NarrativeManager.js
|
|
* Manages the flow of story events, dialogue, and tutorials.
|
|
* Extends EventTarget to broadcast UI updates.
|
|
*/
|
|
export class NarrativeManager extends EventTarget {
|
|
constructor() {
|
|
super();
|
|
this.currentSequence = null;
|
|
this.currentNode = null;
|
|
this.history = new Set(); // Track played sequences IDs
|
|
}
|
|
|
|
/**
|
|
* Loads and starts a narrative sequence.
|
|
* @param {Object} sequenceData - The JSON object of the conversation.
|
|
*/
|
|
startSequence(sequenceData) {
|
|
if (!sequenceData || !sequenceData.nodes) {
|
|
console.error("Invalid sequence data");
|
|
return;
|
|
}
|
|
|
|
console.log(`Starting Narrative: ${sequenceData.id}`);
|
|
this.currentSequence = sequenceData;
|
|
this.history.add(sequenceData.id);
|
|
|
|
// Find first node (usually index 0 or id '1')
|
|
this.currentNode = sequenceData.nodes[0];
|
|
this.broadcastUpdate();
|
|
}
|
|
|
|
/**
|
|
* Advances to the next node in the sequence.
|
|
*/
|
|
next() {
|
|
if (!this.currentNode) return;
|
|
|
|
// 1. Handle Triggers (Side Effects)
|
|
if (this.currentNode.trigger) {
|
|
this.dispatchEvent(
|
|
new CustomEvent("narrative-trigger", {
|
|
detail: { action: this.currentNode.trigger },
|
|
})
|
|
);
|
|
}
|
|
|
|
// 2. Find Next Node
|
|
const nextId = this.currentNode.next;
|
|
|
|
if (nextId === "END" || !nextId) {
|
|
this.endSequence();
|
|
} else {
|
|
this.currentNode = this.currentSequence.nodes.find(
|
|
(n) => n.id === nextId
|
|
);
|
|
this.broadcastUpdate();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles player choice selection.
|
|
*/
|
|
makeChoice(choiceIndex) {
|
|
if (!this.currentNode.choices) return;
|
|
|
|
const choice = this.currentNode.choices[choiceIndex];
|
|
const nextId = choice.next;
|
|
|
|
if (choice.trigger) {
|
|
this.dispatchEvent(
|
|
new CustomEvent("narrative-trigger", {
|
|
detail: { action: choice.trigger },
|
|
})
|
|
);
|
|
}
|
|
|
|
this.currentNode = this.currentSequence.nodes.find((n) => n.id === nextId);
|
|
this.broadcastUpdate();
|
|
}
|
|
|
|
endSequence() {
|
|
console.log("Narrative Ended");
|
|
this.currentSequence = null;
|
|
this.currentNode = null;
|
|
this.dispatchEvent(new CustomEvent("narrative-end"));
|
|
}
|
|
|
|
broadcastUpdate() {
|
|
this.dispatchEvent(
|
|
new CustomEvent("narrative-update", {
|
|
detail: {
|
|
node: this.currentNode,
|
|
active: !!this.currentNode,
|
|
},
|
|
})
|
|
);
|
|
}
|
|
}
|
|
|
|
// Export singleton for global access
|
|
export const narrativeManager = new NarrativeManager();
|