317 lines
10 KiB
C#
317 lines
10 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
|
|
#if TEXTMESHPRO_INSTALLED
|
|
using TMPro;
|
|
#endif
|
|
|
|
using UnityEngine;
|
|
|
|
namespace EasyTalk.Display
|
|
{
|
|
/// <summary>
|
|
/// The OptionListDisplay is an implementation of an Option Display which displays an aligned collection of dialogue option buttons to the player.
|
|
/// </summary>
|
|
public class OptionListDisplay : OptionDisplay
|
|
{
|
|
/// <summary>
|
|
/// The List of option buttons used to display dialogue options.
|
|
/// </summary>
|
|
[Tooltip("The list of Option Buttons available in the Option Display.")]
|
|
[SerializeField]
|
|
protected List<DialogueButton> optionButtons = new List<DialogueButton>();
|
|
|
|
/// <summary>
|
|
/// Whether the next/previous option selection controls should be reversed when selecting options.
|
|
/// </summary>
|
|
[Tooltip("If set to true, player input controls will be reversed for option selection, e.g. " +
|
|
"down will select the previous choice rather than the next (as is normal), etc..")]
|
|
[SerializeField]
|
|
protected bool reverseControls = false;
|
|
|
|
/// <summary>
|
|
/// Whether new option buttons should be dynamically created if the number of options set on the display exceeds the number of option buttons currently available.
|
|
/// </summary>
|
|
[Tooltip("If set to true, new option buttons will be automatically created as needed by cloning the first button.")]
|
|
[SerializeField]
|
|
protected bool isDynamic = true;
|
|
|
|
/// <summary>
|
|
/// The index of the currently selected option button.
|
|
/// </summary>
|
|
protected int selectedButtonIdx = 0;
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
protected DialogueOption selectedOption;
|
|
|
|
/// <summary>
|
|
/// Initializes the display and sets up the buttons' click actions.
|
|
/// </summary>
|
|
public override void Init()
|
|
{
|
|
base.Init();
|
|
|
|
foreach (DialogueButton optionButton in optionButtons)
|
|
{
|
|
optionButton.onClick.AddListener(
|
|
delegate
|
|
{
|
|
selectedOption = ((DialogueOption)optionButton.Value);
|
|
selectedButtonIdx = optionButtons.IndexOf(optionButton);
|
|
OptionChosen();
|
|
}
|
|
);
|
|
|
|
optionButton.onEnter.AddListener(
|
|
delegate
|
|
{
|
|
if (optionButton.IsClickable)
|
|
{
|
|
selectedOption = ((DialogueOption)optionButton.Value);
|
|
DialogueOption oldOption = ((DialogueOption)optionButtons[selectedButtonIdx].Value);
|
|
|
|
int newSelectedButtonIdx = optionButtons.IndexOf(optionButton);
|
|
|
|
if (newSelectedButtonIdx != selectedButtonIdx)
|
|
{
|
|
optionButtons[selectedButtonIdx].DisplayNormal();
|
|
}
|
|
|
|
selectedButtonIdx = newSelectedButtonIdx;
|
|
|
|
foreach (OptionDisplayListener listener in optionDisplayListeners)
|
|
{
|
|
listener.OnOptionChanged(oldOption, selectedOption);
|
|
}
|
|
|
|
OptionSelected(selectedOption);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
protected override void ReadyOptions()
|
|
{
|
|
for (int i = 0; i < optionButtons.Count; i++)
|
|
{
|
|
if (optionButtons[i].gameObject.activeSelf)
|
|
{
|
|
optionButtons[i].Interactable = true;
|
|
optionButtons[i].DisplayNormal();
|
|
}
|
|
}
|
|
|
|
if (selectedOption != null)
|
|
{
|
|
OptionSelected(selectedOption);
|
|
}
|
|
|
|
StartCoroutine(HighlightOptionAfterDelay());
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override int GetSelectedOption()
|
|
{
|
|
return selectedOption.OptionIndex;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void SetOptions(List<DialogueOption> options)
|
|
{
|
|
OnOptionsSet(options);
|
|
|
|
int firstOption = -1;
|
|
|
|
for (int i = 0; i < options.Count; i++)
|
|
{
|
|
if (i > optionButtons.Count - 1)
|
|
{
|
|
if (isDynamic)
|
|
{
|
|
CreateNewOptionButton();
|
|
}
|
|
else { break; }
|
|
}
|
|
|
|
DialogueOption currentOption = options[i];
|
|
|
|
DialogueButton optionButton = optionButtons[i];
|
|
optionButton.Value = currentOption;
|
|
optionButton.Interactable = false;
|
|
optionButton.IsClickable = currentOption.IsSelectable;
|
|
optionButton.SetText(currentOption.OptionText);
|
|
|
|
if (currentOption.IsSelectable)
|
|
{
|
|
//optionButton.DisplayNormal();
|
|
if (firstOption < 0)
|
|
{
|
|
firstOption = i;
|
|
selectedOption = currentOption;
|
|
}
|
|
}
|
|
|
|
optionButton.gameObject.SetActive(true);
|
|
}
|
|
|
|
for (int i = options.Count; i < optionButtons.Count; i++)
|
|
{
|
|
optionButtons[i].gameObject.SetActive(false);
|
|
}
|
|
|
|
selectedButtonIdx = firstOption;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a new dialogue option button (cloned from the first button) and adds it to the display.
|
|
/// </summary>
|
|
/// <returns>The new DialogueButton.</returns>
|
|
protected DialogueButton CreateNewOptionButton()
|
|
{
|
|
GameObject newOptionButtonObject = GameObject.Instantiate(optionButtons[0].gameObject, optionButtons[0].transform.parent);
|
|
DialogueButton optionButton = newOptionButtonObject.GetComponent<DialogueButton>();
|
|
|
|
optionButtons.Add(optionButton);
|
|
|
|
optionButton.onClick.AddListener(
|
|
delegate
|
|
{
|
|
selectedOption = ((DialogueOption)optionButton.Value);
|
|
selectedButtonIdx = optionButtons.IndexOf(optionButton);
|
|
OptionChosen();
|
|
}
|
|
);
|
|
|
|
return optionButton;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Asynchronously highlights the selected option after a single frame delay.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private IEnumerator HighlightOptionAfterDelay()
|
|
{
|
|
yield return new WaitForEndOfFrame();
|
|
optionButtons[selectedButtonIdx].DisplayHighlighted();
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool SelectNextOption()
|
|
{
|
|
int originalIdx = selectedButtonIdx;
|
|
optionButtons[selectedButtonIdx].DisplayNormal();
|
|
|
|
DialogueOption oldOption = selectedOption;
|
|
|
|
do
|
|
{
|
|
if (reverseControls)
|
|
{
|
|
selectedButtonIdx--;
|
|
if (selectedButtonIdx < 0)
|
|
{
|
|
selectedButtonIdx = optionButtons.Count - 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
selectedButtonIdx++;
|
|
if (selectedButtonIdx >= optionButtons.Count)
|
|
{
|
|
selectedButtonIdx = 0;
|
|
}
|
|
}
|
|
|
|
if (selectedButtonIdx == originalIdx) { break; }
|
|
}
|
|
while (!optionButtons[selectedButtonIdx].isActiveAndEnabled || !optionButtons[selectedButtonIdx].IsClickable);
|
|
|
|
selectedOption = ((DialogueOption)optionButtons[selectedButtonIdx].Value);
|
|
OptionSelected(selectedOption);
|
|
|
|
if(oldOption != selectedOption)
|
|
{
|
|
OptionChanged(oldOption, selectedOption);
|
|
}
|
|
|
|
optionButtons[selectedButtonIdx].DisplayHighlighted();
|
|
optionButtons[selectedButtonIdx].PlayHoverSound();
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override bool SelectPreviousOption()
|
|
{
|
|
int originalIdx = selectedButtonIdx;
|
|
optionButtons[selectedButtonIdx].DisplayNormal();
|
|
|
|
DialogueOption oldOption = selectedOption;
|
|
|
|
do
|
|
{
|
|
if (reverseControls)
|
|
{
|
|
selectedButtonIdx++;
|
|
if (selectedButtonIdx >= optionButtons.Count)
|
|
{
|
|
selectedButtonIdx = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
selectedButtonIdx--;
|
|
if (selectedButtonIdx < 0)
|
|
{
|
|
selectedButtonIdx = optionButtons.Count - 1;
|
|
}
|
|
}
|
|
|
|
if (selectedButtonIdx == originalIdx) { break; }
|
|
}
|
|
while (!optionButtons[selectedButtonIdx].isActiveAndEnabled || !optionButtons[selectedButtonIdx].IsClickable);
|
|
|
|
selectedOption = ((DialogueOption)optionButtons[selectedButtonIdx].Value);
|
|
OptionSelected(selectedOption);
|
|
|
|
if (oldOption != selectedOption)
|
|
{
|
|
OptionChanged(oldOption, selectedOption);
|
|
}
|
|
|
|
optionButtons[selectedButtonIdx].DisplayHighlighted();
|
|
optionButtons[selectedButtonIdx].PlayHoverSound();
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override List<DialogueButton> GetOptionButtons()
|
|
{
|
|
return optionButtons;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void ActivateButtons()
|
|
{
|
|
foreach(DialogueButton button in optionButtons)
|
|
{
|
|
button.Interactable = true;
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
public override void DeactivateButtons()
|
|
{
|
|
foreach (DialogueButton button in optionButtons)
|
|
{
|
|
button.Interactable = false;
|
|
}
|
|
}
|
|
}
|
|
} |