Refactor stat loading to allow spans

Can load stats without allocating
This commit is contained in:
Kurt
2022-04-08 21:08:06 -07:00
parent 274b613487
commit cc1c3e8d42
6 changed files with 47 additions and 56 deletions

View File

@@ -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<ushort> 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)

View File

@@ -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<ushort> 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));
}
/// <summary>

View File

@@ -709,45 +709,50 @@ public virtual void RefreshAbility(int n)
/// </summary>
/// <param name="p"><see cref="PersonalInfo"/> entry containing Base Stat Info</param>
/// <returns>Battle Stats (H/A/B/S/C/D)</returns>
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<ushort> 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<ushort> 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<ushort> 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;
}
/// <summary>
/// Applies the specified stats to the <see cref="PKM"/>.
/// </summary>
/// <param name="stats">Battle Stats (H/A/B/S/C/D)</param>
public void SetStats(ushort[] stats)
public void SetStats(ReadOnlySpan<ushort> stats)
{
Stat_HPMax = Stat_HPCurrent = stats[0];
Stat_ATK = stats[1];
@@ -767,7 +772,9 @@ public void SetStats(ushort[] stats)
/// </summary>
public void ResetPartyStats()
{
SetStats(GetStats(PersonalInfo));
Span<ushort> stats = stackalloc ushort[6];
LoadStats(PersonalInfo, stats);
SetStats(stats);
Stat_Level = CurrentLevel;
Status_Condition = 0;
}

View File

@@ -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<ushort> 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)

View File

@@ -100,7 +100,7 @@ public static bool GetNatureModification(int nature, out int incr, out int decr)
/// </summary>
/// <param name="stats">Current stats to amplify if appropriate</param>
/// <param name="nature">Nature</param>
public static void ModifyStatsForNature(ushort[] stats, int nature)
public static void ModifyStatsForNature(Span<ushort> stats, int nature)
{
if (GetNatureModification(nature, out int incr, out int decr))
return;

View File

@@ -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();
}
/// <summary>