Split min sheen calc for 3 & 4, revise limits

Thanks @SadisticMystic!

https: //github.com/kwsch/PKHeX/commit/9ce0da6c46ebea3c7c6edd1f1e0571e5ecbec739#r63579484
Co-Authored-By: Russell Jones <questiondesk@gmail.com>
This commit is contained in:
Kurt 2022-01-11 23:29:01 -08:00
parent da9d09ea76
commit bb2a63bbce
3 changed files with 60 additions and 15 deletions

View file

@ -41,13 +41,13 @@ public sealed class ContestStatVerifier : Verifier
else if (correlation == CorrelateSheen) else if (correlation == CorrelateSheen)
{ {
bool gen3 = data.Info.Generation == 3; bool gen3 = data.Info.Generation == 3;
bool bdsp = pkm.HasVisitedBDSP(data.Info.EncounterOriginal.Species);
var method = gen3 ? ContestStatGrantingSheen.Gen3 :
bdsp ? ContestStatGrantingSheen.Gen8b : ContestStatGrantingSheen.Gen4;
// Check for stat values that exceed a valid sheen value. // Check for stat values that exceed a valid sheen value.
var initial = GetReferenceTemplate(data.Info.EncounterMatch); var initial = GetReferenceTemplate(data.Info.EncounterMatch);
bool bdsp = pkm.HasVisitedBDSP(data.Info.EncounterOriginal.Species); var minSheen = CalculateMinimumSheen(s, initial, pkm, method);
var minSheen = bdsp
? CalculateMinimumSheen8b(s, pkm.Nature, initial)
: CalculateMinimumSheen(s, pkm.Nature, initial, gen3);
if (s.CNT_Sheen < minSheen) if (s.CNT_Sheen < minSheen)
data.AddLine(GetInvalid(string.Format(LContestSheenTooLow_0, minSheen))); data.AddLine(GetInvalid(string.Format(LContestSheenTooLow_0, minSheen)));

View file

@ -11,3 +11,10 @@ public enum ContestStatGranting
/// <summary> Contest stats are possible to obtain, and has visited a multitude of games such that any value of sheen is possible. </summary> /// <summary> Contest stats are possible to obtain, and has visited a multitude of games such that any value of sheen is possible. </summary>
Mixed, Mixed,
} }
public enum ContestStatGrantingSheen
{
Gen3,
Gen4,
Gen8b,
}

View file

