예제 #1
0
        /// <summary>
        /// Called after the current node or the index of the current dialogue entry has changed.
        /// </summary>
        /// <remarks>
        /// Trigger events according to the current game state and how it is changed
        /// </remarks>
        /// <param name="nodeChanged"></param>
        /// <param name="dialogueChanged"></param>
        /// <param name="firstEntryOfNode"></param>
        /// <param name="dialogueStepped"></param>
        private void UpdateGameState(bool nodeChanged, bool dialogueChanged, bool firstEntryOfNode,
                                     bool dialogueStepped)
        {
            // Debug.LogFormat("UpdateGameState begin {0} {1} {2}", stepNumFromLastCheckpoint, restrainCheckpoint, forceCheckpoint);

            if (nodeChanged)
            {
                // Debug.Log($"Nova: node changed to {currentNode.name}");

                if (firstEntryOfNode)
                {
                    EnsureCheckpoint();                   // always get a checkpoint at the beginning of the node
                }
                NodeChanged?.Invoke(new NodeChangedData(currentNode.name));
            }

            if (dialogueChanged)
            {
                this.RuntimeAssert(currentIndex >= 0 && currentIndex < currentNode.dialogueEntryCount,
                                   "Dialogue index out of range.");

                if (!firstEntryOfNode && dialogueStepped)
                {
                    stepNumFromLastCheckpoint++;
                }

                var gameStateRestoreEntry = checkpointManager.IsReached(currentNode.name, currentIndex, variables.hash);
                if (gameStateRestoreEntry == null)
                {
                    // Tell the checkpoint manager a new dialogue entry has been reached
                    checkpointManager.SetReached(currentNode.name, currentIndex, variables,
                                                 GetGameStateStepRestoreEntry());
                }

                // Change states after creating or restoring from checkpoint
                if (shouldSaveRealCheckpoint)
                {
                    stepNumFromLastCheckpoint = 0;
                }

                if (gameStateRestoreEntry != null)
                {
                    this.RuntimeAssert(stepNumFromLastCheckpoint == gameStateRestoreEntry.stepNumFromLastCheckpoint,
                                       $"StepNumFromLastCheckpoint mismatch: {stepNumFromLastCheckpoint} {gameStateRestoreEntry.stepNumFromLastCheckpoint}");
                    this.RuntimeAssert(restrainCheckpoint == gameStateRestoreEntry.restrainCheckpointNum,
                                       $"RestrainCheckpointNum mismatch: {restrainCheckpoint} {gameStateRestoreEntry.restrainCheckpointNum}");
                }

                if (checkpointRestrained)
                {
                    restrainCheckpoint--;
                    if (restrainCheckpoint == 1)
                    {
                        Debug.LogWarning($"Nova: restrainCheckpoint reaches 1");
                    }
                }

                // As the action for this dialogue will be re-run, it's fine to just reset forceCheckpoint to false
                forceCheckpoint = false;

                DialogueWillChange?.Invoke();

                state = State.ActionRunning;
                lastVariablesHashBeforeAction = variables.hash;
                currentDialogueEntry          = currentNode.GetDialogueEntryAt(currentIndex);
                currentDialogueEntry.ExecuteAction();
                StartCoroutine(WaitActionEnd(gameStateRestoreEntry != null));
            }

            // Debug.LogFormat("UpdateGameState end {0} {1} {2} {3}", stepNumFromLastCheckpoint, restrainCheckpoint, forceCheckpoint, currentDialogueEntry?.displayData.FormatNameDialogue());
        }
예제 #2
0
 /// <summary>
 /// Add a dialogue entry to the end of the dialogue entry list
 /// </summary>
 /// <param name="entry"></param>
 public void AddDialogueEntry(DialogueEntry entry)
 {
     CheckFreeze();
     dialogueEntries.Add(entry);
 }
예제 #3
0
        public static DialogueEntry[] ParseDialogueEntries(string[] dialogueEntryTexts)
        {
            var indexToCode = new string[dialogueEntryTexts.Length];
            var indexToText = new string[dialogueEntryTexts.Length];
            var indexToAdditionalActions = new Dictionary <int, string>();

            for (int i = 0; i < dialogueEntryTexts.Length; ++i)
            {
                ParseText(dialogueEntryTexts[i], out string code, out string text);
                indexToCode[i] = code;
                indexToText[i] = text;
                if (!string.IsNullOrEmpty(code))
                {
                    GenerateAdditionalActions(code, out string preloadActions, out string unpreloadActions,
                                              out string forceCheckpointActions);
                    CombineActions(indexToAdditionalActions, Math.Max(i - PreloadDialogueSteps, 0), preloadActions);
                    CombineActions(indexToAdditionalActions, i, unpreloadActions);

                    // The first entry of a node must have a real checkpoint, so no need to force here
                    if (i > 0)
                    {
                        CombineActions(indexToAdditionalActions, i - 1, forceCheckpointActions);
                    }
                }
            }

            var results = new DialogueEntry[dialogueEntryTexts.Length];

            for (int i = 0; i < dialogueEntryTexts.Length; ++i)
            {
                string code = indexToCode[i];
                string text = indexToText[i];
                indexToAdditionalActions.TryGetValue(i, out string additionalActions);

                var    m = Regex.Match(text, @"(.*?)(?:::|::)(.*)");
                string characterName, dialogue;
                if (m.Success)
                {
                    characterName = m.Groups[1].Value;
                    dialogue      = m.Groups[2].Value;
                }
                else
                {
                    characterName = "";
                    dialogue      = text;
                }

                LuaFunction action       = null;
                string      combinedCode = string.Format(ActionBeforeLazyBlock, characterName)
                                           + (code ?? "")
                                           + (additionalActions ?? "")
                                           + string.Format(ActionAfterLazyBlock, characterName);
                if (!string.IsNullOrEmpty(combinedCode))
                {
                    action = LuaRuntime.Instance.WrapClosure(combinedCode);
                    if (action == null)
                    {
                        throw new Exceptions.ScriptParseException(
                                  $"Syntax error while parsing lazy execution block:\nText: {text}\nCode: {combinedCode}");
                    }
                }

                // TODO: there may be some grammar to set different internal and displayed character names
                results[i] = new DialogueEntry(characterName, characterName, dialogue, action);
            }

            return(results);
        }