// Copyright (c) Pixel Crushers. All rights reserved. using UnityEngine; using System; namespace PixelCrushers.DialogueSystem { public delegate void DialogueEntrySpokenDelegate(Subtitle subtitle); public delegate float GetDefaultSubtitleDurationDelegate(string text); /// /// Handles the user interaction part of a conversation. The ConversationController /// provides the content. ConversationView processes UI events and hands control to /// ConversationController. /// public class ConversationView : MonoBehaviour { /// /// You can assign a function here to override the method used to /// determine the default subtitle duration -- that is, the value of {{end}}. /// public static GetDefaultSubtitleDurationDelegate overrideGetDefaultSubtitleDuration = null; /// /// Called when a subtitle is finished displaying (including text delay and cutscene /// sequence). /// public event EventHandler FinishedSubtitleHandler = null; /// /// Called when the player selects a response. /// public event EventHandler SelectedResponseHandler = null; private delegate bool IsCancelKeyDownDelegate(); private IDialogueUI ui = null; private Sequencer m_sequencer = null; private DisplaySettings settings = null; private Subtitle lastNPCSubtitle = null; private Subtitle lastPCSubtitle = null; private Subtitle lastSubtitle = null; private IsCancelKeyDownDelegate IsCancelKeyDown = null; private Action CancelledHandler = null; private DialogueEntrySpokenDelegate dialogueEntrySpokenHandler = null; private bool waitForContinue = false; private bool notifyOnFinishSubtitle = false; private bool isPlayingResponseMenuSequence = false; private int initialFrameCount; public DisplaySettings displaySettings { get { return settings; } } public bool isWaitingForContinue { get { return waitForContinue; } } public Sequencer sequencer { get { return m_sequencer; } } public IDialogueUI dialogueUI { get { return ui; } set { if (ui != value) { ui.SelectedResponseHandler -= OnSelectedResponse; ui.Close(); ui = value; ui.Open(); ui.SelectedResponseHandler += OnSelectedResponse; } } } /// /// Initialize a UI and sequencer with displaySettings. /// /// /// Dialogue UI. /// /// /// Sequencer. /// /// /// Display settings to initiate the UI and sequencer with. /// public void Initialize(IDialogueUI ui, Sequencer sequencer, DisplaySettings displaySettings, DialogueEntrySpokenDelegate dialogueEntrySpokenHandler) { this.ui = ui; this.m_sequencer = sequencer; this.settings = DialogueManager.allowSimultaneousConversations ? new DisplaySettings(displaySettings) : displaySettings; this.dialogueEntrySpokenHandler = dialogueEntrySpokenHandler; this.initialFrameCount = Time.frameCount; ui.Open(); sequencer.Open(); ui.SelectedResponseHandler += OnSelectedResponse; sequencer.FinishedSequenceHandler += OnFinishedSubtitle; } /// /// Close the conversation view. /// public void Close() { ui.SelectedResponseHandler -= OnSelectedResponse; m_sequencer.FinishedSequenceHandler -= OnFinishedSubtitle; ui.Close(); m_sequencer.Close(); Destroy(this); } /// /// Checks if the player has cancelled the conversation. /// public void Update() { if (Cancelled() && (CancelledHandler != null)) CancelledHandler(); } private bool Cancelled() { return (IsCancelKeyDown == null) ? false : IsCancelKeyDown(); } private bool IsSubtitleCancelKeyDown() { return settings.GetCancelSubtitleInput().isDown; } private bool IsConversationCancelKeyDown() { return settings.GetCancelConversationInput().isDown; } /// /// Starts displaying a subtitle. /// /// /// Subtitle to display. /// /// /// Indicates whether the next stage is the player or NPC. /// /// /// Indicates whether the next stage is a player auto-response. /// public void StartSubtitle(Subtitle subtitle, bool isPCResponseMenuNext, bool isPCAutoResponseNext) { notifyOnFinishSubtitle = true; if (subtitle != null) { if (DialogueDebug.logInfo) Debug.Log(string.Format("{0}: {1} says '{2}'", new System.Object[] { DialogueDebug.Prefix, Tools.GetGameObjectName(subtitle.speakerInfo.transform), subtitle.formattedText.text })); if (DialogueManager.instance.allowSimultaneousConversations) { DialogueManager.instance.displaySettings = settings; } NotifyParticipantsOnConversationLine(subtitle); m_sequencer.SetParticipants(subtitle.speakerInfo.transform, subtitle.listenerInfo.transform); m_sequencer.entrytag = subtitle.entrytag; m_sequencer.subtitleEndTime = GetDefaultSubtitleDuration(subtitle.formattedText.text); if (!string.IsNullOrEmpty(subtitle.sequence) && subtitle.sequence.Contains("{{default}}")) { subtitle.sequence = subtitle.sequence.Replace("{{default}}", GetDefaultSequence(subtitle)); } subtitle.sequence = string.IsNullOrEmpty(subtitle.sequence) ? GetDefaultSequence(subtitle) : PreprocessSequence(subtitle); if (ShouldShowSubtitle(subtitle)) { ui.ShowSubtitle(subtitle); // Save this info in case SetContinueMode() sequencer command forces reevaluation: _subtitle = subtitle; _isPCResponseMenuNext = isPCResponseMenuNext; _isPCAutoResponseNext = isPCAutoResponseNext; SetupContinueButton(subtitle, isPCResponseMenuNext, isPCAutoResponseNext); } else { waitForContinue = false; } if (subtitle.speakerInfo.isNPC) { lastNPCSubtitle = subtitle; } else { lastPCSubtitle = subtitle; } lastSubtitle = subtitle; if (dialogueEntrySpokenHandler != null) dialogueEntrySpokenHandler(subtitle); m_sequencer.PlaySequence(subtitle.sequence, settings.subtitleSettings.informSequenceStartAndEnd, false); } else { FinishSubtitle(); } IsCancelKeyDown = IsSubtitleCancelKeyDown; CancelledHandler = OnCancelSubtitle; if (!string.IsNullOrEmpty(subtitle.formattedText.text)) _lastModeWasResponseMenu = false; } private Subtitle _subtitle = null; private bool _isPCResponseMenuNext = false; private bool _isPCAutoResponseNext = false; private bool _lastModeWasResponseMenu = false; /// /// Determines whether the continue button should be shown, and shows or hides it. /// Call this if you've manually changed the continue button mode while the /// conversation is displaying a line. In most cases you won't ever need to call this /// manually. /// public void SetupContinueButton() { SetupContinueButton(_subtitle, _isPCResponseMenuNext, _isPCAutoResponseNext); } private void SetupContinueButton(Subtitle subtitle, bool isPCResponseMenuNext, bool isPCAutoResponseNext) { if (subtitle == null) return; var isPCLine = subtitle.speakerInfo.characterType == CharacterType.PC; waitForContinue = ShouldWaitForContinueButton(isPCLine, isPCResponseMenuNext, isPCAutoResponseNext); var showContinueButton = ShouldShowContinueButton(isPCLine, isPCResponseMenuNext, isPCAutoResponseNext); if (waitForContinue) { if (string.IsNullOrEmpty(subtitle.formattedText.text) && (subtitle.dialogueEntry.id == 0)) { waitForContinue = false; } } var abstractDialogueUI = ui as AbstractDialogueUI; if (abstractDialogueUI != null) { if (showContinueButton) { abstractDialogueUI.ShowContinueButton(subtitle); } else { abstractDialogueUI.HideContinueButton(subtitle); } } } private bool ShouldWaitForContinueButton(bool isPCLine, bool isPCResponseMenuNext, bool isPCAutoResponseNext) { switch (settings.GetContinueButtonMode()) { case DisplaySettings.SubtitleSettings.ContinueButtonMode.Always: return true; case DisplaySettings.SubtitleSettings.ContinueButtonMode.Never: return false; case DisplaySettings.SubtitleSettings.ContinueButtonMode.Optional: return false; case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalBeforeResponseMenu: return !isPCResponseMenuNext; case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotBeforeResponseMenu: return !isPCResponseMenuNext; case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalBeforePCAutoresponseOrMenu: return !(isPCResponseMenuNext || isPCAutoResponseNext); case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotBeforePCAutoresponseOrMenu: return !(isPCResponseMenuNext || isPCAutoResponseNext); case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalForPC: return !isPCLine; case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotForPC: return !isPCLine; case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalForPCOrBeforeResponseMenu: return !(isPCLine || isPCResponseMenuNext); case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotForPCOrBeforeResponseMenu: return !(isPCLine || isPCResponseMenuNext); case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalForPCOrBeforePCAutoresponseOrMenu: return !(isPCLine || isPCResponseMenuNext || isPCAutoResponseNext); case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotForPCOrBeforePCAutoresponseOrMenu: return !(isPCLine || isPCResponseMenuNext || isPCAutoResponseNext); case DisplaySettings.SubtitleSettings.ContinueButtonMode.OnlyForPC: return isPCLine; default: return false; } } private bool ShouldShowContinueButton(bool isPCLine, bool isPCResponseMenuNext, bool isPCAutoResponseNext) { // If we require continue button on last line, we have to grab the current conversation state to check it: if (settings.subtitleSettings.requireContinueOnLastLine && !DialogueManager.instance.currentConversationState.hasAnyResponses) { // Note: side effect - set waitForContinue true waitForContinue = true; return true; } // Should we show the continue button? (Even if optional and not waiting for it) switch (settings.GetContinueButtonMode()) { case DisplaySettings.SubtitleSettings.ContinueButtonMode.Always: return true; case DisplaySettings.SubtitleSettings.ContinueButtonMode.Never: return false; case DisplaySettings.SubtitleSettings.ContinueButtonMode.Optional: return true; case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalBeforeResponseMenu: return true; case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotBeforeResponseMenu: return !isPCResponseMenuNext; case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalBeforePCAutoresponseOrMenu: return true; case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotBeforePCAutoresponseOrMenu: return !(isPCResponseMenuNext || isPCAutoResponseNext); case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalForPC: return true; case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotForPC: return !isPCLine; case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalForPCOrBeforeResponseMenu: return true; case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotForPCOrBeforeResponseMenu: return !(isPCLine || isPCResponseMenuNext); case DisplaySettings.SubtitleSettings.ContinueButtonMode.OptionalForPCOrBeforePCAutoresponseOrMenu: return true; case DisplaySettings.SubtitleSettings.ContinueButtonMode.NotForPCOrBeforePCAutoresponseOrMenu: return !(isPCLine || isPCResponseMenuNext || isPCAutoResponseNext); case DisplaySettings.SubtitleSettings.ContinueButtonMode.OnlyForPC: return isPCLine; default: return false; } } /// /// Shows the most recently displayed subtitle. /// public void ShowLastNPCSubtitle() { if (ShouldShowLastNPCSubtitle()) ui.ShowSubtitle(lastNPCSubtitle); FinishSubtitle(); } private bool ShouldShowLastNPCSubtitle() { return (settings != null) && settings.GetShowNPCSubtitlesWithResponses() && (lastNPCSubtitle != null) && (lastNPCSubtitle.speakerInfo.characterType == CharacterType.NPC); } private bool ShouldShowLastPCSubtitle() { return (settings != null) && settings.GetShowNPCSubtitlesWithResponses() && settings.subtitleSettings.allowPCSubtitleReminders && (lastPCSubtitle != null) && (lastSubtitle == lastPCSubtitle) && (lastPCSubtitle.speakerInfo.characterType == CharacterType.PC); } private bool ShouldShowSubtitle(Subtitle subtitle) { if ((subtitle != null) && (settings != null) && (settings.subtitleSettings != null)) { if (subtitle.formattedText.noSubtitle || string.Equals(subtitle.sequence, "None()") || string.Equals(subtitle.sequence, "None();") || (!settings.cameraSettings.showSubtitleOnEmptyContinue && (string.Equals(subtitle.sequence, "Continue()") || string.Equals(subtitle.sequence, "Continue();")))) { return false; } if ((subtitle.speakerInfo.characterType == CharacterType.NPC) && settings.GetShowNPCSubtitlesDuringLine()) { return true; } if ((subtitle.speakerInfo.characterType == CharacterType.PC) && settings.GetShowPCSubtitlesDuringLine()) { return !(_lastModeWasResponseMenu && settings.GetSkipPCSubtitleAfterResponseMenu()); } } return false; } /// /// Continues this conversation if the dialogue UI matches. /// /// public void OnConversationContinue(IDialogueUI dialogueUI) { if (dialogueUI == this.ui) { HandleContinueButtonClick(); } } /// /// Continues all conversations. /// public void OnConversationContinueAll() { HandleContinueButtonClick(); } public void HandleContinueButtonClick() { // If we just started and another conversation just ended, ignore the continue: if (Time.frameCount == initialFrameCount && initialFrameCount == ConversationController.frameLastConversationEnded) { if (DialogueDebug.logInfo) Debug.Log($"Dialogue System: At frame {Time.frameCount}, just started a conversation but another just ended, so ignoring continue button."); return; } waitForContinue = false; FinishSubtitle(); } private void OnCancelSubtitle() { if (lastSubtitle == null) // Need to create a dummy subtitle to OnConversationLineCancelled's signature. { var dummySubtitle = new Subtitle(null, null, null, string.Empty, string.Empty, null); BroadcastMessage(DialogueSystemMessages.OnConversationLineCancelled, dummySubtitle, SendMessageOptions.DontRequireReceiver); } else { BroadcastMessage(DialogueSystemMessages.OnConversationLineCancelled, lastSubtitle, SendMessageOptions.DontRequireReceiver); } waitForContinue = false; FinishSubtitle(); } private void FinishSubtitle() { if (!waitForContinue) { if (m_sequencer != null) m_sequencer.Stop(); ui.HideSubtitle(lastSubtitle); if (notifyOnFinishSubtitle) { notifyOnFinishSubtitle = false; if (lastSubtitle != null) NotifyParticipantsOnConversationLineEnd(lastSubtitle); if (FinishedSubtitleHandler != null) FinishedSubtitleHandler(this, EventArgs.Empty); } } } private void OnFinishedSubtitle() { FinishSubtitle(); } /// /// Displays the player response menu. /// /// /// Last subtitle, to display as a reminder of what the player is responding to. /// /// /// Responses. /// public void StartResponses(Subtitle subtitle, Response[] responses) { PlayResponseMenuSequence(subtitle.responseMenuSequence); Subtitle lastSubtitle = ShouldShowLastPCSubtitle() ? lastPCSubtitle : ShouldShowLastNPCSubtitle() ? lastNPCSubtitle : null; NotifyOnResponseMenu(responses); ui.ShowResponses(lastSubtitle, responses, settings.GetResponseTimeout()); IsCancelKeyDown = IsConversationCancelKeyDown; CancelledHandler = OnCancelResponseMenu; _lastModeWasResponseMenu = true; } private void PlayResponseMenuSequence(string responseMenuSequence) { if (string.IsNullOrEmpty(responseMenuSequence) && !string.IsNullOrEmpty(settings.GetDefaultResponseMenuSequence())) { responseMenuSequence = settings.GetDefaultResponseMenuSequence(); } if (!string.IsNullOrEmpty(responseMenuSequence)) { m_sequencer.FinishedSequenceHandler -= OnFinishedSubtitle; m_sequencer.Stop(); m_sequencer.PlaySequence(responseMenuSequence); isPlayingResponseMenuSequence = true; } } private void StopResponseMenuSequence() { if (isPlayingResponseMenuSequence) { isPlayingResponseMenuSequence = false; m_sequencer.StopAllCoroutines(); m_sequencer.Stop(); // This starts a cleanup coroutine. m_sequencer.FinishedSequenceHandler += OnFinishedSubtitle; } } private void OnCancelResponseMenu() { NotifyParticipantsOnConversationCancelled(); //---Was: BroadcastMessage(DialogueSystemMessages.OnConversationCancelled, sequencer.speaker, SendMessageOptions.DontRequireReceiver); SelectResponse(new SelectedResponseEventArgs(null)); } private void OnSelectedResponse(object sender, SelectedResponseEventArgs e) { SelectResponse(e); } public void SelectResponse(SelectedResponseEventArgs e) { StopResponseMenuSequence(); ui.HideResponses(); if (SelectedResponseHandler != null) SelectedResponseHandler(this, e); } /// /// Gets the default sequence for a subtitle. /// /// /// The default sequence. /// /// /// Subtitle. /// public string GetDefaultSequence(Subtitle subtitle) { float duration = m_sequencer.subtitleEndTime; var isPlayerLine = (subtitle.speakerInfo.characterType == CharacterType.PC); if (isPlayerLine && (!settings.GetShowPCSubtitlesDuringLine() || (_lastModeWasResponseMenu && settings.GetSkipPCSubtitleAfterResponseMenu()))) { var playerSequence = settings.GetDefaultPlayerSequence(); return Sequencer.ReplaceShortcuts(playerSequence).Replace(SequencerKeywords.End, duration.ToString(System.Globalization.CultureInfo.InvariantCulture)); } else { var line = settings.GetDefaultSequence(); if (isPlayerLine && !string.IsNullOrEmpty(settings.GetDefaultPlayerSequence())) { line = settings.GetDefaultPlayerSequence(); } if (string.IsNullOrEmpty(line)) { return string.Format(System.Globalization.CultureInfo.InvariantCulture, "Delay({0})", new System.Object[] { duration }); } else { return Sequencer.ReplaceShortcuts(line).Replace(SequencerKeywords.End, duration.ToString(System.Globalization.CultureInfo.InvariantCulture)); } } } /// /// A duration based on the text length and the Dialogue Manager's /// Subtitle Settings > Min Subtitle Seconds and Subtitle Chars Per Second. /// Also factors in time for RPGMaker-style pause codes. /// public float GetDefaultSubtitleDuration(string text) { return GetDefaultSubtitleDurationInSeconds(text, settings); //if (overrideGetDefaultSubtitleDuration != null) return overrideGetDefaultSubtitleDuration(text); //int numCharacters = string.IsNullOrEmpty(text) ? 0 : Tools.StripRichTextCodes(text).Length; //float numRPGMakerPauses = 0; //if (text.Contains("\\")) //{ // var numFullPauses = (text.Length - text.Replace("\\.", string.Empty).Length) / 2; // var numQuarterPauses = (text.Length - text.Replace("\\,", string.Empty).Length) / 2; // numRPGMakerPauses = (1.0f * numFullPauses) + (0.25f * numQuarterPauses); //} //return Mathf.Max(settings.GetMinSubtitleSeconds(), numRPGMakerPauses + (numCharacters / Mathf.Max(1, settings.GetSubtitleCharsPerSecond()))); } /// /// A duration based on the text length and the Dialogue Manager's /// Subtitle Settings > Min Subtitle Seconds and Subtitle Chars Per Second. /// Also factors in time for RPGMaker-style pause codes. /// /// Text. /// If null, uses Dialogue Manager's Display Settings. public static float GetDefaultSubtitleDurationInSeconds(string text, DisplaySettings displaySettings = null) { if (overrideGetDefaultSubtitleDuration != null) return overrideGetDefaultSubtitleDuration(text); var settings = displaySettings ?? DialogueManager.displaySettings; int numCharacters = string.IsNullOrEmpty(text) ? 0 : Tools.StripRichTextCodes(text).Length; float numRPGMakerPauses = 0; if (text.Contains("\\")) { var numFullPauses = (text.Length - text.Replace("\\.", string.Empty).Length) / 2; var numQuarterPauses = (text.Length - text.Replace("\\,", string.Empty).Length) / 2; numRPGMakerPauses = (1.0f * numFullPauses) + (0.25f * numQuarterPauses); } return Mathf.Max(settings.GetMinSubtitleSeconds(), numRPGMakerPauses + (numCharacters / Mathf.Max(1, settings.GetSubtitleCharsPerSecond()))); } private string PreprocessSequence(Subtitle subtitle) { if ((subtitle == null) || (string.IsNullOrEmpty(subtitle.sequence))) return string.Empty; subtitle.sequence = Sequencer.ReplaceShortcuts(subtitle.sequence); if (!subtitle.sequence.Contains(SequencerKeywords.End)) return subtitle.sequence; float duration = m_sequencer.subtitleEndTime; return subtitle.sequence.Replace(SequencerKeywords.End, duration.ToString(System.Globalization.CultureInfo.InvariantCulture)); } private void NotifyParticipantsOnConversationLine(Subtitle subtitle) { NotifyParticipants(DialogueSystemMessages.OnConversationLine, subtitle); } private void NotifyParticipantsOnConversationLineEnd(Subtitle subtitle) { NotifyParticipants(DialogueSystemMessages.OnConversationLineEnd, subtitle); } private void NotifyParticipants(string message, Subtitle subtitle) { if (subtitle != null) { bool validSpeakerTransform = CharacterInfoHasValidTransform(subtitle.speakerInfo); bool validListenerTransform = CharacterInfoHasValidTransform(subtitle.listenerInfo); bool speakerIsListener = validSpeakerTransform && validListenerTransform && (subtitle.speakerInfo.transform == subtitle.listenerInfo.transform); if (validSpeakerTransform) subtitle.speakerInfo.transform.BroadcastMessage(message, subtitle, SendMessageOptions.DontRequireReceiver); if (validListenerTransform && !speakerIsListener) subtitle.listenerInfo.transform.BroadcastMessage(message, subtitle, SendMessageOptions.DontRequireReceiver); DialogueManager.instance.BroadcastMessage(message, subtitle, SendMessageOptions.DontRequireReceiver); } } private void NotifyOnResponseMenu(Response[] responses) { if (responses != null) { if (lastSubtitle != null) { bool validSpeakerTransform = CharacterInfoHasValidTransform(lastSubtitle.speakerInfo); bool validListenerTransform = CharacterInfoHasValidTransform(lastSubtitle.listenerInfo); bool speakerIsListener = validSpeakerTransform && validListenerTransform && (lastSubtitle.speakerInfo.transform == lastSubtitle.listenerInfo.transform); if (validSpeakerTransform) lastSubtitle.speakerInfo.transform.BroadcastMessage(DialogueSystemMessages.OnConversationResponseMenu, responses, SendMessageOptions.DontRequireReceiver); if (validListenerTransform && !speakerIsListener) lastSubtitle.listenerInfo.transform.BroadcastMessage(DialogueSystemMessages.OnConversationResponseMenu, responses, SendMessageOptions.DontRequireReceiver); } DialogueManager.instance.BroadcastMessage(DialogueSystemMessages.OnConversationResponseMenu, responses, SendMessageOptions.DontRequireReceiver); } } private void NotifyParticipantsOnConversationCancelled() { if (lastSubtitle != null) { bool validSpeakerTransform = CharacterInfoHasValidTransform(lastSubtitle.speakerInfo); bool validListenerTransform = CharacterInfoHasValidTransform(lastSubtitle.listenerInfo); bool speakerIsListener = validSpeakerTransform && validListenerTransform && (lastSubtitle.speakerInfo.transform == lastSubtitle.listenerInfo.transform); if (validSpeakerTransform) lastSubtitle.speakerInfo.transform.BroadcastMessage(DialogueSystemMessages.OnConversationCancelled, m_sequencer.listener ?? transform, SendMessageOptions.DontRequireReceiver); if (validListenerTransform && !speakerIsListener) lastSubtitle.listenerInfo.transform.BroadcastMessage(DialogueSystemMessages.OnConversationCancelled, m_sequencer.speaker ?? transform, SendMessageOptions.DontRequireReceiver); } DialogueManager.instance.BroadcastMessage(DialogueSystemMessages.OnConversationCancelled, m_sequencer.speaker ?? transform, SendMessageOptions.DontRequireReceiver); } private bool CharacterInfoHasValidTransform(CharacterInfo characterInfo) { return (characterInfo != null) && (characterInfo.transform != null); } /// /// Sets the PC portrait to use for the response menu. /// /// PC sprite. /// PC name. public void SetPCPortrait(Sprite pcSprite, string pcName) { var ui = DialogueManager.dialogueUI as AbstractDialogueUI; if (ui == null) return; ui.SetPCPortrait(pcSprite, pcName); } /// /// Sets the portrait sprite to use in the UI for an actor. /// This is used when the SetPortrait() sequencer command changes an actor's image. /// /// Actor name. /// Portrait sprite. public void SetActorPortraitSprite(string actorName, Sprite sprite) { var ui = DialogueManager.dialogueUI as AbstractDialogueUI; if (ui == null) return; ui.SetActorPortraitSprite(actorName, sprite); } } }