@ -5,11 +5,26 @@ namespace PKHeX.Core;
public static class ContestStatInfo public static class ContestStatInfo
{ {
private const int LowestFeelBlock3 = 3; private const int LowestFeelBlock3 = 1; // quad Nutpea
private const int LowestFeelPoffin4 = 17; private const int LowestFeelPoffin4 = 16;
private const int LowestFeelPoffin8b = 8; private const int LowestFeelPoffin8b = 7;
private const int MaxContestStat = 255;
private const int BestSheenStat8b = 160; // using optimal poffins in BD/SP, roughly 160-170; be generous. private const byte MaxContestStat = 255;
/// <summary>
/// By giving out all-Nutpea blocks in 3, you can have contest stats all maxed while feel is at 214 if the random stats of the foul blocks line up perfectly.
/// </summary>
private const int BestSheenStat3 = 214;
/// <summary>
/// Using optimal poffins in BD/SP, roughly 120-140; be generous.
/// </summary>
/// <remarks>
/// Liechi-Pomeg-Qualot-Occa etc. (2 each), which puts sheen at 140 and will max all stats if the cook times are 47.43 or faster
/// Leppa-Pomeg-Qualot-Occa etc. (3 each), which puts sheen at 135 and will max all stats if the cook times are 43.32 or faster
/// Liechi-Leppa-Pomeg-Qualot etc. (2 each), which puts sheen at 120 and will max all stats if the cook times area 40.40 or faster
/// </remarks>
private const int BestSheenStat8b = 120;
public static void SetSuggestedContestStats(this PKM pk, IEncounterTemplate enc) public static void SetSuggestedContestStats(this PKM pk, IEncounterTemplate enc)
{ {
@ -21,7 +36,7 @@ public static class ContestStatInfo
if (restrict == None || pk.Species is not (int)Species.Milotic) if (restrict == None || pk.Species is not (int)Species.Milotic)
baseStat.CopyContestStatsTo(s); // reset baseStat.CopyContestStatsTo(s); // reset
else else
s.SetAllContestStatsTo(MaxContestStat, restrict == NoSheen ? baseStat.CNT_Sheen : (byte)255); s.SetAllContestStatsTo(MaxContestStat, restrict == NoSheen ? baseStat.CNT_Sheen : MaxContestStat);
} }
public static void SetMaxContestStats(this PKM pk, IEncounterTemplate enc) public static void SetMaxContestStats(this PKM pk, IEncounterTemplate enc)
@ -32,7 +47,7 @@ public static class ContestStatInfo
var baseStat = GetReferenceTemplate(enc); var baseStat = GetReferenceTemplate(enc);
if (restrict == None) if (restrict == None)
return; return;
s.SetAllContestStatsTo(MaxContestStat, restrict == NoSheen ? baseStat.CNT_Sheen : (byte)255); s.SetAllContestStatsTo(MaxContestStat, restrict == NoSheen ? baseStat.CNT_Sheen : MaxContestStat);
} }
public static ContestStatGranting GetContestStatRestriction(PKM pk, int origin) => origin switch public static ContestStatGranting GetContestStatRestriction(PKM pk, int origin) => origin switch
@ -65,6 +80,14 @@ public static class ContestStatInfo
return Math.Min(MaxContestStat, avg * LowestFeelPoffin4); return Math.Min(MaxContestStat, avg * LowestFeelPoffin4);
} }
public static int CalculateMinimumSheen(IContestStats s, IContestStats initial, INature pkm, ContestStatGrantingSheen method) => method switch
{
ContestStatGrantingSheen.Gen8b => CalculateMinimumSheen8b(s, pkm.Nature, initial),
ContestStatGrantingSheen.Gen3 => CalculateMinimumSheen3(s, pkm.Nature, initial),
ContestStatGrantingSheen.Gen4 => CalculateMinimumSheen4(s, pkm.Nature, initial),
_ => throw new IndexOutOfRangeException(nameof(method))
};
// Slightly better stat:sheen ratio than Gen4; prefer if has visited. // Slightly better stat:sheen ratio than Gen4; prefer if has visited.
public static int CalculateMinimumSheen8b(IContestStats s, int nature, IContestStats initial) public static int CalculateMinimumSheen8b(IContestStats s, int nature, IContestStats initial)
{ {
@ -77,12 +100,12 @@ public static class ContestStatInfo
var avg = Math.Max(1, nature % 6 == 0 ? rawAvg : GetAverageFeel(s, nature, initial)); var avg = Math.Max(1, nature % 6 == 0 ? rawAvg : GetAverageFeel(s, nature, initial));
avg = Math.Min(rawAvg, avg); // be generous avg = Math.Min(rawAvg, avg); // be generous
avg = (avg * 8) / 10; // even more generous?? sheen formula undocumented avg = (BestSheenStat8b * avg) / MaxContestStat;
return Math.Min(BestSheenStat8b, Math.Max(LowestFeelPoffin8b, avg)); return Math.Min(BestSheenStat8b, Math.Max(LowestFeelPoffin8b, avg));
} }
public static int CalculateMinimumSheen(IContestStats s, int nature, IContestStats initial, bool pokeBlock3) public static int CalculateMinimumSheen3(IContestStats s, int nature, IContestStats initial)
{ {
if (s.IsContestEqual(initial)) if (s.IsContestEqual(initial))
return initial.CNT_Sheen; return initial.CNT_Sheen;
@ -94,8 +117,23 @@ public static class ContestStatInfo
var avg = Math.Max(1, nature % 6 == 0 ? rawAvg : GetAverageFeel(s, nature, initial)); var avg = Math.Max(1, nature % 6 == 0 ? rawAvg : GetAverageFeel(s, nature, initial));
avg = Math.Min(rawAvg, avg); // be generous avg = Math.Min(rawAvg, avg); // be generous
var worst = pokeBlock3 ? LowestFeelBlock3 : LowestFeelPoffin4; avg = (BestSheenStat3 * avg) / MaxContestStat;
return Math.Min(MaxContestStat, Math.Max(worst, avg)); return Math.Min(BestSheenStat3, Math.Max(LowestFeelBlock3, avg));
}
public static int CalculateMinimumSheen4(IContestStats s, int nature, IContestStats initial)
{
if (s.IsContestEqual(initial))
return initial.CNT_Sheen;
var rawAvg = GetAverageFeel(s, 0, initial);
if (rawAvg == MaxContestStat)
return MaxContestStat;
var avg = Math.Max(1, nature % 6 == 0 ? rawAvg : GetAverageFeel(s, nature, initial));
avg = Math.Min(rawAvg, avg); // be generous
return Math.Min(MaxContestStat, Math.Max(LowestFeelPoffin4, avg));
} }
private static int CalculateMaximumSheen3(IContestStats s, int nature, IContestStats initial) private static int CalculateMaximumSheen3(IContestStats s, int nature, IContestStats initial)