Files
2026-07-09 21:33:33 +02:00

128 lines
4.4 KiB
C#

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
{
/// <summary>
/// Manages Player's main <see cref="UnitObject"/> exp and level. Also manages sources which increases experience.
/// </summary>
[DefaultExecutionOrder(-1)]
public class PlayerLevelManager : MonoBehaviour
{
public static PlayerLevelManager current { get; private set; }
// Cache
private UnitObject _mainUnit;
private Dictionary<LevelUpOption, int> _selectedOptionsCounter = new();
private List<LevelUpOption> _optionsAvailable = new();
private List<LevelUpOption> _optionsForSelection = new();
private int _remainingLevelUps;
// Config
[SerializeField] private List<LevelUpOption> _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<LevelUpOption> 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<BasicStatus>();
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();
}
}
}