using CharacterSystem; using PrizeSystem; using System; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Serialization; using UnityEngine.UI; public class PrizesSelector : MonoBehaviour, IControlable { public event Action OnConfirmed; [SerializeField] private RectTransform _addedPrizesTable; [SerializeField] private AvailablePrizesTable _availablePrizesTable; [SerializeField] private MSignalButton _selectButton; [SerializeField, FormerlySerializedAs("pointer")] private RectTransform _pointer; private readonly List _addedPrizeButtons = new(); private PrizeSet _prizeSet; private SelectionArea _selectionArea; private int _rowIndex; private bool _waitForActionRelease; public bool ControlsEnabled { get; set; } = true; private enum SelectionArea { Available, Added, Confirm } private void Awake() { _availablePrizesTable.OnPrizeConfigured += OnPrizeConfigured; _selectButton.OnClick += Confirm; } private void OnDestroy() { _availablePrizesTable.OnPrizeConfigured -= OnPrizeConfigured; _selectButton.OnClick -= Confirm; } public void Open(Character character) { gameObject.SetActive(true); _prizeSet = PrizeSystemManager.PrizeContainer.Sets[character.CharacterIndex]; RefreshView(); _selectionArea = _availablePrizesTable.PrizeButtons.Count > 0 ? SelectionArea.Available : GetInitialFallbackArea(); _rowIndex = 0; _waitForActionRelease = In.GetAction(JoystickSide.Both, InteractMode.Continious); RebuildLayouts(); UpdatePointer(); } public void UpdateControls() { bool actionPressed = In.GetAction(JoystickSide.Both, InteractMode.Continious); if (_waitForActionRelease) { _waitForActionRelease = actionPressed; return; } Vector2Int axes = In.GetAxis(JoystickSide.Both, InteractMode.Discrete); NavigateHorizontal(axes.x); NavigateVertical(axes.y); GetSelectedButton()?.TakeInput(actionPressed); } private void RefreshView() { ClearAddedPrizes(); DisplayAddedPrizes(); _availablePrizesTable.Refresh(_prizeSet); } private void DisplayAddedPrizes() { foreach (Prize prize in _prizeSet.Prizes.Where(prize => prize is not EmptyPrize)) { PrizeButton button = Instantiate(_availablePrizesTable.PrizeButtonPrefab, _addedPrizesTable); button.Configure(prize); button.OnPrize += _ => RemovePrize(prize); _addedPrizeButtons.Add(button); } } private void ClearAddedPrizes() { _addedPrizeButtons.Clear(); for (int i = _addedPrizesTable.childCount - 1; i >= 0; i--) { Transform child = _addedPrizesTable.GetChild(i); child.SetParent(null, false); Destroy(child.gameObject); } } private void OnPrizeConfigured(Prize prize) { _prizeSet.Prizes.RemoveAll(item => item is EmptyPrize); _prizeSet.Prizes.Add(prize); RefreshView(); _selectionArea = SelectionArea.Added; _rowIndex = _addedPrizeButtons.Count - 1; _waitForActionRelease = true; RebuildLayouts(); UpdatePointer(); ControlsPerformer.Instance.SetControlable(this); } private void RemovePrize(Prize prize) { _prizeSet.Prizes.Remove(prize); EnsureEmptyPrizeWhenNeeded(); RefreshView(); _selectionArea = _availablePrizesTable.PrizeButtons.Count > 0 ? SelectionArea.Available : GetInitialFallbackArea(); _rowIndex = 0; _waitForActionRelease = true; RebuildLayouts(); UpdatePointer(); } private void EnsureEmptyPrizeWhenNeeded() { if (_prizeSet.Prizes.Count == 0) _prizeSet.Prizes.Add(new EmptyPrize()); } private void NavigateHorizontal(int direction) { if (direction < 0 && _availablePrizesTable.PrizeButtons.Count > 0) { _selectionArea = SelectionArea.Available; ClampRowIndex(); UpdatePointer(); } else if (direction > 0 && _addedPrizeButtons.Count > 0) { _selectionArea = SelectionArea.Added; ClampRowIndex(); UpdatePointer(); } } private void NavigateVertical(int direction) { if (direction == 0) return; if (_selectionArea == SelectionArea.Confirm) { if (direction > 0) SelectBottomAvailableRow(); return; } int buttonsCount = GetCurrentButtons().Count; if (buttonsCount == 0) { SelectConfirm(); return; } if (direction < 0 && _rowIndex == buttonsCount - 1) SelectConfirm(); else _rowIndex = Mathf.Clamp(_rowIndex - direction, 0, buttonsCount - 1); UpdatePointer(); } private void SelectBottomAvailableRow() { if (_availablePrizesTable.PrizeButtons.Count > 0) { _selectionArea = SelectionArea.Available; _rowIndex = _availablePrizesTable.PrizeButtons.Count - 1; } else if (_addedPrizeButtons.Count > 0) { _selectionArea = SelectionArea.Added; _rowIndex = _addedPrizeButtons.Count - 1; } UpdatePointer(); } private void SelectConfirm() { _selectionArea = SelectionArea.Confirm; _rowIndex = 0; } private void ClampRowIndex() { _rowIndex = Mathf.Clamp(_rowIndex, 0, GetCurrentButtons().Count - 1); } private void UpdatePointer() { MSignalButton selectedButton = GetSelectedButton(); if (selectedButton != null) _pointer.position = selectedButton.transform.position; } private void RebuildLayouts() { Canvas.ForceUpdateCanvases(); LayoutRebuilder.ForceRebuildLayoutImmediate((RectTransform)_availablePrizesTable.transform); LayoutRebuilder.ForceRebuildLayoutImmediate(_addedPrizesTable); Canvas.ForceUpdateCanvases(); } private MSignalButton GetSelectedButton() { if (_selectionArea == SelectionArea.Confirm) return _selectButton; IReadOnlyList buttons = GetCurrentButtons(); return buttons.Count > 0 ? buttons[_rowIndex] : null; } private IReadOnlyList GetCurrentButtons() { return _selectionArea == SelectionArea.Added ? _addedPrizeButtons : _availablePrizesTable.PrizeButtons; } private SelectionArea GetInitialFallbackArea() { return _addedPrizeButtons.Count > 0 ? SelectionArea.Added : SelectionArea.Confirm; } private void Confirm() { OnConfirmed?.Invoke(); } }