Files
VOIDRPG/Assets/92 - UserInterface/Generic/Game/TurnQueueUI.cs
T
2026-07-09 21:33:33 +02:00

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;
}
}
}