protected void OutputRemove(StoryOutput output) { if (this.Output.Remove(output)) { if (OnOutputRemoved != null) { OnOutputRemoved(output); } OutputUpdateIndexes(output.Index); } }
void OutputSend(StoryOutput output, bool add = false) { if (_groupStack.Count > 0) { output.Group = _groupStack.Peek(); } if (add) { OutputAdd(output); } if (OnOutput != null) { OnOutput(output); } }
void OutputAdd(StoryOutput output) { // Insert the output into the right place int insertIndex = InsertStack.Count > 0 ? InsertStack.Peek() : -1; if (insertIndex < 0) { output.Index = this.Output.Count; this.Output.Add(output); } else { // When a valid insert index is specified, update the following outputs' index output.Index = insertIndex; this.Output.Insert(insertIndex, output); OutputUpdateIndexes(insertIndex + 1); } // Increase the topmost index if (InsertStack.Count > 0 && insertIndex >= 0) { InsertStack.Push(InsertStack.Pop() + 1); } }
/// <summary> /// Executes the current thread by advancing its enumerator, sending its output and invoking cues. /// </summary> void ExecuteCurrentThread() { Abort aborted = null; UpdateCuesRefresh(); while (_currentThread.MoveNext()) { StoryOutput output = _currentThread.Current; // If output is not null, process it. Otherwise, just check if story was paused and continue if (output != null) { // Abort this thread if (output is Abort) { aborted = (Abort)output; break; } OutputAdd(output); // Let the handlers and cues kick in if (output is EmbedPassage) { CuesInvoke(CuesGet(output.Name, CueType.Enter)); UpdateCuesRefresh(); } // Send output OutputSend(output); CuesInvoke(CuesFind(CueType.Output), output); } // Story was paused, wait for it to resume if (this.State == StoryState.Paused) { _lastThreadResult = ThreadResult.InProgress; return; } } _currentThread.Dispose(); _currentThread = null; _lastThreadResult = ThreadResult.Done; this.State = StoryState.Idle; // Next passage, if any, will either be a goto or a link string goToPassage = aborted != null ? aborted.GoToPassage : CurrentLinkInAction != null ? CurrentLinkInAction.PassageName : null; // Invoke the general passage enter event if (this.OnPassageDone != null) { this.OnPassageDone(this.CurrentPassage); } // Invoke the done cue - either for main or for a link if (CurrentLinkInAction == null) { CuesInvoke(CuesFind(CueType.Done)); } else { CuesInvoke(CuesFind(CueType.Done, CurrentLinkInAction.Name)); CurrentLinkInAction = null; NumberOfLinksDone++; } // Now that the link is done, go to its passage if (goToPassage != null) { GoTo(goToPassage); } }
/// <summary> /// Executes the current thread by advancing its enumerator, sending its output and invoking cues. /// </summary> void ExecuteCurrentThread() { Abort aborted = null; UpdateCuesRefresh(); while (_currentThread.MoveNext()) { StoryOutput output = _currentThread.Current; // If output is not null, process it. Otherwise, just check if story was paused and continue if (output != null) { // Abort this thread if (output is Abort) { aborted = (Abort)output; break; } OutputAdd(output); // Let the handlers and cues kick in if (output is EmbedPassage) { CuesInvoke(CuesGet(output.Name, "Enter")); UpdateCuesRefresh(); } // Send output OutputSend(output); CuesInvoke(CuesFind("Output"), output); } // Story was paused, wait for it to resume if (this.State == StoryState.Paused) { _lastThreadResult = ThreadResult.InProgress; return; } } _currentThread.Dispose(); _currentThread = null; this.State = StoryState.Idle; // Return the appropriate result if (aborted != null) { CuesInvoke(CuesFind("Aborted")); _lastThreadResult = ThreadResult.Aborted; } else { // Invoke the done cue - either for main or for a link if (CurrentLinkInAction == null) { CuesInvoke(CuesFind("Done")); } else { CuesInvoke(CuesFind("Done", CurrentLinkInAction.Name)); } _lastThreadResult = ThreadResult.Done; } CurrentLinkInAction = null; if (aborted != null && aborted.GoToPassage != null) { this.GoTo(aborted.GoToPassage); } }