aether-shards/test/managers/NarrativeManager.js

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();