// Executes a node. Use this in a for-each construct; each time you iterate over it, // you'll get a line, command, or set of options. public IEnumerable<Yarn.Dialogue.RunnerResult> Run(string startNode = DEFAULT_START) { stopExecuting = false; var runner = new Runner (this); if (LogDebugMessage == null) { throw new YarnException ("LogDebugMessage must be set before running"); } if (LogErrorMessage == null) { throw new YarnException ("LogErrorMessage must be set before running"); } var nextNode = startNode; do { LogDebugMessage ("Running node " + nextNode); Parser.Node node; try { node = loader.nodes [nextNode]; } catch (KeyNotFoundException) { LogErrorMessage ("Can't find node " + nextNode); yield break; } foreach (var result in runner.RunNode(node)) { // Is it the special custom command "<<stop>>"? if (result is CommandResult && (result as CommandResult).command.text == "stop") { yield break; } // Did we get our stop flag set? if (stopExecuting) { yield break; } // Are we now done with this node? if (result is NodeCompleteResult) { var nodeComplete = result as NodeCompleteResult; // Move to the next node (or to null) nextNode = nodeComplete.nextNode; // NodeComplete is not interactive, so skip immediately to next step // (which should end this loop) continue; } yield return result; } // Register that we've finished with this node. We do this // after running the node, not before, so that "visited("Node")" can // be called in "Node" itself, and fail. This lets you check to see // if, for example, this is the first time you've run this node, without // having to add extra variables to keep track of state. visitedNodeNames.Add(node.name); } while (nextNode != null); LogDebugMessage ("Run complete."); }