using Microsoft.Xna.Framework; using OpenVIII.IGMDataItem; using System; using System.Collections.Concurrent; namespace OpenVIII.IGMData.Group { public class PlayerEXP : IGMData.Group.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 = false; private bool disposedValue = false; /// /// The looping exp sound. Need to track the object here to stop the loop. /// private AV.Audio EXPsnd = null; private Box header; /// /// Keeps remainder between cycles /// private double remaining = 0; #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 = init_debugger_Audio.PlaySound(34, loop: true); return true; } else 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.gameTime.ElapsedGameTime.TotalMilliseconds / speedOfEarningExp) > 1) { if (EXP > 0) { EXP -= (int)remaining; } else { int total = 0; foreach (System.Collections.Generic.KeyValuePair 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 IGMDataItem.Box { Data = Memory.Strings.Read(Strings.FileID.KERNEL, 30, 23), Pos = new Rectangle(0, 0, CONTAINER.Width, 78), Title = Icons.ID.INFO, Options = Box_Options.Middle }; } private void RefreshEXP() { foreach (Menu_Base i in ITEM) { int tmpexp = EXP; if (EXPExtra != null && i.Damageable.GetCharacterData(out Saves.CharacterData c) && EXPExtra.TryGetValue(c.ID, out int bonus)) tmpexp += bonus; ((IGMData.PlayerEXP)i).NoEarnExp = NoEarnExp; ((IGMData.PlayerEXP)i).EXP = tmpexp; } header.Width = Width; } #endregion Methods } }