244 lines
10 KiB
C#
244 lines
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Sirenix.OdinInspector;
|
|
using Sirenix.Utilities;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using VOID.Generic.Objects.Unit;
|
|
using VOID.Generic.Objects.Unit.Actions;
|
|
using VOID.Generic.Objects.Usable;
|
|
using VOID.Generic.Player.CursorOperation;
|
|
using VOID.Generic.Player.Input;
|
|
using VOID.Generic.Player.Util;
|
|
using VOID.UserInterface.Game;
|
|
using VOID.UserInterface.Game.AlertUI;
|
|
using VOID.UserInterface.Game.Util;
|
|
using VOID.ScriptableObjects.Abilities;
|
|
using PlayerInputManager = VOID.Generic.Player.Input.PlayerInputManager;
|
|
|
|
namespace VOID.Generic.Player
|
|
{
|
|
/// <summary>
|
|
/// Manages ALL inputs from player and <see cref="UnitObject"/> which player can control.
|
|
/// </summary>
|
|
[DefaultExecutionOrder(-1)]
|
|
public class PlayerController : MonoBehaviour
|
|
{
|
|
public static PlayerController current { get; private set; }
|
|
|
|
[Title("Unit currently controlled by player")]
|
|
public UnitObject activeUnit { get; private set; }
|
|
|
|
[Title("Units which player can control")]
|
|
[field: SerializeField] public UnitObject mainUnit { get; private set; }
|
|
[field: SerializeField] public UnitObject subUnit { get; private set; }
|
|
|
|
// Event
|
|
public event Action<UnitObject> OnActiveUnitChange;
|
|
public event Action<UnitObject> OnMainUnitChange;
|
|
public event Action<UnitObject> OnSubUnitChange;
|
|
|
|
// References
|
|
private AlertUI _alertUI;
|
|
private ActionBarSlotsUI _actionBarSlotsUI;
|
|
private PlayerInputManager _playerInputManager;
|
|
private ShortcutsInputManager _shortcutsInputManager;
|
|
|
|
private readonly List<AbstractCursorOperation> _playerOperations = new();
|
|
|
|
private void Awake()
|
|
{
|
|
current = this;
|
|
|
|
// Get all classes that inherits from "AbstractCursorOperation"
|
|
// BUT! In that order where children will be before parents
|
|
// So when we can choose first matching OrdersList for that specific type
|
|
AppDomain.CurrentDomain.GetAssemblies()
|
|
.SelectMany(assembly => assembly.GetTypes())
|
|
.Where(type => type.IsSubclassOf(typeof(AbstractCursorOperation)) && type.IsClass)
|
|
.Select(Activator.CreateInstance)
|
|
.Cast<AbstractCursorOperation>()
|
|
.ForEach(ordersList =>
|
|
{
|
|
var insertIndex = _playerOperations.FindIndex(otherOrderList =>
|
|
ordersList.ForType() != null && otherOrderList.ForType() != null && ordersList.ForType().IsSubclassOf(otherOrderList.ForType()));
|
|
if (insertIndex == -1) insertIndex = _playerOperations.Count;
|
|
_playerOperations.Insert(insertIndex, ordersList);
|
|
});
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
// references
|
|
_playerInputManager = PlayerInputManager.current;
|
|
_shortcutsInputManager = ShortcutsInputManager.current;
|
|
_alertUI = AlertUI.current;
|
|
_actionBarSlotsUI = ActionBarSlotsUI.current;
|
|
|
|
// left and right mouse buttons events
|
|
_playerInputManager.OnDefaultUseUI += OnPlayerDefaultUseOnUI;
|
|
_playerInputManager.OnDefaultAlternateUseUI += OnPlayerDefaultAlternateUseOnUI;
|
|
_playerInputManager.OnDefaultUse += OnPlayerDefaultUseOnScene;
|
|
_playerInputManager.OnContextUse += OnPlayerContextUse;
|
|
|
|
// Bind ESC
|
|
_shortcutsInputManager.menu.performed += _ => OnESC();
|
|
|
|
// Bind events for action bar slot shortcuts
|
|
_shortcutsInputManager.actionBarSlot1.performed += _ => OnActionBarUseShortcut(0);
|
|
_shortcutsInputManager.actionBarSlot2.performed += _ => OnActionBarUseShortcut(1);
|
|
_shortcutsInputManager.actionBarSlot3.performed += _ => OnActionBarUseShortcut(2);
|
|
_shortcutsInputManager.actionBarSlot4.performed += _ => OnActionBarUseShortcut(3);
|
|
_shortcutsInputManager.actionBarSlot5.performed += _ => OnActionBarUseShortcut(4);
|
|
_shortcutsInputManager.actionBarSlot6.performed += _ => OnActionBarUseShortcut(5);
|
|
_shortcutsInputManager.actionBarSlot7.performed += _ => OnActionBarUseShortcut(6);
|
|
_shortcutsInputManager.actionBarSlot8.performed += _ => OnActionBarUseShortcut(7);
|
|
_shortcutsInputManager.actionBarSlot9.performed += _ => OnActionBarUseShortcut(8);
|
|
_shortcutsInputManager.actionBarSlot10.performed += _ => OnActionBarUseShortcut(9);
|
|
_shortcutsInputManager.actionBarSlot11.performed += _ => OnActionBarUseShortcut(10);
|
|
_shortcutsInputManager.actionBarSlot12.performed += _ => OnActionBarUseShortcut(11);
|
|
_shortcutsInputManager.actionBarSlot13.performed += _ => OnActionBarUseShortcut(12);
|
|
_shortcutsInputManager.actionBarSlot14.performed += _ => OnActionBarUseShortcut(13);
|
|
_shortcutsInputManager.actionBarSlot15.performed += _ => OnActionBarUseShortcut(14);
|
|
_shortcutsInputManager.actionBarSlot16.performed += _ => OnActionBarUseShortcut(15);
|
|
_shortcutsInputManager.actionBarSlot17.performed += _ => OnActionBarUseShortcut(16);
|
|
_shortcutsInputManager.actionBarSlot18.performed += _ => OnActionBarUseShortcut(17);
|
|
_shortcutsInputManager.actionBarSlot19.performed += _ => OnActionBarUseShortcut(18);
|
|
_shortcutsInputManager.actionBarSlot20.performed += _ => OnActionBarUseShortcut(19);
|
|
_shortcutsInputManager.actionBarSlot21.performed += _ => OnActionBarUseShortcut(20);
|
|
_shortcutsInputManager.actionBarSlot22.performed += _ => OnActionBarUseShortcut(21);
|
|
_shortcutsInputManager.actionBarSlot23.performed += _ => OnActionBarUseShortcut(22);
|
|
_shortcutsInputManager.actionBarSlot24.performed += _ => OnActionBarUseShortcut(23);
|
|
_shortcutsInputManager.actionBarSlot25.performed += _ => OnActionBarUseShortcut(24);
|
|
}
|
|
|
|
public void SetMainUnit(UnitObject mainUnit)
|
|
{
|
|
this.mainUnit = mainUnit;
|
|
OnMainUnitChange?.Invoke(mainUnit);
|
|
}
|
|
|
|
public void SetSubUnit(UnitObject subUnit)
|
|
{
|
|
this.subUnit = subUnit;
|
|
OnSubUnitChange?.Invoke(subUnit);
|
|
}
|
|
|
|
public void SetMainUnitActive() => SetUnitActive(mainUnit);
|
|
|
|
public void SetSubUnitActive() => SetUnitActive(subUnit);
|
|
|
|
private void SetUnitActive(UnitObject unit)
|
|
{
|
|
if (activeUnit) _alertUI.StopListenFor(activeUnit);
|
|
|
|
activeUnit = unit;
|
|
_alertUI.ListenFor(activeUnit);
|
|
OnActiveUnitChange?.Invoke(activeUnit);
|
|
}
|
|
|
|
#region CURSOR - DEFAULT & CONTEXT
|
|
|
|
/// <summary>
|
|
/// Shortcuts from player to use <see cref="UsableObject"/> or <see cref="BasicAbility"/>
|
|
/// from <see cref="UnitObjectActionBar"/> in currently <see cref="activeUnit"/>.
|
|
/// </summary>
|
|
/// <param name="index">Index of slot to use</param>
|
|
private void OnActionBarUseShortcut(int index)
|
|
{
|
|
var slotUI = _actionBarSlotsUI.slotsUI[index];
|
|
|
|
if (slotUI == null) return;
|
|
if (!slotUI.item && !slotUI.ability) return;
|
|
|
|
activeUnit.OrderStop();
|
|
if (slotUI.item) activeUnit.Order(new UseAction(activeUnit, slotUI.item));
|
|
if (slotUI.ability) activeUnit.Order(new CastingAction(activeUnit, slotUI.ability));
|
|
}
|
|
|
|
private void OnPlayerDefaultAlternateUseOnUI(Vector2 cachedPosition, List<VisualElement> cachedElements)
|
|
{
|
|
HandlePlayerDefaultUseOnUI(cachedElements, true);
|
|
}
|
|
|
|
private void OnPlayerDefaultUseOnUI(Vector2 cachedPosition, List<VisualElement> cachedElements)
|
|
{
|
|
HandlePlayerDefaultUseOnUI(cachedElements);
|
|
}
|
|
|
|
private void HandlePlayerDefaultUseOnUI(List<VisualElement> cachedElements, bool isAlternate = false)
|
|
{
|
|
var select = SelectUtil.SelectFromUI(cachedElements);
|
|
|
|
// For QoL ActionBar slots can be used with single click
|
|
if (select.actionBarSlotsUI) isAlternate = false;
|
|
|
|
HandlePlayerDefaultUse(select, isAlternate);
|
|
}
|
|
|
|
private void OnPlayerDefaultUseOnScene()
|
|
{
|
|
HandlePlayerDefaultUse(SelectUtil.SelectFromScene());
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handle default use from both SCENE and UI
|
|
/// </summary>
|
|
private void HandlePlayerDefaultUse(SelectUtilResult select, bool isAlternate = false)
|
|
{
|
|
if (!activeUnit || !activeUnit.unitState.isControllable) return;
|
|
if (!select.hit) return;
|
|
var operation = _playerOperations.FirstOrDefault(operation => operation.Check(select));
|
|
operation?.DoDefault(select, isAlternate);
|
|
if (operation == null) Debug.LogError($"No Cursor Operation defined for: {select.selectObject.GetType().GetNiceName()}");
|
|
}
|
|
|
|
private void OnPlayerContextUse()
|
|
{
|
|
if (!activeUnit || !activeUnit.unitState.isControllable) return;
|
|
var select = SelectUtil.Select();
|
|
if (!select.hit) return;
|
|
var operation = _playerOperations.FirstOrDefault(operation => operation.Check(select));
|
|
operation?.DoContext(select);
|
|
if (operation == null) Debug.LogError($"No Cursor Operation defined for: {select.selectObject.GetType().GetNiceName()}");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region ESC
|
|
|
|
private void OnESC()
|
|
{
|
|
if (TryStopCasting()) return;
|
|
if (TryCloseWindowUI()) return;
|
|
if (TryTogglePauseMenu()) return;
|
|
}
|
|
|
|
private bool TryStopCasting()
|
|
{
|
|
if (!activeUnit) return false;
|
|
if (activeUnit.unitActionQueue.actionCurrent is not CastingAction) return false;
|
|
|
|
activeUnit.OrderStop();
|
|
return true;
|
|
}
|
|
|
|
private bool TryCloseWindowUI()
|
|
{
|
|
if (WindowUI.openWindows.IsNullOrEmpty()) return false;
|
|
|
|
WindowUI.openWindows.First().Close();
|
|
return true;
|
|
}
|
|
|
|
private bool TryTogglePauseMenu()
|
|
{
|
|
PauseMenuUI.current.Toggle();
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|