class DialogueTree { public id : string; private nodes : {[id : string] : DialogueNode} = {}; public startNode : DialogueNode = undefined; private repeatChoices : boolean = true; private lastPrintedChoice : Array; public constructor (id : string) { this.id = id; } public addNode (node : DialogueNode) { this.nodes[node.id] = node; if (node.type == NodeType.Node) { this.nodes[node.name] = node; // This is a label! } } public addStartNode (node : DialogueNode) { this.addNode(node); this.startNode = node; } public getNode (id : string) { return this.nodes[id]; } public getNext (node : DialogueNode) { let next = node.getNext(); if (next != undefined) { return this.getNode(next); } } public setRepeatChoices (doIt : boolean) { this.repeatChoices = doIt; } public async execute (startId? : string) { console.debug(Rulebook.getIndentation() + "[DialogueTree] Running " + this.id); Rulebook.increaseIndentation(this); let node : DialogueNode; if (startId == undefined) { node = this.startNode; } else { node = this.getNode(startId); } if (node == undefined) { Elements.CurrentTurnHandler.printAsError("Unable to start dialogue " + this.id + ": A starting node could not be found."); return; } let previousNode : DialogueNode; while (node != undefined) { let nextNode = await this.processNode(node, previousNode); previousNode = node; node = nextNode; } Rulebook.decreaseIndentation(); } public async processNode (node : DialogueNode, previousNode : DialogueNode) { console.debug(Rulebook.getIndentation() + "[" + node.type + "] " + node.id); Rulebook.increaseIndentation(node); let doChoices = node.hasChoices(); if (node.type == NodeType.Tree) { await ( node).tree().execute(); } else if (node.type == NodeType.Text) { let say = ( node).getSay(); Elements.CurrentTurnHandler.printAsContent(say); } else if (node.type == NodeType.Set) { let runningSet = ( node).run(); if (runningSet instanceof Promise) { await runningSet; } } if (doChoices) { // Next node is decided by the choices let branchingDialogue = new BranchingDialogue(); let choices = node.choices; let options = []; for (let i = 0; i < choices.length; i++) { let choice = this.getNode(choices[i]); let branchingOption = new BranchingOption(choice.getSay(), choice.isAvailable()); options.push(branchingOption); branchingDialogue.addOptions(branchingOption); } let chosenOption : BranchingOption = await branchingDialogue.getChosenOption(); let chosenNodeId = choices[options.indexOf(chosenOption)]; let chosenNode = this.getNode(chosenNodeId); if (this.repeatChoices) { let say = new Say(new SayBold(" > ", chosenNode.getSay())); this.lastPrintedChoice = await Elements.CurrentTurnHandler.getSayElementsAsContent(say); await Elements.CurrentTurnHandler.print(...this.lastPrintedChoice); } console.debug(Rulebook.getIndentation() + "[Choice] Picked " + chosenNodeId); console.debug(Rulebook.getIndentation() + "[Choice] Going to " + chosenNode.getNext()); Rulebook.increaseIndentation(chosenNodeId); Rulebook.decreaseIndentation(); Rulebook.decreaseIndentation(); return this.getNext(chosenNode); } else { Rulebook.decreaseIndentation(); return this.getNext(node); } } public unprintLastChoice () { Elements.CurrentTurnHandler.unprint(...this.lastPrintedChoice); } }