/// <summary>Runs the story until continuation point.</summary> /// <param name="story">The story.</param> /// <param name="parsedFiction"></param> /// <param name="options">The options.</param> /// <returns></returns> public virtual bool RunStoryUntilContinuationPoint(Runtime.IStory story, Parsed.IFiction parsedFiction, ConsoleUserInterfaceOptions options) { if (story == null) { return(false); } var choices = story.currentChoices; bool isAutoPlayActive = options != null ? options.IsAutoPlayActive : false; if (isAutoPlayActive) { // autoPlay: Pick random choice var choiceIndex = ChoiceGenerator.GetRandomChoice(choices.Count); ConsoleInteractor.ResetConsoleColor(); } else { // Normal: Ask user for choice number OutputManager.ShowChoices(choices, options); var uiResult = GetPropperUserInteractionResult(story, parsedFiction, options); ConsoleInteractor.ResetConsoleColor(); if (uiResult == null) { return(false); } else if (uiResult.IsInputStreamClosed) { return(false); } else if (uiResult.IsValidChoice) { story.ChooseChoiceIndex(uiResult.ChosenIndex); } else if (uiResult.DivertedPath != null) { story.ChoosePathString(uiResult.DivertedPath); uiResult.DivertedPath = null; } } EvaluateStory(story, options); return(true); }
/// <summary>Begins the user interaction with the specified story.</summary> /// <param name="story">The story.</param> /// <param name="parsedFiction"></param> /// <param name="options">The options.</param> public void Begin(Runtime.IStory story, Parsed.IFiction parsedFiction, ConsoleUserInterfaceOptions options) { if (story == null || parsedFiction == null) { return; } SetOutputFormat(options); // Add a handler for the story errors story.StoryError += StoryErrorHandler; EvaluateStory(story, options); bool continueAfterThisPoint = true; bool isKeepRunningAfterStoryFinishedNeeded = options != null ? options.IsKeepRunningAfterStoryFinishedNeeded : false; while (continueAfterThisPoint && (story.HasCurrentChoices || isKeepRunningAfterStoryFinishedNeeded)) { continueAfterThisPoint = RunStoryUntilContinuationPoint(story, parsedFiction, options); } }
/// <summary>Gets a proper user interaction result.</summary> /// <param name="runtimeStory"></param> /// <param name="parsedFiction"></param> /// <param name="options">The options.</param> /// <returns></returns> public virtual UserInteractionResult GetPropperUserInteractionResult(Runtime.IStory runtimeStory, Parsed.IFiction parsedFiction, ConsoleUserInterfaceOptions options) { UserInteractionResult uiResult; do { uiResult = GetUserInteractionResult(runtimeStory, parsedFiction, options); }while (!(uiResult == null || // if the uiResult is null something is seriously wrong and we stop asking and go on. uiResult.IsInputStreamClosed || // We keep asking the user again for input as long as the stream is active uiResult.IsExitRequested || // no exit is requested uiResult.IsValidChoice || // no valid choice was made uiResult.DivertedPath != null)); // and no diverted path was present return(uiResult); }
/// <summary>Gets the user interaction result.</summary> /// <param name="runtimeStory"></param> /// <param name="parsedFiction"></param> /// <param name="options">The options.</param> /// <returns></returns> public virtual UserInteractionResult GetUserInteractionResult(Runtime.IStory runtimeStory, Parsed.IFiction parsedFiction, ConsoleUserInterfaceOptions options) { var uiResult = new UserInteractionResult(); OutputManager.RequestInput(options); var userInput = OutputManager.GetUserInput(); // If we have null user input, it means that we're // "at the end of the stream", or in other words, the input // stream has closed, so there's nothing more we can do. // We return immediately, since otherwise we get into a busy // loop waiting for user input. if (userInput == null) { OutputManager.ShowStreamError(options); uiResult.IsInputStreamClosed = true; } else { var result = Interpreter.InterpretCommandLineInput(userInput, parsedFiction, runtimeStory); if (result == null) { return(null); } ProcessCommandLineInputResult(uiResult, result, runtimeStory); if (uiResult.Output != null) { OutputManager.ShowOutputResult(result, options); } if (!uiResult.IsValidChoice) { // The choice is only valid if it's a valid index. OutputManager.ShowChoiceOutOffRange(options); } } return(uiResult); }
public InputInterpretationResult InterpretCommandLineInput(string userInput, Parsed.IFiction parsedFiction, Runtime.IStory runtimeStory) { var inputParser = new InkParser.InkParser(userInput); var inputResult = inputParser.CommandLineUserInput(); var result = new InputInterpretationResult(); if (inputResult.choiceInput != null) { // Choice result.choiceIdx = ((int)inputResult.choiceInput) - 1; } else if (inputResult.isHelp) { // Help result.output = "Type a choice number, a divert (e.g. '-> myKnot'), an expression, or a variable assignment (e.g. 'x = 5')"; } else if (inputResult.isExit) { // Quit result.requestsExit = true; } else if (inputResult.debugSource != null) { // Request for debug source line number var offset = (int)inputResult.debugSource; var dm = DebugMetadataForContentAtOffset(offset); if (dm != null) { result.output = "DebugSource: " + dm.ToString(); } else { result.output = "DebugSource: Unknown source"; } } else if (inputResult.debugPathLookup != null) { // Request for runtime path lookup (to line number) var pathStr = inputResult.debugPathLookup; var contentResult = runtimeStory.ContentAtPath(new Runtime.Path(pathStr)); var dm = contentResult.obj.debugMetadata; if (dm != null) { result.output = "DebugSource: " + dm.ToString(); } else { result.output = "DebugSource: Unknown source"; } } else if (inputResult.userImmediateModeStatement != null) { // User entered some ink var parsedObj = inputResult.userImmediateModeStatement as Parsed.Object; // Variable assignment: create in Parsed.Story as well as the Runtime.Story // so that we don't get an error message during reference resolution if (parsedObj is Parsed.VariableAssignment) { var varAssign = (Parsed.VariableAssignment)parsedObj; if (varAssign.isNewTemporaryDeclaration) { parsedFiction.TryAddNewVariableDeclaration(varAssign); } } parsedObj.parent = (Parsed.Object)parsedFiction; var runtimeObj = parsedObj.runtimeObject; parsedObj.ResolveReferences(parsedFiction); if (!parsedFiction.hadError) { // Divert if (parsedObj is Parsed.Divert) { var parsedDivert = parsedObj as Parsed.Divert; result.divertedPath = parsedDivert.runtimeDivert.targetPath.ToString(); } // Expression or variable assignment else if (parsedObj is Parsed.Expression || parsedObj is Parsed.VariableAssignment) { var evalResult = runtimeStory.EvaluateExpression((Runtime.Container)runtimeObj); if (evalResult != null) { result.output = evalResult.ToString(); } } } else { parsedFiction.ResetError(); } } else { result.output = "Unexpected input. Type 'help' or a choice number."; } return(result); }