private IEnumerator UpdateDialogue(bool firstEntryOfNode, bool dialogueStepped, bool fromCheckpoint, Action onFinish) { if (!fromCheckpoint) { // If the following lines of code are put into a new coroutine, one frame's delay will be introduced, // so don't do that currentDialogueEntry.ExecuteAction(DialogueActionStage.BeforeCheckpoint, isRestoring); while (actionPauseLock.isLocked) { yield return(null); } } DialogueSaveCheckpoint(firstEntryOfNode, dialogueStepped, out var isReached, out var isReachedAnyHistory); dialogueWillChange.Invoke(new DialogueWillChangeData()); currentDialogueEntry.ExecuteAction(DialogueActionStage.Default, isRestoring); while (actionPauseLock.isLocked) { yield return(null); } dialogueChanged.Invoke(new DialogueChangedData(nodeHistory.Last(), currentIndex, currentDialogueEntry.GetDisplayData(), new Dictionary <string, VoiceEntry>(voicesNextDialogue), isReached, isReachedAnyHistory)); voicesNextDialogue.Clear(); currentDialogueEntry.ExecuteAction(DialogueActionStage.AfterDialogue, isRestoring); while (actionPauseLock.isLocked) { yield return(null); } if (advancedDialogueHelper.GetFallThrough()) { Step(Utils.WrapActionWithParameter <bool>(onFinish)); yield break; } var pendingJumpTarget = advancedDialogueHelper.GetJump(); if (pendingJumpTarget != null) { var node = flowChartTree.GetNode(pendingJumpTarget); this.RuntimeAssert(node != null, $"Node {pendingJumpTarget} not found."); MoveToNextNode(node, onFinish); yield break; } onFinish?.Invoke(); }
/// <summary> /// Called after the current node or the index of the current dialogue entry has changed. /// </summary> /// <remarks> /// The game state will be updated according to the current node and current dialogue index. /// This method will execute the action in the new current dialogue entry and informs all game state listeners /// Since the action inside the dialogue entry will be executed, this method should not be called twice /// if only one update has happen /// </remarks> private void UpdateGameState() { currentDialogueEntry = currentNode.GetDialogueEntryAt(currentIndex); DialogueWillChange.Invoke(); currentDialogueEntry.ExecuteAction(); DialogueChanged.Invoke( new DialogueChangedEventData(currentNode.name, currentIndex, currentDialogueEntry.text, voicesOfNextDialogue)); voicesOfNextDialogue.Clear(); }
/// <summary> /// Called after the current node or the index of the current dialogue entry has changed. /// </summary> /// <remarks> /// The game state will be updated according to walkedThroughNodes and current dialogue index. /// This method will check if the game state has changed and trigger proper events /// </remarks> /// <param name="forceRefreshDialogue">refresh dialogue no matter the game state has change or not</param> /// <param name="forceRefreshNode">refresh the node no matter the node has changed or not</param> private void UpdateGameState(bool forceRefreshDialogue = false, bool forceRefreshNode = false) { Assert.IsFalse(walkedThroughNodes.Count == 0, "Nova: walkedThroughNodes is empty, can not update game state."); // update current node var desiredNodeName = walkedThroughNodes.Last(); var nodeChanged = currentNode == null || currentNode.name != desiredNodeName; if (nodeChanged || forceRefreshNode) { currentNode = flowChartTree.FindNode(desiredNodeName); if (NodeChanged != null) { NodeChanged.Invoke(new NodeChangedData(currentNode.name, currentNode.description)); } } // update dialogue var dialogueChanged = nodeChanged || currentIndex != oldIndex; if (dialogueChanged || forceRefreshDialogue) { Assert.IsTrue(currentIndex >= 0 && currentIndex < currentNode.DialogueEntryCount, "Nova: dialogue index out of range"); currentDialogueEntry = currentNode.GetDialogueEntryAt(currentIndex); oldIndex = currentIndex; if (checkpointManager.IsReached(currentNode.name, currentIndex) == null) { // tell the checkpoint manager a new dialogue entry has been reached checkpointManager.SetReached(currentNode.name, currentIndex, GetGameStateStepRestoreEntry()); } if (DialogueWillChange != null) { DialogueWillChange.Invoke(); } state = State.ActionRunning; currentDialogueEntry.ExecuteAction(); StartCoroutine(WaitActionEnd()); } }
/// <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()); }