using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UIElements;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Abstract.Events;
using VOID.Generic.Objects.Unit;
using VOID.Generic.Objects.Unit.Actions;
using VOID.Generic.Objects.Unit.Actions.Exceptions;
using VOID.Generic.Objects.Unit.Events;
using VOID.Generic.Player;
using VOID.Generic.Turn;
namespace VOID.UserInterface.Game
{
///
/// Manages ActionBar's Turn elements for current player only:
/// - Turn resources of
/// - Button to start new
/// - Buttons to and when in combat
///
public class ActionBarTurnInfoUI : MonoBehaviour
{
public static ActionBarTurnInfoUI current { get; private set; }
// ActionBar for this unit
private UnitObject _unit;
private UnitObjectActionBar _actionBar;
// Visual Elements - Turn Info
private VisualElement _turnInfoElement;
private VisualElement _actionPointsElement;
private readonly List _actionPointsElements = new();
private ProgressBar _moveBar;
private Button _nextTurnButton;
private Button _startTurnButton;
private Button _endTurnButton;
// References
private PlayerController _playerController;
private void Awake()
{
current = this;
var uiDocument = gameObject.GetComponent();
var templateElement = uiDocument.rootVisualElement;
// Find all important elements
_turnInfoElement = templateElement.Q("turn-info");
_actionPointsElement = templateElement.Q("action-points");
_moveBar = templateElement.Q("move-bar");
_nextTurnButton = templateElement.Q("next-turn");
_startTurnButton = templateElement.Q("start-turn");
_endTurnButton = templateElement.Q("end-turn");
// Remove placeholders from action points
_actionPointsElement.Clear();
_turnInfoElement.dataSource = this;
_turnInfoElement.pickingMode = PickingMode.Position;
}
private void Start()
{
_playerController = PlayerController.current;
_playerController.OnActiveUnitChange += OnActiveUnitChange;
_nextTurnButton.clicked += NextTurn;
_startTurnButton.clicked += StartTurn;
_endTurnButton.clicked += EndTurn;
}
///
/// Player order active unit to end its turn.
///
private void NextTurn()
{
if (!_unit) return;
_unit.OrderStop();
_unit.Order(new EndTurnAction(_unit));
}
///
/// Starts new turn manager - also nearby units will also join
///
private void StartTurn()
{
if (!_unit) return;
if (_unit.basicState.turnManager) return;
TurnManager.BuildGameObject(_unit);
}
///
/// Player order active unit to try end turn.
/// - If combat is FORCED then try to escape (if possible)
/// - If combat is NOT FORCED then end whole turn manager
///
private void EndTurn()
{
if (!_unit) return;
if (!_unit.basicState.turnManager) return;
// if fight is forced when try leave with current unit
// else end whole turn combat
if (_unit.basicState.turnManager.isForcedFight)
_unit.OrderInstantly(new LeaveTurnAction(_unit));
else
_unit.basicState.turnManager.EndTurnManager();
}
///
/// Depending on unit turn state it hide or show player's buttons for turn.
///
private void UpdateTurnButtonsVisibility()
{
if (_unit.basicState.turnManager)
{
_nextTurnButton.style.display = DisplayStyle.Flex;
_endTurnButton.style.display = DisplayStyle.Flex;
_startTurnButton.style.display = DisplayStyle.None;
}
else
{
_nextTurnButton.style.display = DisplayStyle.None;
_endTurnButton.style.display = DisplayStyle.None;
_startTurnButton.style.display = DisplayStyle.Flex;
}
}
///
/// 1. Stops listening to changes for previous unit
/// 2. Start listening to changes in new active unit
/// 3. Updates whole UI
///
private void OnActiveUnitChange(UnitObject unit)
{
if (_unit)
{
_unit.basicEvents.onTurnQueueEnter.RemoveListener(OnTurnEnter);
_unit.basicEvents.onTurnQueueLeave.RemoveListener(OnTurnLeave);
_unit.basicEvents.onTurnSelfStart.RemoveListener(OnTurnSelfStart);
_unit.basicEvents.onTurnSelfEnd.RemoveListener(OnTurnSelfEnd);
_unit.unitEvents.onCurrentResourceChange.RemoveListener(OnResourceChange);
_unit.unitEvents.onMaxResourceChange.RemoveListener(OnResourceChange);
}
_unit = unit;
UpdateActionPoints();
UpdateMovePoints();
UpdateTurnButtonsVisibility();
UpdateWaitingForTurn();
_unit.basicEvents.onTurnQueueEnter.AddListener(OnTurnEnter);
_unit.basicEvents.onTurnQueueLeave.AddListener(OnTurnLeave);
_unit.basicEvents.onTurnSelfStart.AddListener(OnTurnSelfStart);
_unit.basicEvents.onTurnSelfEnd.AddListener(OnTurnSelfEnd);
_unit.unitEvents.onCurrentResourceChange.AddListener(OnResourceChange);
_unit.unitEvents.onMaxResourceChange.AddListener(OnResourceChange);
}
private void OnTurnEnter(TurnEvent turnEvent)
{
UpdateTurnButtonsVisibility();
UpdateWaitingForTurn();
}
private void OnTurnLeave(TurnEvent turnEvent)
{
UpdateTurnButtonsVisibility();
UpdateWaitingForTurn();
}
private void OnTurnSelfStart(TurnEvent turnEvent)
{
UpdateWaitingForTurn();
}
private void OnTurnSelfEnd(TurnEvent turnEvent)
{
UpdateWaitingForTurn();
}
///
/// Makes ActionBar's turn elements inactive if currently active unit is waiting for its turn.
///
private void UpdateWaitingForTurn()
{
var isWaiting = _unit.basicState.turnManager && _unit.basicState.turnManager.currentUnitTurn != _unit;
_turnInfoElement.EnableInClassList("inactive", isWaiting);
}
private void OnResourceChange(UnitResourceChangeEvent resourceChangeEvent)
{
switch (resourceChangeEvent.type)
{
case UnitResourceType.ActionPoints:
UpdateActionPoints();
break;
case UnitResourceType.MovePoints:
UpdateMovePoints();
break;
default: return;
}
}
///
/// Updates current and max action points to correspond these from UnitData.
///
private void UpdateActionPoints()
{
var maxActionPoints = (int)_unit.unitData.maxResources.actionPoints;
var currentActionPoints = (int)_unit.unitData.currentResources.actionPoints;
// Add/Remove visual elements if needed
for (var i = 0; i < maxActionPoints - _actionPointsElements.Count;) AddActionPointElement();
for (var i = 0; i < _actionPointsElements.Count - maxActionPoints;) RemoveActionPointElement();
// Activate/Disable action points
for (var i = 0; i < _actionPointsElements.Count; i++)
{
var actionPointElement = _actionPointsElements[i];
actionPointElement.EnableInClassList("active-action-point", i < currentActionPoints);
}
}
///
/// Adds new action point element to UI.
///
private void AddActionPointElement()
{
var actionPointElement = new VisualElement();
actionPointElement.AddToClassList("action-point");
_actionPointsElement.Add(actionPointElement);
_actionPointsElements.Add(actionPointElement);
}
///
/// Removes one action point element from UI.
///
private void RemoveActionPointElement()
{
_actionPointsElement.Remove(_actionPointsElements.Last());
_actionPointsElements.Remove(_actionPointsElements.Last());
}
///
/// Updates current and max move points to correspond these from UnitData.
///
private void UpdateMovePoints()
{
_moveBar.highValue = _unit.unitData.maxResources.movePoints;
_moveBar.value = _unit.unitData.currentResources.movePoints;
_moveBar.title = $"{_moveBar.value:F1} / {_moveBar.highValue:F1}";
}
}
}