From cc1c3e8d42ded704304e095ac08afe4d4accff9e Mon Sep 17 00:00:00 2001 From: Kurt Date: Fri, 8 Apr 2022 21:08:06 -0700 Subject: [PATCH] Refactor stat loading to allow spans Can load stats without allocating --- PKHeX.Core/PKM/PA8.cs | 19 +++++++----------- PKHeX.Core/PKM/PB7.cs | 19 +++++++----------- PKHeX.Core/PKM/PKM.cs | 35 ++++++++++++++++++++-------------- PKHeX.Core/PKM/Shared/GBPKM.cs | 25 ++++++++++-------------- PKHeX.Core/PKM/Util/PKX.cs | 2 +- PKHeX.Core/Saves/SaveFile.cs | 3 +-- 6 files changed, 47 insertions(+), 56 deletions(-) diff --git a/PKHeX.Core/PKM/PA8.cs b/PKHeX.Core/PKM/PA8.cs index 84e0566ee..6e5b85458 100644 --- a/PKHeX.Core/PKM/PA8.cs +++ b/PKHeX.Core/PKM/PA8.cs @@ -563,22 +563,17 @@ public void SetMasteredRecordFlag(int index, bool value) public override int Stat_SPD { get => ReadUInt16LittleEndian(Data.AsSpan(0x174)); set => WriteUInt16LittleEndian(Data.AsSpan(0x174), (ushort)value); } #endregion - public override ushort[] GetStats(PersonalInfo p) => CalculateStatsArceus(p); - - public ushort[] CalculateStatsArceus(PersonalInfo p) + public override void LoadStats(PersonalInfo p, Span stats) { int level = CurrentLevel; int nature = StatNature; - return new[] - { - (ushort)(GetGanbaruStat(p.HP, HT_HP ? 31 : IV_HP, GV_HP, level) + GetStatHp(p.HP, level)), - (ushort)(GetGanbaruStat(p.ATK, HT_ATK ? 31 : IV_ATK, GV_ATK, level) + GetStat(p.ATK, level, nature, 0)), - (ushort)(GetGanbaruStat(p.DEF, HT_DEF ? 31 : IV_DEF, GV_DEF, level) + GetStat(p.DEF, level, nature, 1)), - (ushort)(GetGanbaruStat(p.SPE, HT_SPE ? 31 : IV_SPE, GV_SPE, level) + GetStat(p.SPE, level, nature, 4)), - (ushort)(GetGanbaruStat(p.SPA, HT_SPA ? 31 : IV_SPA, GV_SPA, level) + GetStat(p.SPA, level, nature, 2)), - (ushort)(GetGanbaruStat(p.SPD, HT_SPD ? 31 : IV_SPD, GV_SPD, level) + GetStat(p.SPD, level, nature, 3)), - }; + stats[0] = (ushort)(GetGanbaruStat(p.HP, HT_HP ? 31 : IV_HP, GV_HP, level) + GetStatHp(p.HP, level)); + stats[1] = (ushort)(GetGanbaruStat(p.ATK, HT_ATK ? 31 : IV_ATK, GV_ATK, level) + GetStat(p.ATK, level, nature, 0)); + stats[2] = (ushort)(GetGanbaruStat(p.DEF, HT_DEF ? 31 : IV_DEF, GV_DEF, level) + GetStat(p.DEF, level, nature, 1)); + stats[3] = (ushort)(GetGanbaruStat(p.SPE, HT_SPE ? 31 : IV_SPE, GV_SPE, level) + GetStat(p.SPE, level, nature, 4)); + stats[4] = (ushort)(GetGanbaruStat(p.SPA, HT_SPA ? 31 : IV_SPA, GV_SPA, level) + GetStat(p.SPA, level, nature, 2)); + stats[5] = (ushort)(GetGanbaruStat(p.SPD, HT_SPD ? 31 : IV_SPD, GV_SPD, level) + GetStat(p.SPD, level, nature, 3)); } public static int GetGanbaruStat(int baseStat, int iv, byte gv, int level) diff --git a/PKHeX.Core/PKM/PB7.cs b/PKHeX.Core/PKM/PB7.cs index 85f987f4b..5a335b36f 100644 --- a/PKHeX.Core/PKM/PB7.cs +++ b/PKHeX.Core/PKM/PB7.cs @@ -364,23 +364,18 @@ public void FixMemories() public override int MaxBallID => Legal.MaxBallID_7; public override int MaxGameID => Legal.MaxGameID_7b; - public override ushort[] GetStats(PersonalInfo p) => CalculateStatsBeluga(p); - - public ushort[] CalculateStatsBeluga(PersonalInfo p) + public override void LoadStats(PersonalInfo p, Span stats) { int level = CurrentLevel; int nature = Nature; int friend = CurrentFriendship; // stats +10% depending on friendship! int scalar = (int)(((friend / 255.0f / 10.0f) + 1.0f) * 100.0f); - return new[] - { - (ushort)(AV_HP + GetStat(p.HP, HT_HP ? 31 : IV_HP, level) + 10 + level), - (ushort)(AV_ATK + (scalar * GetStat(p.ATK, HT_ATK ? 31 : IV_ATK, level, nature, 0) / 100)), - (ushort)(AV_DEF + (scalar * GetStat(p.DEF, HT_DEF ? 31 : IV_DEF, level, nature, 1) / 100)), - (ushort)(AV_SPE + (scalar * GetStat(p.SPE, HT_SPE ? 31 : IV_SPE, level, nature, 4) / 100)), - (ushort)(AV_SPA + (scalar * GetStat(p.SPA, HT_SPA ? 31 : IV_SPA, level, nature, 2) / 100)), - (ushort)(AV_SPD + (scalar * GetStat(p.SPD, HT_SPD ? 31 : IV_SPD, level, nature, 3) / 100)), - }; + stats[0] = (ushort)(AV_HP + GetStat(p.HP, HT_HP ? 31 : IV_HP, level) + 10 + level); + stats[1] = (ushort)(AV_ATK + (scalar * GetStat(p.ATK, HT_ATK ? 31 : IV_ATK, level, nature, 0) / 100)); + stats[2] = (ushort)(AV_DEF + (scalar * GetStat(p.DEF, HT_DEF ? 31 : IV_DEF, level, nature, 1) / 100)); + stats[3] = (ushort)(AV_SPE + (scalar * GetStat(p.SPE, HT_SPE ? 31 : IV_SPE, level, nature, 4) / 100)); + stats[4] = (ushort)(AV_SPA + (scalar * GetStat(p.SPA, HT_SPA ? 31 : IV_SPA, level, nature, 2) / 100)); + stats[5] = (ushort)(AV_SPD + (scalar * GetStat(p.SPD, HT_SPD ? 31 : IV_SPD, level, nature, 3) / 100)); } /// diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index 44cb1ec1f..e041abeff 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -709,45 +709,50 @@ public virtual void RefreshAbility(int n) /// /// entry containing Base Stat Info /// Battle Stats (H/A/B/S/C/D) - public virtual ushort[] GetStats(PersonalInfo p) + public ushort[] GetStats(PersonalInfo p) { - int level = CurrentLevel; - - ushort[] stats = this is IHyperTrain t ? GetStats(p, t, level) : GetStats(p, level); - // Account for nature - PKX.ModifyStatsForNature(stats, StatNature); + ushort[] stats = new ushort[6]; + LoadStats(p, stats); return stats; } - private ushort[] GetStats(PersonalInfo p, IHyperTrain t, int level) + public virtual void LoadStats(PersonalInfo p, Span stats) + { + int level = CurrentLevel; // recalculate instead of checking Stat_Level + if (this is IHyperTrain t) + LoadStats(stats, p, t, level); + else + LoadStats(stats, p, level); + + // Account for nature + PKX.ModifyStatsForNature(stats, StatNature); + } + + private void LoadStats(Span stats, PersonalInfo p, IHyperTrain t, int level) { - ushort[] stats = new ushort[6]; stats[0] = (ushort)(p.HP == 1 ? 1 : (((t.HT_HP ? 31 : IV_HP) + (2 * p.HP) + (EV_HP / 4) + 100) * level / 100) + 10); stats[1] = (ushort)((((t.HT_ATK ? 31 : IV_ATK) + (2 * p.ATK) + (EV_ATK / 4)) * level / 100) + 5); stats[2] = (ushort)((((t.HT_DEF ? 31 : IV_DEF) + (2 * p.DEF) + (EV_DEF / 4)) * level / 100) + 5); stats[4] = (ushort)((((t.HT_SPA ? 31 : IV_SPA) + (2 * p.SPA) + (EV_SPA / 4)) * level / 100) + 5); stats[5] = (ushort)((((t.HT_SPD ? 31 : IV_SPD) + (2 * p.SPD) + (EV_SPD / 4)) * level / 100) + 5); stats[3] = (ushort)((((t.HT_SPE ? 31 : IV_SPE) + (2 * p.SPE) + (EV_SPE / 4)) * level / 100) + 5); - return stats; } - private ushort[] GetStats(PersonalInfo p, int level) + private void LoadStats(Span stats, PersonalInfo p, int level) { - ushort[] stats = new ushort[6]; stats[0] = (ushort)(p.HP == 1 ? 1 : ((IV_HP + (2 * p.HP) + (EV_HP / 4) + 100) * level / 100) + 10); stats[1] = (ushort)(((IV_ATK + (2 * p.ATK) + (EV_ATK / 4)) * level / 100) + 5); stats[2] = (ushort)(((IV_DEF + (2 * p.DEF) + (EV_DEF / 4)) * level / 100) + 5); stats[4] = (ushort)(((IV_SPA + (2 * p.SPA) + (EV_SPA / 4)) * level / 100) + 5); stats[5] = (ushort)(((IV_SPD + (2 * p.SPD) + (EV_SPD / 4)) * level / 100) + 5); stats[3] = (ushort)(((IV_SPE + (2 * p.SPE) + (EV_SPE / 4)) * level / 100) + 5); - return stats; } /// /// Applies the specified stats to the . /// /// Battle Stats (H/A/B/S/C/D) - public void SetStats(ushort[] stats) + public void SetStats(ReadOnlySpan stats) { Stat_HPMax = Stat_HPCurrent = stats[0]; Stat_ATK = stats[1]; @@ -767,7 +772,9 @@ public void SetStats(ushort[] stats) /// public void ResetPartyStats() { - SetStats(GetStats(PersonalInfo)); + Span stats = stackalloc ushort[6]; + LoadStats(PersonalInfo, stats); + SetStats(stats); Stat_Level = CurrentLevel; Status_Condition = 0; } diff --git a/PKHeX.Core/PKM/Shared/GBPKM.cs b/PKHeX.Core/PKM/Shared/GBPKM.cs index ded1c36ed..d5405463c 100644 --- a/PKHeX.Core/PKM/Shared/GBPKM.cs +++ b/PKHeX.Core/PKM/Shared/GBPKM.cs @@ -193,26 +193,21 @@ protected int TransferLanguage(int destLanguage) return GuessedLanguage(destLanguage); } - public sealed override ushort[] GetStats(PersonalInfo p) + public override void LoadStats(PersonalInfo p, Span stats) { var lv = Stat_Level; - ushort[] stats = - { - GetStat(p.HP , IV_HP , EV_HP , lv), - GetStat(p.ATK, IV_ATK, EV_ATK, lv), - GetStat(p.DEF, IV_DEF, EV_DEF, lv), - GetStat(p.SPE, IV_SPE, EV_SPE, lv), - GetStat(p.SPA, IV_SPA, EV_SPA, lv), - GetStat(p.SPD, IV_SPD, EV_SPD, lv), - }; - stats[0] += (ushort)(5 + lv); // HP - return stats; + stats[0] = (ushort)(GetStat(p.HP, IV_HP, EV_HP, lv) + (5 + lv)); // HP + stats[1] = GetStat(p.ATK, IV_ATK, EV_ATK, lv); + stats[2] = GetStat(p.DEF, IV_DEF, EV_DEF, lv); + stats[3] = GetStat(p.SPE, IV_SPE, EV_SPE, lv); + stats[4] = GetStat(p.SPA, IV_SPA, EV_SPA, lv); + stats[5] = GetStat(p.SPD, IV_SPD, EV_SPD, lv); } - protected static ushort GetStat(int BV, int IV, int EV, int LV) + protected static ushort GetStat(int baseStat, int iv, int effort, int level) { - EV = (ushort)Math.Min(255, Math.Sqrt(EV) + 1) >> 2; - return (ushort)((((2 * (BV + IV)) + EV) * LV / 100) + 5); + effort = (ushort)Math.Min(255, Math.Sqrt(effort) + 1) >> 2; + return (ushort)((((2 * (baseStat + iv)) + effort) * level / 100) + 5); } public sealed override int GetMovePP(int move, int ppUpCount) diff --git a/PKHeX.Core/PKM/Util/PKX.cs b/PKHeX.Core/PKM/Util/PKX.cs index b6c3e77ff..37905f4e5 100644 --- a/PKHeX.Core/PKM/Util/PKX.cs +++ b/PKHeX.Core/PKM/Util/PKX.cs @@ -100,7 +100,7 @@ public static bool GetNatureModification(int nature, out int incr, out int decr) /// /// Current stats to amplify if appropriate /// Nature - public static void ModifyStatsForNature(ushort[] stats, int nature) + public static void ModifyStatsForNature(Span stats, int nature) { if (GetNatureModification(nature, out int incr, out int decr)) return; diff --git a/PKHeX.Core/Saves/SaveFile.cs b/PKHeX.Core/Saves/SaveFile.cs index c24d879c1..2db060a97 100644 --- a/PKHeX.Core/Saves/SaveFile.cs +++ b/PKHeX.Core/Saves/SaveFile.cs @@ -457,8 +457,7 @@ protected virtual void SetPartyValues(PKM pkm, bool isParty) return; if (pkm.PartyStatsPresent) // Stats already present return; - pkm.SetStats(pkm.GetStats(pkm.PersonalInfo)); - pkm.Stat_Level = pkm.CurrentLevel; + pkm.ResetPartyStats(); } ///