ProjectDDD/Assets/Plugins/Pixel Crushers/Dialogue System/Scripts/UI/Standard/Dialogue/StandardUISubtitlePanel.cs
2025-06-11 14:35:40 +09:00

831 lines
32 KiB (Stored with Git LFS)
C#

// Copyright (c) Pixel Crushers. All rights reserved.
using UnityEngine;
using UnityEngine.Events;
using System.Collections;
using System;
using System.Text.RegularExpressions;
namespace PixelCrushers.DialogueSystem
{
[AddComponentMenu("")] // Use wrapper.
public class StandardUISubtitlePanel : UIPanel
{
#region Serialized Fields
[Tooltip("(Optional) Main panel for subtitle.")]
public RectTransform panel;
[Tooltip("(Optional) Image for actor's portrait.")]
public UnityEngine.UI.Image portraitImage;
[Tooltip("(Optional) Text element for actor's name.")]
public UITextField portraitName;
[Tooltip("Subtitle text.")]
public UITextField subtitleText;
[Tooltip("Add speaker's name to subtitle text.")]
public bool addSpeakerName = false;
[Tooltip("Format to add speaker name, where {0} is name and {1} is subtitle text.")]
public string addSpeakerNameFormat = "{0}: {1}";
[Tooltip("Each subtitle adds to Subtitle Text instead of replacing it.")]
public bool accumulateText = false;
[Tooltip("If Accumulate Text is ticked, accumulate up to this many lines, removing the oldest lines when over the limit.")]
public int maxLines = 100;
[Tooltip("If panel has a typewriter effect, don't start typing until panel's Show animation has completed.")]
public bool delayTypewriterUntilOpen = false;
[Tooltip("(Optional) Continue button. Only shown if Dialogue Manager's Continue Button mode uses continue button.")]
public UnityEngine.UI.Button continueButton;
[Tooltip("If non-zero, prevent continue button clicks for this duration in seconds when opening subtitle panel.")]
public float blockInputDuration = 0;
[Tooltip("When the subtitle UI elements should be visible.")]
public UIVisibility visibility = UIVisibility.OnlyDuringContent;
[Tooltip("When focusing panel, set this animator trigger.")]
public string focusAnimationTrigger = string.Empty;
[Tooltip("When unfocusing panel, set this animator trigger.")]
public string unfocusAnimationTrigger = string.Empty;
[Tooltip("If a player actor uses this panel, don't show player portrait name & image; keep previous NPC portrait visible instead.")]
public bool onlyShowNPCPortraits = false;
[Tooltip("Check Dialogue Actors for portrait animator controllers. Portrait image must have an Animator.")]
public bool useAnimatedPortraits = false;
[Tooltip("Set Portrait Image to actor portrait's native size. Image's Rect Transform can't use Stretch anchors.")]
public bool usePortraitNativeSize = false;
[Tooltip("Wait for panel state to be Open before showing subtitle.")]
public bool waitForOpen = false;
[Tooltip("Wait for panels within this dialogue UI (not external panels) to close before showing.")]
public bool waitForClose = false;
[Tooltip("Clear text when closing panel, including when hiding using SetDialoguePanel().")]
public bool clearTextOnClose = true;
[Tooltip("Clear text when any conversation starts.")]
public bool clearTextOnConversationStart = false;
[Tooltip("If Subtitle Text doesn't have a typewriter effect, to enable scroll to bottom add UIScrollbarEnabler to Scroll Rect and assign it here.")]
public UIScrollbarEnabler scrollbarEnabler;
/// <summary>
/// Invoked when the subtitle panel gains focus.
/// </summary>
public UnityEvent onFocus = new UnityEvent();
/// <summary>
/// Invoked when the subtitle panel loses focus.
/// </summary>
public UnityEvent onUnfocus = new UnityEvent();
#endregion
#region Public Properties
[SerializeField, Tooltip("Panel is currently in focused state.")]
private bool m_hasFocus = true;
public bool hasFocus
{
get { return m_hasFocus; }
set { m_hasFocus = value; }
}
[SerializeField, Tooltip("Panel is playing the focus animation.")]
private bool m_isFocusing = true;
public bool isFocusing
{
get { return m_isFocusing; }
set { m_isFocusing = value; }
}
public override bool waitForShowAnimation { get { return true; } }
private Subtitle m_currentSubtitle = null;
public virtual Subtitle currentSubtitle
{
get { return m_currentSubtitle; }
protected set { m_currentSubtitle = value; }
}
/// <summary>
/// The database name of the actor whose display name appears in the Portrait Name field.
/// </summary>
public string portraitActorName { get; protected set; }
#endregion
#region Internal Properties
private bool m_haveSavedOriginalColor = false;
protected bool haveSavedOriginalColor { get { return m_haveSavedOriginalColor; } set { m_haveSavedOriginalColor = value; } }
protected Color originalColor { get; set; }
private string m_accumulatedText = string.Empty;
public string accumulatedText { get { return m_accumulatedText; } set { m_accumulatedText = value; } }
protected int numAccumulatedLines = 0;
private Animator m_portraitAnimator = null;
protected virtual Animator animator { get { if (m_portraitAnimator == null && portraitImage != null) m_portraitAnimator = portraitImage.GetComponent<Animator>(); return m_portraitAnimator; } set { m_portraitAnimator = value; } }
private Animator m_panelAnimator = null;
private bool m_isDefaultNPCPanel = false;
public bool isDefaultNPCPanel { get { return m_isDefaultNPCPanel; } set { m_isDefaultNPCPanel = value; } }
private bool m_isDefaultPCPanel = false;
public bool isDefaultPCPanel { get { return m_isDefaultPCPanel; } set { m_isDefaultPCPanel = value; } }
private int m_panelNumber = -1;
public int panelNumber { get { return m_panelNumber; } set { m_panelNumber = value; } }
public Transform m_actorOverridingPanel = null;
public Transform actorOverridingPanel { get { return m_actorOverridingPanel; } set { m_actorOverridingPanel = value; } }
private int m_lastActorID = -1;
protected int lastActorID { get { return m_lastActorID; } set { m_lastActorID = value; } }
protected int frameLastSetContent = -1; // Frame when we last set this panel's content.
protected bool shouldShowContinueButton = false;
protected const float WaitForCloseTimeoutDuration = 8f;
private StandardDialogueUI m_dialogueUI = null;
public StandardDialogueUI dialogueUI
{
get
{
if (m_dialogueUI == null)
{
m_dialogueUI = GetComponentInParent<StandardDialogueUI>();
if (m_dialogueUI == null) m_dialogueUI = DialogueManager.dialogueUI as StandardDialogueUI;
}
return m_dialogueUI;
}
set
{
m_dialogueUI = value;
}
}
protected Coroutine m_focusWhenOpenCoroutine = null;
protected Coroutine m_showAfterClosingCoroutine = null;
protected Coroutine m_setAnimatorCoroutine = null;
protected WaitForEndOfFrame endOfFrame = new WaitForEndOfFrame();
#endregion
#region Initialization
protected virtual void Awake()
{
if (addSpeakerName)
{
addSpeakerNameFormat = addSpeakerNameFormat.Replace("\\n", "\n").Replace("\\t", "\t");
}
m_panelAnimator = GetComponent<Animator>();
}
#endregion
#region Typewriter Control
/// <summary>
/// Returns the typewriter effect on the subtitle text element, or null if there is none.
/// </summary>
public AbstractTypewriterEffect GetTypewriter()
{
return TypewriterUtility.GetTypewriter(subtitleText);
}
/// <summary>
/// Checks if the subtitle text element has a typewriter effect.
/// </summary>
public bool HasTypewriter()
{
return GetTypewriter() != null;
}
/// <summary>
/// Returns the speed of the typewriter effect on the subtitle element if it has one.
/// </summary>
public float GetTypewriterSpeed()
{
return TypewriterUtility.GetTypewriterSpeed(subtitleText);
}
/// <summary>
/// Sets the speed of the typewriter effect on the subtitle element if it has one.
/// </summary>
public void SetTypewriterSpeed(float charactersPerSecond)
{
TypewriterUtility.SetTypewriterSpeed(subtitleText, charactersPerSecond);
}
#endregion
#region Show & Hide
/// <summary>
/// Shows the panel at the start of the conversation; called if it's configured to be visible at the start.
/// </summary>
/// <param name="portraitSprite">The image of the first actor who will use this panel.</param>
/// <param name="portraitName">The name of the first actor who will use this panel.</param>
/// <param name="dialogueActor">The actor's DialogueActor component, or null if none.</param>
public virtual void OpenOnStartConversation(Sprite portraitSprite, string portraitName, DialogueActor dialogueActor)
{
Open();
SetUIElementsActive(true);
SetPortraitImage(portraitSprite);
portraitActorName = (dialogueActor != null) ? dialogueActor.GetActorName() : portraitName;
if (this.portraitName != null) this.portraitName.text = portraitActorName;
if (subtitleText.text != null) subtitleText.text = string.Empty;
CheckDialogueActorAnimator(dialogueActor);
}
[System.Obsolete("Use OpenOnStartConversation(Sprite,string,DialogueActor) instead.")]
public virtual void OpenOnStartConversation(Texture2D portraitTexture, string portraitName, DialogueActor dialogueActor)
{
OpenOnStartConversation(UITools.CreateSprite(portraitTexture), portraitName, dialogueActor);
}
public virtual void OnConversationStart(Transform actor)
{
if (clearTextOnConversationStart && (frameLastSetContent < (Time.frameCount - 1))) // If we just set content, don't clear the text.
{
ClearText();
}
}
/// <summary>
/// Shows a subtitle, playing the open and focus animations.
/// </summary>
public virtual void ShowSubtitle(Subtitle subtitle)
{
var supercedeOnActorChange = waitForClose && isOpen && visibility == UIVisibility.UntilSupercededOrActorChange &&
subtitle != null && lastActorID != subtitle.speakerInfo.id;
if ((waitForClose && dialogueUI.AreAnyPanelsClosing(this)) || supercedeOnActorChange)
{
if (supercedeOnActorChange) Close();
StopShowAfterClosingCoroutine();
m_showAfterClosingCoroutine = DialogueManager.instance.StartCoroutine(ShowSubtitleAfterClosing(subtitle));
}
else
{
ShowSubtitleNow(subtitle);
}
}
protected virtual void ShowSubtitleNow(Subtitle subtitle)
{
SetUIElementsActive(true);
if (!isOpen)
{
hasFocus = false;
isFocusing = false;
}
Open();
Focus();
SetContent(subtitle);
actorOverridingPanel = null;
}
protected virtual IEnumerator ShowSubtitleAfterClosing(Subtitle subtitle)
{
shouldShowContinueButton = false;
float safeguardTime = Time.realtimeSinceStartup + WaitForCloseTimeoutDuration;
while (dialogueUI.AreAnyPanelsClosing() && Time.realtimeSinceStartup < safeguardTime)
{
yield return null;
}
ShowSubtitleNow(subtitle);
if (shouldShowContinueButton) ShowContinueButton();
m_showAfterClosingCoroutine = null;
}
protected virtual void StopShowAfterClosingCoroutine()
{
if (m_showAfterClosingCoroutine != null)
{
DialogueManager.instance.StopCoroutine(m_showAfterClosingCoroutine);
m_showAfterClosingCoroutine = null;
}
}
protected virtual void StopFocusWhenOpenCoroutine()
{
if (m_focusWhenOpenCoroutine != null)
{
StopCoroutine(m_focusWhenOpenCoroutine);
m_focusWhenOpenCoroutine = null;
}
}
public virtual void StopShowSubtitleCoroutines()
{
StopShowAfterClosingCoroutine();
StopFocusWhenOpenCoroutine();
}
/// <summary>
/// Hides a subtitle, playing the unfocus and close animations.
/// </summary>
public virtual void HideSubtitle(Subtitle subtitle)
{
if (panelState != PanelState.Closed) Unfocus();
Close();
}
/// <summary>
/// Immediately hides the panel without playing any animations.
/// </summary>
public virtual void HideImmediate()
{
OnHidden();
}
protected override void OnHidden()
{
base.OnHidden();
if (clearTextOnClose) ClearText();
if (deactivateOnHidden) DeactivateUIElements();
currentSubtitle = null;
}
/// <summary>
/// Opens the panel.
/// </summary>
public override void Open()
{
base.Open();
}
/// <summary>
/// Closes the panel.
/// </summary>
public override void Close()
{
StopShowAfterClosingCoroutine();
if (isOpen) base.Close();
if (clearTextOnClose && !waitForClose) ClearText();
hasFocus = false;
isFocusing = false;
}
/// <summary>
/// Focuses the panel.
/// </summary>
public virtual void Focus()
{
if (panelState == PanelState.Opening && enabled && gameObject.activeInHierarchy)
{
StopFocusWhenOpenCoroutine();
m_focusWhenOpenCoroutine = StartCoroutine(FocusWhenOpen());
}
else
{
FocusNow();
}
}
protected IEnumerator FocusWhenOpen()
{
float timeout = Time.realtimeSinceStartup + 5f;
while (panelState != PanelState.Open && Time.realtimeSinceStartup < timeout)
{
yield return null;
}
m_focusWhenOpenCoroutine = null;
FocusNow();
}
protected virtual void FocusNow()
{
panelState = PanelState.Open;
if (hasFocus) return;
isFocusing = true;
if (m_panelAnimator != null && !string.IsNullOrEmpty(unfocusAnimationTrigger)) m_panelAnimator.ResetTrigger(unfocusAnimationTrigger);
if (string.IsNullOrEmpty(focusAnimationTrigger))
{
OnFocused();
}
else
{
animatorMonitor.SetTrigger(focusAnimationTrigger, OnFocused, true);
}
onFocus.Invoke();
}
private void OnFocused()
{
hasFocus = true;
isFocusing = false;
}
/// <summary>
/// Unfocuses the panel.
/// </summary>
public virtual void Unfocus()
{
if (m_panelAnimator != null && !string.IsNullOrEmpty(focusAnimationTrigger)) m_panelAnimator.ResetTrigger(focusAnimationTrigger);
StopShowSubtitleCoroutines();
if (!string.IsNullOrEmpty(focusAnimationTrigger) && animatorMonitor.currentTrigger == focusAnimationTrigger)
{
animatorMonitor.CancelCurrentAnimation();
}
else
{
if (!(hasFocus || isFocusing))
{
hasFocus = false;
isFocusing = false;
return;
}
}
if (panelState == PanelState.Opening) panelState = PanelState.Open;
hasFocus = false;
animatorMonitor.SetTrigger(unfocusAnimationTrigger, null, false);
onUnfocus.Invoke();
}
public virtual void ActivateUIElements()
{
SetUIElementsActive(true);
}
public virtual void DeactivateUIElements()
{
SetUIElementsActive(false);
if (clearTextOnClose) ClearText();
}
protected virtual void SetUIElementsActive(bool value)
{
Tools.SetGameObjectActive(panel, value);
Tools.SetGameObjectActive(portraitImage, value && portraitImage != null && portraitImage.sprite != null);
portraitName.SetActive(value);
subtitleText.SetActive(value);
Tools.SetGameObjectActive(continueButton, false); // Let ConversationView determine if continueButton should be shown.
}
public virtual void ClearText()
{
m_accumulatedText = string.Empty;
subtitleText.text = string.Empty;
numAccumulatedLines = 0;
}
private Coroutine m_ShowContinueButtonCoroutine;
public virtual void ShowContinueButton()
{
if (m_ShowContinueButtonCoroutine != null)
{
DialogueManager.instance.StopCoroutine(m_ShowContinueButtonCoroutine);
}
if (blockInputDuration > 0)
{
m_ShowContinueButtonCoroutine = DialogueManager.instance.StartCoroutine(ShowContinueButtonAfterBlockDuration());
}
else
{
StartCoroutine(ShowContinueButtonAtEndOfFrame());
}
}
public virtual void HideContinueButton()
{
if (m_ShowContinueButtonCoroutine != null)
{
DialogueManager.instance.StopCoroutine(m_ShowContinueButtonCoroutine);
}
Tools.SetGameObjectActive(continueButton, false);
}
protected virtual IEnumerator ShowContinueButtonAfterBlockDuration()
{
if (continueButton == null) yield break;
continueButton.interactable = false;
// Wait for panel to open, or timeout:
var timeout = Time.realtimeSinceStartup + 10f;
while (panelState != PanelState.Open && Time.realtimeSinceStartup < timeout)
{
yield return null;
}
yield return DialogueManager.instance.StartCoroutine(DialogueTime.WaitForSeconds(blockInputDuration));
continueButton.interactable = true;
ShowContinueButtonNow();
m_ShowContinueButtonCoroutine = null;
}
protected virtual IEnumerator ShowContinueButtonAtEndOfFrame()
{
// We wait until the end of the frame in case another subtitle panel shares the
// same continue button and decides to deactivate it.
yield return endOfFrame;
ShowContinueButtonNow();
}
protected virtual void ShowContinueButtonNow()
{
Tools.SetGameObjectActive(continueButton, true);
if (InputDeviceManager.autoFocus) Select();
if (continueButton != null && continueButton.onClick.GetPersistentEventCount() == 0)
{
continueButton.onClick.RemoveAllListeners();
var fastForward = continueButton.GetComponent<StandardUIContinueButtonFastForward>();
if (fastForward != null)
{
continueButton.onClick.AddListener(fastForward.OnFastForward);
}
else
{
continueButton.onClick.AddListener(OnContinue);
}
}
shouldShowContinueButton = true;
}
/// <summary>
/// Finishes the subtitle without hiding the panel. Called if the panel is configured to stay open.
/// Hides the continue button and stops the typewriter effect.
/// </summary>
public virtual void FinishSubtitle()
{
HideContinueButton();
var typewriter = GetTypewriter();
if (typewriter != null && typewriter.isPlaying) typewriter.Stop();
}
/// <summary>
/// Selects the panel's continue button (i.e., navigates to it).
/// </summary>
/// <param name="allowStealFocus">Select continue button even if another element is already selected.</param>
public virtual void Select(bool allowStealFocus = true)
{
UITools.Select(continueButton, allowStealFocus, eventSystem);
}
/// <summary>
/// The continue button should call this method to continue.
/// </summary>
public virtual void OnContinue()
{
if (dialogueUI != null) dialogueUI.OnContinueConversation();
}
/// <summary>
/// Sets the content of the panel. Assumes the panel is already open.
/// </summary>
public virtual void SetContent(Subtitle subtitle)
{
if (subtitle == null) return;
currentSubtitle = subtitle;
lastActorID = subtitle.speakerInfo.id;
CheckSubtitleAnimator(subtitle);
if (!onlyShowNPCPortraits || subtitle.speakerInfo.isNPC)
{
if (portraitImage != null)
{
var sprite = subtitle.GetSpeakerPortrait();
SetPortraitImage(sprite);
}
portraitActorName = subtitle.speakerInfo.nameInDatabase;
if (portraitName.text != subtitle.speakerInfo.Name)
{
portraitName.text = subtitle.speakerInfo.Name;
UITools.SendTextChangeMessage(portraitName);
}
}
if (waitForOpen && panelState != PanelState.Open)
{
DialogueManager.instance.StartCoroutine(SetSubtitleTextContentAfterOpen(subtitle));
}
else
{
SetSubtitleTextContent(subtitle);
}
frameLastSetContent = Time.frameCount;
}
protected virtual IEnumerator SetSubtitleTextContentAfterOpen(Subtitle subtitle)
{
float timeout = Time.realtimeSinceStartup + WaitForCloseTimeoutDuration;
while (panelState != PanelState.Open && Time.realtimeSinceStartup < timeout)
{
yield return null;
}
SetSubtitleTextContent(subtitle);
}
protected virtual void SetSubtitleTextContent(Subtitle subtitle)
{
if (addSpeakerName && !string.IsNullOrEmpty(subtitle.speakerInfo.Name))
{
subtitle.formattedText.text = FormattedText.Parse(string.Format(addSpeakerNameFormat, new object[] { subtitle.speakerInfo.Name, subtitle.formattedText.text })).text;
}
TypewriterUtility.StopTyping(subtitleText);
var previousText = accumulateText ? m_accumulatedText : string.Empty;
if (accumulateText && !string.IsNullOrEmpty(subtitle.formattedText.text))
{
if (numAccumulatedLines < maxLines)
{
numAccumulatedLines += (1 + NumCharOccurrences('\n', subtitle.formattedText.text));
}
else
{
// If we're at the max number of lines, remove the first line from the accumulated text:
previousText = RemoveFirstLine(previousText);
}
}
var previousChars = accumulateText ? UITools.StripRPGMakerCodes(Tools.StripTextMeshProTags(Tools.StripRichTextCodes(previousText))).Length : 0;
SetFormattedText(subtitleText, previousText, subtitle);
if (accumulateText) m_accumulatedText = UITools.StripRPGMakerCodes(subtitleText.text) + "\n";
if (scrollbarEnabler != null && !HasTypewriter())
{
scrollbarEnabler.CheckScrollbarWithResetValue(0);
}
else if (delayTypewriterUntilOpen && !hasFocus)
{
DialogueManager.instance.StartCoroutine(StartTypingWhenFocused(subtitleText, subtitleText.text, previousChars));
}
else
{
TypewriterUtility.StartTyping(subtitleText, subtitleText.text, previousChars);
}
}
protected virtual string RemoveFirstLine(string previousText)
{
if (string.IsNullOrEmpty(previousText)) return string.Empty;
var newlineIndex = previousText.IndexOf("\n");
if (previousText.Contains("<"))
{
// Preserve rich text tags in first line:
var tags = string.Empty;
var firstLine = previousText.Substring(0, newlineIndex);
foreach (Match match in Tools.TextMeshProTagsRegex.Matches(firstLine))
{
tags += match.Value;
}
return tags + previousText.Substring(newlineIndex + 1);
}
else
{
return previousText.Substring(newlineIndex + 1);
}
}
/// <summary>
/// Returns the number of times character c occurs in string s.
/// </summary>
protected int NumCharOccurrences(char c, string s)
{
int count = 0;
for (int i = 0; i < s.Length; i++)
{
if (c == s[i]) count++;
}
return count;
}
protected virtual IEnumerator StartTypingWhenFocused(UITextField subtitleText, string text, int fromIndex)
{
subtitleText.text = string.Empty;
float timeout = Time.realtimeSinceStartup + 5f;
while ((!hasFocus || panelState != PanelState.Open) && Time.realtimeSinceStartup < timeout)
{
yield return null;
}
subtitleText.text = text;
TypewriterUtility.StartTyping(subtitleText, text, fromIndex);
}
protected virtual void SetFormattedText(UITextField textField, string previousText, Subtitle subtitle)
{
var currentText = UITools.GetUIFormattedText(subtitle.formattedText);
textField.text = previousText + currentText;
UITools.SendTextChangeMessage(textField);
if (!haveSavedOriginalColor)
{
originalColor = textField.color;
haveSavedOriginalColor = true;
}
textField.color = (subtitle.formattedText.emphases != null && subtitle.formattedText.emphases.Length > 0) ? subtitle.formattedText.emphases[0].color : originalColor;
}
// No longer used, but kept in case user subclasses use it.
protected virtual void SetFormattedText(UITextField textField, string previousText, FormattedText formattedText)
{
textField.text = previousText + UITools.GetUIFormattedText(formattedText);
UITools.SendTextChangeMessage(textField);
if (!haveSavedOriginalColor)
{
originalColor = textField.color;
haveSavedOriginalColor = true;
}
textField.color = (formattedText.emphases != null && formattedText.emphases.Length > 0) ? formattedText.emphases[0].color : originalColor;
}
public virtual void SetPortraitName(string actorName)
{
if (portraitName == null) return;
portraitName.gameObject.SetActive(!string.IsNullOrEmpty(actorName));
portraitName.text = actorName;
}
public virtual void SetActorPortraitSprite(string actorName, Sprite portraitSprite)
{
if (portraitImage == null) return;
var sprite = AbstractDialogueUI.GetValidPortraitSprite(actorName, portraitSprite);
SetPortraitImage(sprite);
}
public virtual void SetPortraitImage(Sprite sprite)
{
if (portraitImage == null) return;
Tools.SetGameObjectActive(portraitImage, sprite != null);
portraitImage.sprite = sprite;
if (usePortraitNativeSize && sprite != null)
{
portraitImage.rectTransform.sizeDelta = sprite.packed ?
new Vector2(sprite.rect.width, sprite.rect.height) :
new Vector2(sprite.texture.width, sprite.texture.height);
}
}
public virtual void CheckSubtitleAnimator(Subtitle subtitle)
{
if (subtitle != null && useAnimatedPortraits && animator != null)
{
var dialogueActor = DialogueActor.GetDialogueActorComponent(subtitle.speakerInfo.transform);
if (dialogueActor != null) // && dialogueActor.standardDialogueUISettings.portraitAnimatorController != null)
{
var speakerPanelNumber = dialogueActor.GetSubtitlePanelNumber();
var isMyPanel =
(actorOverridingPanel == subtitle.speakerInfo.transform) ||
(PanelNumberUtility.GetSubtitlePanelIndex(speakerPanelNumber) == this.panelNumber) ||
(speakerPanelNumber == SubtitlePanelNumber.Default && subtitle.speakerInfo.isNPC && isDefaultNPCPanel) ||
(speakerPanelNumber == SubtitlePanelNumber.Default && subtitle.speakerInfo.isPlayer && isDefaultPCPanel) ||
(speakerPanelNumber == SubtitlePanelNumber.Custom && dialogueActor.standardDialogueUISettings.customSubtitlePanel == this);
if (isMyPanel)
{
if (m_setAnimatorCoroutine != null) DialogueManager.instance.StopCoroutine(m_setAnimatorCoroutine);
m_setAnimatorCoroutine = DialogueManager.instance.StartCoroutine(SetAnimatorAtEndOfFrame(dialogueActor.standardDialogueUISettings.portraitAnimatorController));
}
}
else
{
if (m_setAnimatorCoroutine != null) DialogueManager.instance.StopCoroutine(m_setAnimatorCoroutine);
m_setAnimatorCoroutine = DialogueManager.instance.StartCoroutine(SetAnimatorAtEndOfFrame(null));
}
}
}
protected virtual void CheckDialogueActorAnimator(DialogueActor dialogueActor)
{
if (dialogueActor != null && useAnimatedPortraits && animator != null &&
dialogueActor.standardDialogueUISettings.portraitAnimatorController != null)
{
if (m_setAnimatorCoroutine != null) DialogueManager.instance.StopCoroutine(m_setAnimatorCoroutine);
m_setAnimatorCoroutine = DialogueManager.instance.StartCoroutine(SetAnimatorAtEndOfFrame(dialogueActor.standardDialogueUISettings.portraitAnimatorController));
}
}
protected virtual IEnumerator SetAnimatorAtEndOfFrame(RuntimeAnimatorController animatorController)
{
if (animator == null) yield break;
if (animator.runtimeAnimatorController != animatorController)
{
animator.runtimeAnimatorController = animatorController;
}
if (animatorController != null)
{
Tools.SetGameObjectActive(portraitImage, portraitImage.sprite != null);
}
yield return CoroutineUtility.endOfFrame;
if (animator.runtimeAnimatorController != animatorController)
{
animator.runtimeAnimatorController = animatorController;
}
if (animatorController != null)
{
Tools.SetGameObjectActive(portraitImage, portraitImage.sprite != null);
}
animator.enabled = animatorController != null;
}
#endregion
}
}