Beispiel #1
0
        /// <summary>Creates the story from the file contents.</summary>
        /// <param name="fileContent">Content of the file.</param>
        /// <param name="options">The options.</param>
        /// <param name="compiler">The compiler.</param>
        /// <param name="compileSuccess">if set to <c>true</c> [compile success].</param>
        /// <param name="finished">if set to <c>true</c> [finished].</param>
        /// <returns></returns>
        public Runtime.IStory CreateStory(string fileContent, CommandLineToolOptions options, out Parsed.Fiction parsedFiction)
        {
            Runtime.IStory story = null;

            if (!options.IsInputFileJson)
            {
                // Loading a normal ink file (as opposed to an already compiled JSON file)
                var compiler = CreateCompiler(fileContent, options);

                if (options.IsOnlyShowJsonStatsActive)
                {
                    ShowStats(compiler, options);
                    parsedFiction = null;
                }
                else
                {
                    //Parsed.Fiction parsedFiction = null;
                    // Full compile
                    story = compiler.Compile(out parsedFiction);
                }
            }
            else
            {
                story         = CreateStoryFromJson(fileContent, options);
                parsedFiction = null;
            }

            return(story);
        }
        /// <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>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);
        }
Beispiel #4
0
 public void RetrieveDebugSourceForLatestContent(Runtime.IStory runtimeStory)
 {
     foreach (var outputObj in runtimeStory.state.outputStream)
     {
         var textContent = outputObj as Runtime.StringValue;
         if (textContent != null)
         {
             var range = new DebugSourceRange();
             range.length        = textContent.value.Length;
             range.debugMetadata = textContent.debugMetadata;
             range.text          = textContent.value;
             DebugSourceRanges.Add(range);
         }
     }
 }
Beispiel #5
0
        /// <summary>Writes the compiled story to a JSON file.</summary>
        /// <param name="story">The story.</param>
        /// <param name="options">The options.</param>
        public void WriteStoryToJsonFile(Runtime.IStory story, CommandLineToolOptions options)
        {
            // Compile mode
            var jsonStr = story.ToJson();

            try
            {
                FileSystemInteractor.WriteAllTextToFile(options.RootedOutputFilePath, jsonStr, System.Text.Encoding.UTF8);

                OutputManager.ShowExportComplete(options);
            }
            catch
            {
                ConsoleInteractor.WriteErrorMessage("Could not write to output file '{0}'", options.RootedOutputFilePath);
                ConsoleInteractor.EnvironmentExitWithCodeError1();
            }
        }
Beispiel #6
0
        /// <summary>Plays the story.</summary>
        /// <param name="story">The story.</param>
        /// <param name="compiler">The compiler.</param>
        /// <param name="options">The options.</param>
        /// <exception cref="Exception"></exception>
        public void PlayStory(Runtime.IStory story, Parsed.Fiction parsedFiction, CommandLineToolOptions options)
        {
            // Always allow ink external fall-backs
            story.allowExternalFunctionFallbacks = true;

            //Capture a CTRL+C key combo so we can restore the console's foreground color back to normal when exiting
            ConsoleInteractor.ResetColorOnCancelKeyPress();

            try
            {
                ConsoleUserInterfaceOptions uiOptions = new ConsoleUserInterfaceOptions()
                {
                    IsAutoPlayActive = false,
                    IsKeepRunningAfterStoryFinishedNeeded = options.IsKeepRunningAfterStoryFinishedNeeded,
                    IsJsonOutputNeeded = options.IsJsonOutputNeeded
                };
                UserInterface.Begin(story, parsedFiction, uiOptions);
            }
            catch (Runtime.StoryException e)
            {
                if (e.Message.Contains("Missing function binding"))
                {
                    Errors.Add(e.Message);

                    // If you get an error while playing, just print immediately
                    PrintAllMessages();
                }
                else
                {
                    throw e;
                }
            }
            catch (Exception e)
            {
                string storyPath = "<END>";
                var    path      = story.state.currentPathString;
                if (path != null)
                {
                    storyPath = path.ToString();
                }
                throw new Exception(e.Message + " (Internal story path: " + storyPath + ")", e);
            }
        }
        /// <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);
        }
        /// <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>Processes the command line input result.</summary>
        /// <param name="uiResult">The UI result.</param>
        /// <param name="result">The result.</param>
        /// <param name="choiceCount">The choices counted.</param>
        public virtual void ProcessCommandLineInputResult(UserInteractionResult uiResult, InputInterpretationResult result, Runtime.IStory runtimeStory)
        {
            if (uiResult == null || result == null)
            {
                return;
            }

            uiResult.IsExitRequested = result.requestsExit;
            uiResult.ChosenIndex     = result.choiceIdx;
            uiResult.DivertedPath    = result.divertedPath;
            uiResult.Output          = result.output;

            int choiceCount = 0;

            if (runtimeStory != null && runtimeStory.currentChoices != null)
            {
                choiceCount = runtimeStory.currentChoices.Count;
            }

            if (result.choiceIdx >= 0 && result.choiceIdx < choiceCount)
            {
                // The choice is only valid if it's a valid index.
                uiResult.IsValidChoice = true;
            }
        }
Beispiel #10
0
        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);
        }