using System; using System.Collections.Concurrent; using System.Collections.Generic; using Microsoft.Xna.Framework; using OpenVIII.AV; using OpenVIII.IGMDataItem; namespace OpenVIII.IGMData.Group { public class PlayerEXP : Base, IDisposable { #region Fields /// /// The Speed the exp counts down. /// Cannot be 0. /// The smaller the number the faster it'll Count down. /// /// /// /// 1 /// 1000 per second /// /// /// 2 /// 500 per second /// /// /// 3 /// 333.333... per second /// /// /// 4 /// 250 per second /// /// private const float speedOfEarningExp = 4; /// /// Total exp left to earn. /// private int _exp; /// /// Are we in counting down exp mode. /// private bool countingDown; private bool disposedValue; /// /// The looping exp sound. Need to track the object here to stop the loop. /// private Audio EXPsnd; private Box header; /// /// Keeps remainder between cycles /// private double remaining; #endregion Fields #region Destructors // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. ~PlayerEXP() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(false); } #endregion Destructors #region Properties public int EXP { get => _exp; set { _exp = value; RefreshEXP(); } } public ConcurrentDictionary EXPExtra { get; set; } public bool NoEarnExp { get; internal set; } = false; private bool remainEXP => (_exp > 0 || EXPExtra != null && EXPExtra.Count > 0); #endregion Properties #region Methods public static new PlayerEXP Create(params Menu_Base[] d) => Create(d); // This code added to correctly implement the disposable pattern. public void Dispose() { // Do not change this code. Put cleanup code in Dispose(bool disposing) above. Dispose(true); // TODO: uncomment the following line if the finalizer is overridden above. GC.SuppressFinalize(this); } public override void Draw() { if (Enabled) header?.Draw(); base.Draw(); } public override bool Inputs_CANCEL() => false; public override bool Inputs_OKAY() { base.Inputs_OKAY(); if (!countingDown && remainEXP) { countingDown = true; if (EXPsnd == null) EXPsnd = Sound.Play(34, loop: true); return true; } if (countingDown && remainEXP) { countingDown = false; EXPsnd.Stop(); EXPsnd = null; EXP = 0; return true; } return false; } public override bool Update() { if (countingDown) { if (remainEXP) { if ((remaining += Memory.ElapsedGameTime.TotalMilliseconds / speedOfEarningExp) > 1) { if (EXP > 0) { EXP -= (int)remaining; } else { var total = 0; if (EXPExtra != null) { foreach (var e in EXPExtra) { if (e.Value > 0) total += (EXPExtra[e.Key] -= (int) remaining); RefreshEXP(); } if (total <= 0) EXPExtra = null; } } remaining -= (int)remaining; } } else { countingDown = false; EXPsnd.Stop(); EXPsnd = null; } } return base.Update(); } protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // TODO: dispose managed state (managed objects). } // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. // TODO: set large fields to null. header.Dispose(); disposedValue = true; } } protected override void Init() { base.Init(); Cursor_Status |= (Cursor_Status.Hidden | (Cursor_Status.Enabled | Cursor_Status.Static)); header = new Box { Data = Strings.Name.EXP_received, Pos = new Rectangle(0, 0, CONTAINER.Width, 78), Title = Icons.ID.INFO, Options = Box_Options.Middle }; } private void RefreshEXP() { foreach (var i in ITEM) { var tmpexp = EXP; if (EXPExtra != null && i.Damageable.GetCharacterData(out var c) && EXPExtra.TryGetValue(c.ID, out var bonus)) tmpexp += bonus; ((IGMData.PlayerExp)i).NoEarnExp = NoEarnExp; ((IGMData.PlayerExp)i).Exp = tmpexp; } header.Width = Width; } #endregion Methods } }