using Chickensoft.Collections; using Godot; using System; using Zennysoft.Ma.Adapter; namespace Zennysoft.Game.Ma; public class ExperiencePointsComponent : IExperiencePointsComponent { public IAutoProp CurrentExp => _currentExp; public IAutoProp ExpToNextLevel => _expToNextLevel; public IAutoProp ExpGainRate => _expGainRate; public IAutoProp Level => _level; private readonly AutoProp _currentExp; private readonly AutoProp _expToNextLevel; private readonly AutoProp _expGainRate; private readonly AutoProp _level; public event Action PlayerLevelUp; public event Action PlayerLevelDown; public ExperiencePointsComponent() { var firstLevelExpRequirement = ExpToNextLevelCalculation(1); _expToNextLevel = new AutoProp(firstLevelExpRequirement); _currentExp = new AutoProp(0); _expGainRate = new AutoProp(1); _level = new AutoProp(1); } public void Reset() { _currentExp.OnNext(0); _expGainRate.OnNext(1); _level.OnNext(1); var firstLevelExpRequirement = ExpToNextLevelCalculation(1); _expToNextLevel.OnNext(firstLevelExpRequirement); } public void Gain(int baseExpGain) { var modifiedExpGain = baseExpGain * _expGainRate.Value; _currentExp.OnNext(Mathf.RoundToInt(modifiedExpGain + _currentExp.Value)); while (_currentExp.Value >= _expToNextLevel.Value) LevelUp(); } public void GainUnmodified(int flatRateExp) { var newCurrentExpTotal = flatRateExp + _currentExp.Value; _currentExp.OnNext(newCurrentExpTotal); while (_currentExp.Value >= _expToNextLevel.Value) LevelUp(); } public void ModifyExpGainRate(double newRate) => _expGainRate.OnNext(newRate); public void LevelUp() { SfxDatabase.Instance.Play(SoundEffect.LevelUp); _level.OnNext(_level.Value + 1); var expToNextLevel = ExpToNextLevelCalculation(_level.Value); _currentExp.OnNext(_currentExp.Value - _expToNextLevel.Value); _expToNextLevel.OnNext(expToNextLevel); PlayerLevelUp?.Invoke(); } public void LevelDown() { SfxDatabase.Instance.Play(SoundEffect.DecreaseStat); _currentExp.OnNext(0); if (_level.Value == 1) return; var newLevel = Mathf.Max(_level.Value - 1, 1); _level.OnNext(newLevel); var expToNextLevel = ExpToNextLevelCalculation(newLevel); _expToNextLevel.OnNext(expToNextLevel); PlayerLevelDown.Invoke(); } private int ExpToNextLevelCalculation(int nextLevel) { return (int)(6.5 * nextLevel + 4.5 * Math.Pow(nextLevel, 2) + Math.Pow(nextLevel, 3)); } }