260 lines
11 KiB
C#
260 lines
11 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Sirenix.Utilities;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using VOID.Generic.Objects.Abstract;
|
|
using VOID.Generic.Objects.Abstract.Events;
|
|
using VOID.Generic.Objects.Unit;
|
|
using VOID.Generic.Player;
|
|
using VOID.Generic.Turn;
|
|
using VOID.UserInterface.Game.Party;
|
|
|
|
namespace VOID.UserInterface.Game
|
|
{
|
|
/// <summary>
|
|
/// Manages TurnQueue elements for current player only:<br/>
|
|
/// - Displays all participating <see cref="UnitObject"/> by their turn order with <see cref="UnitPortraitUI"/><br/>
|
|
/// - Additional info when currently active unit is waiting for its turn<br/>
|
|
/// </summary>
|
|
public class TurnQueueUI : MonoBehaviour
|
|
{
|
|
public static TurnQueueUI current { get; private set; }
|
|
|
|
// Visual Elements
|
|
private VisualElement _rootElement;
|
|
private VisualElement _currentQueueElement;
|
|
private VisualElement _nextQueueElement;
|
|
private VisualElement _waitingElement;
|
|
|
|
// Portraits for units in current and next queue
|
|
private readonly Dictionary<UnitObject, UnitPortraitUI> _currentQueuePortraits = new();
|
|
private readonly Dictionary<UnitObject, UnitPortraitUI> _nextQueuePortraits = new();
|
|
|
|
// References
|
|
private UnitObject _activeUnit;
|
|
private UnitObject _currentUnitTurn;
|
|
private TurnManager _turnManager;
|
|
|
|
private void Awake()
|
|
{
|
|
current = this;
|
|
|
|
var uiDocument = gameObject.GetComponent<UIDocument>();
|
|
var templateElement = uiDocument.rootVisualElement;
|
|
|
|
_rootElement = templateElement.Q("root-turn-queue");
|
|
_currentQueueElement = _rootElement.Q("current-queue");
|
|
_nextQueueElement = _rootElement.Q("next-queue");
|
|
_waitingElement = _rootElement.Q("waiting");
|
|
|
|
HideTurnQueue();
|
|
|
|
_rootElement.dataSource = this;
|
|
_rootElement.pickingMode = PickingMode.Position;
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
PlayerController.current.OnActiveUnitChange += OnActiveUnitChange;
|
|
}
|
|
|
|
private void OnActiveUnitChange(UnitObject nextUnit)
|
|
{
|
|
var sameQueue = false;
|
|
if (_activeUnit)
|
|
{
|
|
sameQueue = _activeUnit.basicState.turnManager == nextUnit.basicState.turnManager;
|
|
_activeUnit.basicEvents.onTurnQueueEnter.RemoveListener(OnActiveUnitTurnQueueEnter);
|
|
_activeUnit.basicEvents.onTurnQueueLeave.RemoveListener(OnActiveUnitTurnQueueLeave);
|
|
_activeUnit.basicEvents.onTurnSelfStart.RemoveListener(OnActiveUnitTurnSelfStart);
|
|
_activeUnit.basicEvents.onTurnSelfEnd.RemoveListener(OnActiveUnitTurnSelfEnd);
|
|
_activeUnit.basicEvents.onTurnQueueSwap.RemoveListener(OnActiveUnitTurnQueueSwap);
|
|
}
|
|
nextUnit.basicEvents.onTurnQueueEnter.AddListener(OnActiveUnitTurnQueueEnter);
|
|
nextUnit.basicEvents.onTurnQueueLeave.AddListener(OnActiveUnitTurnQueueLeave);
|
|
nextUnit.basicEvents.onTurnSelfStart.AddListener(OnActiveUnitTurnSelfStart);
|
|
nextUnit.basicEvents.onTurnSelfEnd.AddListener(OnActiveUnitTurnSelfEnd);
|
|
nextUnit.basicEvents.onTurnQueueSwap.AddListener(OnActiveUnitTurnQueueSwap);
|
|
|
|
if (!sameQueue)
|
|
{
|
|
HideTurnQueue();
|
|
if (nextUnit.basicState.turnManager) ShowTurnQueue(nextUnit.basicState.turnManager);
|
|
}
|
|
_activeUnit = nextUnit;
|
|
|
|
UpdateWaitingForTurn();
|
|
}
|
|
|
|
private void OnActiveUnitTurnQueueSwap(TurnEvent turnEvent)
|
|
{
|
|
_turnManager = turnEvent.turnManager;
|
|
_turnManager.allUnitsInQueue.ForEach((unit, index) =>
|
|
{
|
|
if (_nextQueuePortraits.Keys.Contains(unit)) return;
|
|
var nextUnit = _turnManager.allUnitsInQueue.ElementAtOrDefault(index + 1);
|
|
AddPortrait(unit, false, nextUnit);
|
|
});
|
|
_turnManager.unitsInCurrentQueue.ForEach((unit, index) =>
|
|
{
|
|
if (_currentQueuePortraits.Keys.Contains(unit)) return;
|
|
var nextUnit = _turnManager.unitsInCurrentQueue.ElementAtOrDefault(index + 1);
|
|
AddPortrait(unit, true, nextUnit);
|
|
});
|
|
|
|
SetActiveTurn(_turnManager.unitsInCurrentQueue.First());
|
|
}
|
|
|
|
private void OnActiveUnitTurnQueueEnter(TurnEvent turnEvent)
|
|
{
|
|
ShowTurnQueue(turnEvent.turnManager);
|
|
UpdateWaitingForTurn();
|
|
}
|
|
|
|
private void OnActiveUnitTurnQueueLeave(TurnEvent turnEvent)
|
|
{
|
|
HideTurnQueue();
|
|
UpdateWaitingForTurn();
|
|
}
|
|
|
|
private void OnActiveUnitTurnSelfStart(TurnEvent turnEvent) => UpdateWaitingForTurn();
|
|
|
|
private void OnActiveUnitTurnSelfEnd(TurnEvent turnEvent) => UpdateWaitingForTurn();
|
|
|
|
private void OnUnitEnter(AbstractObject obj)
|
|
{
|
|
if (obj is not UnitObject unit) return;
|
|
var beforeUnitInCurrent = _turnManager.unitsInCurrentQueue.ElementAtOrDefault(
|
|
_turnManager.unitsInCurrentQueue.IndexOf(unit) + 1);
|
|
var beforeUnitInNext = _turnManager.allUnitsInQueue.ElementAtOrDefault(
|
|
_turnManager.allUnitsInQueue.IndexOf(unit) + 1);
|
|
AddPortrait(unit, true, beforeUnitInCurrent);
|
|
AddPortrait(unit, false, beforeUnitInNext);
|
|
}
|
|
|
|
private void OnUnitLeave(AbstractObject obj)
|
|
{
|
|
if (obj is not UnitObject unit) return;
|
|
RemovePortrait(unit);
|
|
}
|
|
|
|
private void OnNextTurn()
|
|
{
|
|
if (_currentUnitTurn)
|
|
{
|
|
_currentQueuePortraits.GetValueOrDefault(_currentUnitTurn)?.Destroy();
|
|
_currentQueuePortraits.Remove(_currentUnitTurn);
|
|
}
|
|
_currentUnitTurn = _turnManager.currentUnitTurn;
|
|
SetActiveTurn(_currentUnitTurn);
|
|
}
|
|
|
|
private void OnNextQueue()
|
|
{
|
|
_currentUnitTurn = null;
|
|
_currentQueuePortraits.Values.ForEach(portrait => portrait.Destroy());
|
|
_currentQueuePortraits.Clear();
|
|
_turnManager.unitsInCurrentQueue.ForEach(unit => AddPortrait(unit));
|
|
}
|
|
|
|
private void ShowTurnQueue(TurnManager turnManager)
|
|
{
|
|
HideTurnQueue();
|
|
_turnManager = turnManager;
|
|
_rootElement.style.display = DisplayStyle.Flex;
|
|
_turnManager.unitsInCurrentQueue.ForEach(unit => AddPortrait(unit));
|
|
_turnManager.allUnitsInQueue.ForEach(unit => AddPortrait(unit, false));
|
|
if (_turnManager.currentUnitTurn) SetActiveTurn(_turnManager.currentUnitTurn);
|
|
_turnManager.OnNextTurn += OnNextTurn;
|
|
_turnManager.OnNextQueue += OnNextQueue;
|
|
_turnManager.OnObjectEnter += OnUnitEnter;
|
|
_turnManager.OnObjectLeave += OnUnitLeave;
|
|
_turnManager.OnNextQueueOrderChange += OnNextQueueOrderChange;
|
|
_turnManager.OnCurrentQueueOrderChange += OnCurrentQueueOrderChange;
|
|
}
|
|
|
|
private void HideTurnQueue()
|
|
{
|
|
_rootElement.style.display = DisplayStyle.None;
|
|
_currentQueuePortraits.Values.ForEach(unitPortrait => unitPortrait.Destroy());
|
|
_currentQueuePortraits.Clear();
|
|
_currentQueueElement.Clear();
|
|
_nextQueuePortraits.Values.ForEach(unitPortrait => unitPortrait.Destroy());
|
|
_nextQueuePortraits.Clear();
|
|
_nextQueueElement.Clear();
|
|
if (!_turnManager) return;
|
|
_turnManager.OnNextTurn -= OnNextTurn;
|
|
_turnManager.OnNextQueue -= OnNextQueue;
|
|
_turnManager.OnObjectEnter -= OnUnitEnter;
|
|
_turnManager.OnObjectLeave -= OnUnitLeave;
|
|
_turnManager.OnNextQueueOrderChange -= OnNextQueueOrderChange;
|
|
_turnManager.OnCurrentQueueOrderChange -= OnCurrentQueueOrderChange;
|
|
_currentUnitTurn = null;
|
|
_turnManager = null;
|
|
}
|
|
|
|
private void AddPortrait(UnitObject unit, bool putIntoCurrent = true, UnitObject putBefore = null)
|
|
{
|
|
var element = putIntoCurrent ? _currentQueueElement : _nextQueueElement;
|
|
var dict = putIntoCurrent ? _currentQueuePortraits : _nextQueuePortraits;
|
|
var unitPortrait = new UnitPortraitUI();
|
|
unitPortrait.InitNew(element);
|
|
unitPortrait.SetUnit(unit);
|
|
if (putBefore)
|
|
{
|
|
var behindElement = dict.GetValueOrDefault(putBefore).templateElement;
|
|
unitPortrait.templateElement.PlaceBehind(behindElement);
|
|
}
|
|
dict.Add(unit, unitPortrait);
|
|
}
|
|
|
|
private void RemovePortrait(UnitObject unit)
|
|
{
|
|
_currentQueuePortraits.GetValueOrDefault(unit)?.Destroy();
|
|
_nextQueuePortraits.GetValueOrDefault(unit)?.Destroy();
|
|
_currentQueuePortraits.Remove(unit);
|
|
_nextQueuePortraits.Remove(unit);
|
|
}
|
|
|
|
private void MovePortrait(UnitObject unit, bool putIntoCurrent = true, UnitObject putBefore = null)
|
|
{
|
|
var dict = putIntoCurrent ? _currentQueuePortraits : _nextQueuePortraits;
|
|
if (putBefore)
|
|
{
|
|
var behindElement = dict.GetValueOrDefault(putBefore).templateElement;
|
|
dict.GetValueOrDefault(unit).templateElement.PlaceBehind(behindElement);
|
|
}
|
|
else
|
|
{
|
|
dict.GetValueOrDefault(unit).templateElement.BringToFront();
|
|
}
|
|
}
|
|
|
|
private void OnNextQueueOrderChange(UnitObject unit, int newIndex)
|
|
{
|
|
MovePortrait(unit, false, _turnManager.allUnitsInQueue.ElementAtOrDefault(newIndex + 1));
|
|
}
|
|
|
|
private void OnCurrentQueueOrderChange(UnitObject unit, int newIndex)
|
|
{
|
|
MovePortrait(unit, true, _turnManager.unitsInCurrentQueue.ElementAtOrDefault(newIndex + 1));
|
|
}
|
|
|
|
private void SetActiveTurn(UnitObject unit)
|
|
{
|
|
_currentQueueElement.Q(className: "active-turn")?.RemoveFromClassList("active-turn");
|
|
_currentQueuePortraits.GetValueOrDefault(unit)?.templateElement.AddToClassList("active-turn");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Makes TurnQueue's waiting element visible if it is not active unit's turn.
|
|
/// </summary>
|
|
private void UpdateWaitingForTurn()
|
|
{
|
|
var isWaiting = _activeUnit.basicState.turnManager && _activeUnit.basicState.turnManager.currentUnitTurn != _activeUnit;
|
|
_waitingElement.style.display = isWaiting ? DisplayStyle.Flex : DisplayStyle.None;
|
|
}
|
|
}
|
|
}
|