using System; using System.Collections.Generic; using QuickOutline; using Sirenix.OdinInspector; using UnityEngine; using VOID.Generic.Dict; using VOID.Generic.Objects.Abstract; using VOID.Generic.Objects.Item; using VOID.Generic.Objects.Unit; using VOID.Generic.Player.Input; using VOID.Generic.Player.Util; using VOID.Generic.Triggers; using VOID.UserInterface.Game.Party; using VOID.Generic.Util; using VOID.Generic.World; namespace VOID.Generic.Player { /// /// Manages Highlights and Outlines of s and s in 2 modes:
/// - When cursor is over specific object - highlight that object
/// - When button is pressed - highlight all objects in range
///
/// can be selected from SCENE or ///
[DefaultExecutionOrder(-1)] public class HighlightManager : MonoBehaviour, IDynamicTrigger { public static HighlightManager current { get; private set; } [Title("Shaders used")] [SerializeField] public Shader[] shaders; [Title("Colors")] [SerializeField] private Color _enemyColor; [SerializeField] private Color _cautiousColor; [SerializeField] private Color _neutralColor; [SerializeField] private Color _friendlyColor; [SerializeField] private Color _companionColor; [SerializeField] private Color _selfColor; [SerializeField] private Color _itemColor; [Title("Outline")] [SerializeField] private float _outlineWidth; [SerializeField] private Outline.Mode _outlineMode; [Title("Group Outline")] [SerializeField] private float _range = Area.Size; // Runtime private GameObject _highlightGameObject; private SphereCollider _collider; private Transform _stickTo; private readonly List _unitsInRange = new(); // private readonly List _objectsInRange = new(); private AbstractObject _objectUnderCursor; private void Awake() { current = this; _highlightGameObject = new GameObject("Highlight Range"); _highlightGameObject.transform.parent = gameObject.transform; _highlightGameObject.layer = LayerManager.TriggerIndex; _collider = _highlightGameObject.AddComponent(); _collider.radius = _range; _collider.isTrigger = true; } private void Start() { PlayerController.current.OnActiveUnitChange += OnActiveUnitChange; PlayerInputManager.current.OnHighlightStart += ShowHighlightForAllInRange; PlayerInputManager.current.OnHighlightEnd += HideHighlightForAllInRange; } private void FixedUpdate() { StickTo(); HighlightUnderCursor(); } private void StickTo() { if (_stickTo) _highlightGameObject.transform.position = _stickTo.position; } private void HighlightUnderCursor() { // Find whats under cursor, we allow only ItemObject (from scene) and UnitObject (from scene and portraits) var select = SelectUtil.Select(); // There is nothing under cursor, but something was previous frame! if (!select.selectObject && _objectUnderCursor) { HideHighlight(_objectUnderCursor); _objectUnderCursor = null; } // Nothing to highlight if (!select.selectObject) return; // This one was already under cursor and is highlighted previously if (select.selectObject == _objectUnderCursor) return; // There is something new under cursor - hide previous object highlight and continue if (_objectUnderCursor) HideHighlight(_objectUnderCursor); _objectUnderCursor = select.selectObject; ShowHighlight(_objectUnderCursor); } private void OnActiveUnitChange(UnitObject unitObject) { _stickTo = unitObject.transform; } public void OnObjectEnter(AbstractObject obj) { if (obj is not UnitObject unit) return; _unitsInRange.Add(unit); if (PlayerInputManager.current.isHighlight) ShowHighlight(unit); } public void OnObjectExit(AbstractObject obj) { if (obj is not UnitObject unit) return; _unitsInRange.Remove(unit); if (PlayerInputManager.current.isHighlight) HideHighlight(unit); } private void ShowHighlight(AbstractObject obj) { // Highlighting only when object allow that on itself if (!obj.basicData.canBeSelected) return; var outline = obj.gameObject.GetComponent(); if (!outline) outline = obj.gameObject.AddComponent(); if (obj is UnitObject unit) outline.OutlineColor = GetColorForUnit(unit); else outline.OutlineColor = _itemColor; outline.OutlineMode = _outlineMode; outline.OutlineWidth = _outlineWidth; outline.enabled = true; } private void HideHighlight(AbstractObject obj) { if (PlayerInputManager.current.isHighlight && obj is UnitObject unit && _unitsInRange.Contains(unit)) return; if (obj.TryGetComponent(out var outline)) outline.enabled = false; } private void ShowHighlightForAllInRange() { _unitsInRange.ForEach(ShowHighlight); } private void HideHighlightForAllInRange() { _unitsInRange.ForEach(HideHighlight); } private Color GetColorForUnit(UnitObject unit) { if (!PlayerController.current.activeUnit) return _neutralColor; if (unit == PlayerController.current.activeUnit) return _selfColor; var attitudeType = PlayerController.current.activeUnit.unitAttitude.GetAttitudeWith(unit); return attitudeType switch { AttitudeType.Hostile => _enemyColor, AttitudeType.Cautious => _cautiousColor, AttitudeType.Neutral => _neutralColor, AttitudeType.Friendly => _friendlyColor, AttitudeType.Companion => _companionColor, _ => throw new ArgumentOutOfRangeException(nameof(attitudeType), attitudeType, null) }; } } }