using System.Collections.Generic; using System.Linq; using Sirenix.OdinInspector; using UnityEngine; using VOID.Generic.Objects.Unit; using VOID.Generic.Objects.Unit.Events; using VOID.UserInterface.Game.LevelUp; using VOID.Generic.Util; using VOID.ScriptableObjects; using VOID.ScriptableObjects.Player; namespace VOID.Generic.Player { /// /// Manages Player's main exp and level. Also manages sources which increases experience. /// [DefaultExecutionOrder(-1)] public class PlayerLevelManager : MonoBehaviour { public static PlayerLevelManager current { get; private set; } // Cache private UnitObject _mainUnit; private Dictionary _selectedOptionsCounter = new(); private List _optionsAvailable = new(); private List _optionsForSelection = new(); private int _remainingLevelUps; // Config [SerializeField] private List _options = new(); [SerializeField, MinValue(1f)] private int _optionsPerLevel = 3; private void Awake() { current = this; _optionsAvailable = _options.ToList(); } private void Start() { PlayerController.current.OnMainUnitChange += OnMainUnitChange; } private void OnMainUnitChange(UnitObject unitObject) { if (_mainUnit) { _mainUnit.unitEvents.onLevelGain.RemoveListener(OnLevelUp); } _mainUnit = unitObject; _mainUnit.unitEvents.onLevelGain.AddListener(OnLevelUp); } private void OnLevelUp(LevelGainEvent levelGainEvent) { _remainingLevelUps += levelGainEvent.amount; OpenLevelUpChoice(); } public void OpenLevelUpChoice() { // No level ups to use - do nothing if (_remainingLevelUps <= 0) return; if (_optionsAvailable.Count <= 0) { Debug.LogWarning($"No more {nameof(LevelUpOption)} available"); return; } LevelUpUI.current.Open(GetOptionsForSelection(), OnLevelUpOptionSelect); } private List GetOptionsForSelection() { // Get cached if available (when player closed previous choice without selecting) if (_optionsForSelection.Count > 0) return _optionsForSelection; var optionsAvailable = _optionsAvailable.ToList(); _optionsForSelection.Clear(); // Rebuild options for selection without repeatations while (true) { // No more available options if (optionsAvailable.Count <= 0) break; // Amount of wanted options achieved if (_optionsForSelection.Count >= _optionsPerLevel) break; // Builds options to select by player var randomOption = RandomUtil.RandomElementByWeight(optionsAvailable, option => option.weight); _optionsForSelection.Add(randomOption); optionsAvailable.Remove(randomOption); } return _optionsForSelection; } private void OnLevelUpOptionSelect(LevelUpOption option) { var status = ScriptableObject.CreateInstance(); status.displayName = option.displayName; status.displayIcon = option.displayIcon; status.description = option.displayDescription; status.effects = option.effects.ToList(); status.hidden = true; status.permanent = true; _mainUnit.statusManager.AddStatus(status); _selectedOptionsCounter.TryAdd(option, 0); _selectedOptionsCounter[option]++; // Remove options from pool when it reached its availability limit if (_selectedOptionsCounter[option] >= option.limit) _optionsAvailable.Remove(option); // Clear cache so it can be rebuild again _optionsForSelection.Clear(); // Checking if we got more level ups to distribute _remainingLevelUps--; if (_remainingLevelUps > 0) OpenLevelUpChoice(); } } }