From c021f893f8f984c4f0fbf66e57858d947ca3cfde Mon Sep 17 00:00:00 2001 From: Kurt Date: Sun, 31 Dec 2023 11:02:23 -0800 Subject: [PATCH] Inject rule bypass logic for SV's level100 lvlup Closes #4143 --- .../EvolutionGroup/EvolutionGroup1.cs | 8 ++-- .../EvolutionGroup/EvolutionGroup2.cs | 5 ++- .../EvolutionGroup/EvolutionGroup3.cs | 5 ++- .../EvolutionGroup/EvolutionGroup4.cs | 5 ++- .../EvolutionGroup/EvolutionGroup5.cs | 5 ++- .../EvolutionGroup/EvolutionGroup6.cs | 5 ++- .../EvolutionGroup/EvolutionGroup7.cs | 5 ++- .../EvolutionGroup/EvolutionGroup7b.cs | 5 ++- .../EvolutionGroup/EvolutionGroupHOME.cs | 26 ++++++------- .../Legality/Evolutions/EvolutionRuleTweak.cs | 22 +++++++++++ .../Forward/EvolutionForwardPersonal.cs | 25 +++++++++--- .../Forward/EvolutionForwardSpecies.cs | 7 ++-- .../Evolutions/Forward/IEvolutionForward.cs | 3 +- .../Evolutions/Methods/EvolutionMethod.cs | 7 +++- .../Evolutions/Reversal/EvolutionReversal.cs | 38 +++++++++++++------ .../Reversal/EvolutionReversePersonal.cs | 5 ++- .../Reversal/EvolutionReverseSpecies.cs | 5 ++- .../Evolutions/Reversal/IEvolutionReverse.cs | 3 +- 18 files changed, 127 insertions(+), 57 deletions(-) create mode 100644 PKHeX.Core/Legality/Evolutions/EvolutionRuleTweak.cs diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup1.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup1.cs index 5aa60a3e2..a33ae0088 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup1.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup1.cs @@ -6,6 +6,7 @@ public sealed class EvolutionGroup1 : IEvolutionGroup, IEvolutionEnvironment { public static readonly EvolutionGroup1 Instance = new(); private static readonly EvolutionTree Tree = EvolutionTree.Evolves1; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public IEvolutionGroup GetNext(PKM pk, EvolutionOrigin enc) => EvolutionGroup2.Instance; public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) => pk.Format == 1 && ParseSettings.AllowGen1Tradeback ? EvolutionGroup2.Instance : null; @@ -43,9 +44,10 @@ public sealed class EvolutionGroup1 : IEvolutionGroup, IEvolutionEnvironment return present; } - public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm + public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) + where T : ISpeciesForm { - return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public int Evolve(Span result, PKM pk, EvolutionOrigin enc, EvolutionHistory history) @@ -75,6 +77,6 @@ public sealed class EvolutionGroup1 : IEvolutionGroup, IEvolutionEnvironment public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup2.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup2.cs index 0b3f6317f..0815776ee 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup2.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup2.cs @@ -8,6 +8,7 @@ public sealed class EvolutionGroup2 : IEvolutionGroup private static readonly EvolutionTree Tree = EvolutionTree.Evolves2; private const int Generation = 2; private static PersonalTable2 Personal => PersonalTable.C; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => pk.Format > Generation ? EvolutionGroup7.Instance : null; public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) => pk.Format != 1 ? EvolutionGroup1.Instance : null; @@ -45,7 +46,7 @@ public sealed class EvolutionGroup2 : IEvolutionGroup public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public int Evolve(Span result, PKM pk, EvolutionOrigin enc, EvolutionHistory history) @@ -75,6 +76,6 @@ public sealed class EvolutionGroup2 : IEvolutionGroup public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup3.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup3.cs index a6745427d..0953f79a3 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup3.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup3.cs @@ -8,6 +8,7 @@ public sealed class EvolutionGroup3 : IEvolutionGroup private static readonly EvolutionTree Tree = EvolutionTree.Evolves3; private const int Generation = 3; private static PersonalTable3 Personal => PersonalTable.E; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => pk.Format > Generation ? EvolutionGroup4.Instance : null; public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) => null; @@ -39,7 +40,7 @@ public sealed class EvolutionGroup3 : IEvolutionGroup public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public int Evolve(Span result, PKM pk, EvolutionOrigin enc, EvolutionHistory history) @@ -69,6 +70,6 @@ public sealed class EvolutionGroup3 : IEvolutionGroup public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup4.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup4.cs index c6ca1ff22..d50557e13 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup4.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup4.cs @@ -8,6 +8,7 @@ public sealed class EvolutionGroup4 : IEvolutionGroup private static readonly EvolutionTree Tree = EvolutionTree.Evolves4; private const int Generation = 4; private static PersonalTable4 Personal => PersonalTable.HGSS; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => pk.Format > Generation ? EvolutionGroup5.Instance : null; public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) => enc.Generation == 3 ? EvolutionGroup3.Instance : null; @@ -39,7 +40,7 @@ public sealed class EvolutionGroup4 : IEvolutionGroup public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public int Evolve(Span result, PKM pk, EvolutionOrigin enc, EvolutionHistory history) @@ -71,6 +72,6 @@ public sealed class EvolutionGroup4 : IEvolutionGroup public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup5.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup5.cs index 3d1eef307..fc47fe6ae 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup5.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup5.cs @@ -8,6 +8,7 @@ public sealed class EvolutionGroup5 : IEvolutionGroup private static readonly EvolutionTree Tree = EvolutionTree.Evolves5; private const int Generation = 5; private static PersonalTable5B2W2 Personal => PersonalTable.B2W2; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => pk.Format > Generation ? EvolutionGroup6.Instance : null; public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) => enc.Generation < Generation ? EvolutionGroup4.Instance : null; @@ -32,7 +33,7 @@ public sealed class EvolutionGroup5 : IEvolutionGroup public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public int Evolve(Span result, PKM pk, EvolutionOrigin enc, EvolutionHistory history) @@ -62,6 +63,6 @@ public sealed class EvolutionGroup5 : IEvolutionGroup public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup6.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup6.cs index c43f9e9a2..78c09a94d 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup6.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup6.cs @@ -8,6 +8,7 @@ public sealed class EvolutionGroup6 : IEvolutionGroup private static readonly EvolutionTree Tree = EvolutionTree.Evolves6; private const int Generation = 6; private static PersonalTable6AO Personal => PersonalTable.AO; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => pk.Format > Generation ? EvolutionGroup7.Instance : null; public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) => enc.Generation < Generation ? EvolutionGroup5.Instance : null; @@ -39,7 +40,7 @@ public sealed class EvolutionGroup6 : IEvolutionGroup public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public int Evolve(Span result, PKM pk, EvolutionOrigin enc, EvolutionHistory history) @@ -66,6 +67,6 @@ public sealed class EvolutionGroup6 : IEvolutionGroup public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup7.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup7.cs index 9fdcbe150..990a3ca8e 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup7.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup7.cs @@ -8,6 +8,7 @@ public sealed class EvolutionGroup7 : IEvolutionGroup private static readonly EvolutionTree Tree = EvolutionTree.Evolves7; private const int Generation = 7; private static PersonalTable7 Personal => PersonalTable.USUM; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => pk.Format > Generation ? EvolutionGroupHOME.Instance : null; public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) @@ -75,12 +76,12 @@ public sealed class EvolutionGroup7 : IEvolutionGroup public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - var b = Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + var b = Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); return b && !IsEvolutionBanned(pk, result); } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup7b.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup7b.cs index a398b27ab..71da82339 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup7b.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroup7b.cs @@ -8,6 +8,7 @@ public sealed class EvolutionGroup7b : IEvolutionGroup private static readonly EvolutionTree Tree = EvolutionTree.Evolves7b; private const int Generation = 7; private static PersonalTable7GG Personal => PersonalTable.GG; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => pk.Format > Generation ? EvolutionGroupHOME.Instance : null; public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc) => null; @@ -32,7 +33,7 @@ public sealed class EvolutionGroup7b : IEvolutionGroup public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public int Evolve(Span result, PKM pk, EvolutionOrigin enc, EvolutionHistory history) @@ -59,6 +60,6 @@ public sealed class EvolutionGroup7b : IEvolutionGroup public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs index e4a61a80a..68db850f5 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs @@ -215,15 +215,16 @@ public sealed class EvolutionGroupHOME : IEvolutionGroup public sealed class EvolutionEnvironment8 : IEvolutionEnvironment { private static readonly EvolutionTree Tree = EvolutionTree.Evolves8; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + return Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm { - var b = Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + var b = Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); return b && !IsEvolutionBanned(pk, head); } @@ -240,38 +241,35 @@ public sealed class EvolutionEnvironment8 : IEvolutionEnvironment public sealed class EvolutionEnvironment8a : IEvolutionEnvironment { private static readonly EvolutionTree Tree = EvolutionTree.Evolves8a; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm - => Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + => Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm - => Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + => Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public sealed class EvolutionEnvironment8b : IEvolutionEnvironment { private static readonly EvolutionTree Tree = EvolutionTree.Evolves8b; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Default; public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm - => Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + => Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm - => Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); + => Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } public sealed class EvolutionEnvironment9 : IEvolutionEnvironment { private static readonly EvolutionTree Tree = EvolutionTree.Evolves9; + private static EvolutionRuleTweak Tweak => EvolutionRuleTweak.Level100; public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm - => Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, out result); + => Tree.Reverse.TryDevolve(head, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm - { - var b = Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, out result); - return b && !IsEvolutionBanned(head); - } - - // Unreleased Item - private static bool IsEvolutionBanned(in ISpeciesForm head) => false; + => Tree.Forward.TryEvolve(head, next, pk, currentMaxLevel, levelMin, skipChecks, Tweak, out result); } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionRuleTweak.cs b/PKHeX.Core/Legality/Evolutions/EvolutionRuleTweak.cs new file mode 100644 index 000000000..053b5b149 --- /dev/null +++ b/PKHeX.Core/Legality/Evolutions/EvolutionRuleTweak.cs @@ -0,0 +1,22 @@ +namespace PKHeX.Core; + +/// +/// Tweaks to Evolution rules to account for game-specific behaviors. +/// +public sealed class EvolutionRuleTweak +{ + /// + /// Default Evolution logic (no tweaks). + /// + public static readonly EvolutionRuleTweak Default = new(); + + /// + /// In Scarlet & Violet, level 100 Pokemon can trigger evolution methods via Rare Candy level up. + /// + public static readonly EvolutionRuleTweak Level100 = new() { AllowLevelUpEvolution100 = true }; + + /// + /// Allow Level Up Evolutions to trigger if already level 100. + /// + public bool AllowLevelUpEvolution100 { get; init; } +} diff --git a/PKHeX.Core/Legality/Evolutions/Forward/EvolutionForwardPersonal.cs b/PKHeX.Core/Legality/Evolutions/Forward/EvolutionForwardPersonal.cs index f4885211f..9ee208e44 100644 --- a/PKHeX.Core/Legality/Evolutions/Forward/EvolutionForwardPersonal.cs +++ b/PKHeX.Core/Legality/Evolutions/Forward/EvolutionForwardPersonal.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace PKHeX.Core; @@ -36,7 +37,7 @@ public sealed class EvolutionForwardPersonal(EvolutionMethod[][] Entries, IPerso } } - public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm + public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, EvolutionRuleTweak tweak, out EvoCriteria result) where T : ISpeciesForm { var methods = GetForward(head.Species, head.Form); foreach (var method in methods.Span) @@ -47,11 +48,11 @@ public sealed class EvolutionForwardPersonal(EvolutionMethod[][] Entries, IPerso if (next.Form != expectForm) continue; - var chk = method.Check(pk, currentMaxLevel, levelMin, skipChecks); + var chk = method.Check(pk, currentMaxLevel, levelMin, skipChecks, tweak); if (chk != EvolutionCheckResult.Valid) continue; - result = Create(next.Species, next.Form, method, currentMaxLevel, levelMin); + result = Create(next.Species, next.Form, method, currentMaxLevel, levelMin, tweak); return true; } @@ -59,7 +60,7 @@ public sealed class EvolutionForwardPersonal(EvolutionMethod[][] Entries, IPerso return false; } - private static EvoCriteria Create(ushort species, byte form, EvolutionMethod method, byte currentMaxLevel, byte min) => new() + private static EvoCriteria Create(ushort species, byte form, EvolutionMethod method, byte currentMaxLevel, byte min, EvolutionRuleTweak tweak) => new() { Species = species, Form = form, @@ -68,6 +69,20 @@ public sealed class EvolutionForwardPersonal(EvolutionMethod[][] Entries, IPerso // Temporarily store these and overwrite them when we clean the list. LevelMin = Math.Max(min, method.Level), - LevelUpRequired = method.LevelUp, + LevelUpRequired = GetLevelUp(method.LevelUp, currentMaxLevel, tweak), }; + + /// + /// Gets the level up requirement for the evolution. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte GetLevelUp(byte flag, byte currentMaxLevel, EvolutionRuleTweak tweak) + { + if (flag == 0) + return 0; + if (currentMaxLevel == 100 && tweak.AllowLevelUpEvolution100) + return 0; + return flag; + } } diff --git a/PKHeX.Core/Legality/Evolutions/Forward/EvolutionForwardSpecies.cs b/PKHeX.Core/Legality/Evolutions/Forward/EvolutionForwardSpecies.cs index dfb8d3100..3c1461901 100644 --- a/PKHeX.Core/Legality/Evolutions/Forward/EvolutionForwardSpecies.cs +++ b/PKHeX.Core/Legality/Evolutions/Forward/EvolutionForwardSpecies.cs @@ -37,7 +37,8 @@ public sealed class EvolutionForwardSpecies(EvolutionMethod[][] Entries) : IEvol } } - public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm + public bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, + EvolutionRuleTweak tweak, out EvoCriteria result) where T : ISpeciesForm { var methods = GetForward(head.Species, head.Form); foreach (var method in methods.Span) @@ -48,7 +49,7 @@ public sealed class EvolutionForwardSpecies(EvolutionMethod[][] Entries) : IEvol if (next.Form != expectForm) continue; - var chk = method.Check(pk, currentMaxLevel, levelMin, skipChecks); + var chk = method.Check(pk, currentMaxLevel, levelMin, skipChecks, tweak); if (chk != EvolutionCheckResult.Valid) continue; @@ -69,6 +70,6 @@ public sealed class EvolutionForwardSpecies(EvolutionMethod[][] Entries) : IEvol // Temporarily store these and overwrite them when we clean the list. LevelMin = Math.Max(min, method.Level), - LevelUpRequired = method.LevelUp, + LevelUpRequired = method.LevelUp, // No need to tweak this, all games of this Type have the same default behavior. }; } diff --git a/PKHeX.Core/Legality/Evolutions/Forward/IEvolutionForward.cs b/PKHeX.Core/Legality/Evolutions/Forward/IEvolutionForward.cs index 03657edb0..a579beb29 100644 --- a/PKHeX.Core/Legality/Evolutions/Forward/IEvolutionForward.cs +++ b/PKHeX.Core/Legality/Evolutions/Forward/IEvolutionForward.cs @@ -30,7 +30,8 @@ public interface IEvolutionForward /// Maximum allowed level for the result /// Minimum level for the result /// Skip evolution exclusion checks + /// Rule tweaks to use when checking evolution criteria /// Resulting evolution criteria /// True if the evolution is possible and is valid. - bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm; + bool TryEvolve(T head, ISpeciesForm next, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, EvolutionRuleTweak tweak, out EvoCriteria result) where T : ISpeciesForm; } diff --git a/PKHeX.Core/Legality/Evolutions/Methods/EvolutionMethod.cs b/PKHeX.Core/Legality/Evolutions/Methods/EvolutionMethod.cs index bd9a83bd5..ef232228e 100644 --- a/PKHeX.Core/Legality/Evolutions/Methods/EvolutionMethod.cs +++ b/PKHeX.Core/Legality/Evolutions/Methods/EvolutionMethod.cs @@ -39,8 +39,9 @@ public readonly record struct EvolutionMethod(ushort Species, ushort Argument, b /// Current level /// Minimum level to sanity check with /// Option to skip some comparisons to return a 'possible' evolution. + /// /// True if the evolution criteria is valid. - public EvolutionCheckResult Check(PKM pk, byte lvl, byte levelMin, bool skipChecks) + public EvolutionCheckResult Check(PKM pk, byte lvl, byte levelMin, bool skipChecks, EvolutionRuleTweak tweak) { if (!Method.IsLevelUpRequired()) return ValidNotLevelUp(pk, skipChecks); @@ -57,7 +58,11 @@ public readonly record struct EvolutionMethod(ushort Species, ushort Argument, b if (Level == 0 && lvl < 2) return InsufficientLevel; if (lvl < levelMin + LevelUp && !skipChecks) + { + if (lvl == 100 && tweak.AllowLevelUpEvolution100) + return Valid; return InsufficientLevel; + } return Valid; } diff --git a/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReversal.cs b/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReversal.cs index 0b304f2b8..7824ba233 100644 --- a/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReversal.cs +++ b/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReversal.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; namespace PKHeX.Core; @@ -19,19 +20,20 @@ public static class EvolutionReversal /// Maximum the entity may exist as /// Species ID that should be the last node, if at all. Provide 0 to fully devolve. /// Option to bypass some evolution criteria + /// Rule tweaks to use when checking evolution criteria /// Reversed evolution lineage, with the lowest index being the current species-form. public static int Devolve(this IEvolutionLookup lineage, Span result, ushort species, byte form, - PKM pk, byte levelMin, byte levelMax, ushort stopSpecies, bool skipChecks) + PKM pk, byte levelMin, byte levelMax, ushort stopSpecies, bool skipChecks, EvolutionRuleTweak tweak) { // Store our results -- trim at the end when we place it on the heap. var head = result[0] = new EvoCriteria { Species = species, Form = form, LevelMax = levelMax }; - int ctr = Devolve(lineage, result, head, pk, levelMax, levelMin, skipChecks, stopSpecies); + int ctr = Devolve(lineage, result, head, pk, levelMax, levelMin, skipChecks, stopSpecies, tweak); EvolutionUtil.CleanDevolve(result[..ctr], levelMin); return ctr; } private static int Devolve(IEvolutionLookup lineage, Span result, EvoCriteria head, - PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, ushort stopSpecies) + PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, ushort stopSpecies, EvolutionRuleTweak tweak) { // There aren't any circular evolution paths, and all lineages have at most 3 evolutions total. // There aren't any convergent evolution paths, so only yield the first connection. @@ -39,7 +41,7 @@ public static class EvolutionReversal while (head.Species != stopSpecies) { ref readonly var node = ref lineage[head.Species, head.Form]; - if (!node.TryDevolve(pk, currentMaxLevel, levelMin, skipChecks, out var x)) + if (!node.TryDevolve(pk, currentMaxLevel, levelMin, skipChecks, tweak, out var x)) return ctr; result[ctr++] = x; @@ -48,7 +50,7 @@ public static class EvolutionReversal return ctr; } - public static bool TryDevolve(this EvolutionNode node, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) + public static bool TryDevolve(this EvolutionNode node, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, EvolutionRuleTweak tweak, out EvoCriteria result) { // Multiple methods can exist to devolve to the same species-form. // The first method is less restrictive (no LevelUp req), if two {level/other} methods exist. @@ -59,10 +61,10 @@ public static class EvolutionReversal return false; } - var chk = link.Method.Check(pk, currentMaxLevel, levelMin, skipChecks); + var chk = link.Method.Check(pk, currentMaxLevel, levelMin, skipChecks, tweak); if (chk == EvolutionCheckResult.Valid) { - result = Create(link, currentMaxLevel); + result = Create(link, currentMaxLevel, tweak); return true; } @@ -73,10 +75,10 @@ public static class EvolutionReversal return false; } - chk = link.Method.Check(pk, currentMaxLevel, levelMin, skipChecks); + chk = link.Method.Check(pk, currentMaxLevel, levelMin, skipChecks, tweak); if (chk == EvolutionCheckResult.Valid) { - result = Create(link, currentMaxLevel); + result = Create(link, currentMaxLevel, tweak); return true; } @@ -84,7 +86,7 @@ public static class EvolutionReversal return false; } - private static EvoCriteria Create(in EvolutionLink link, byte currentMaxLevel) => new() + private static EvoCriteria Create(in EvolutionLink link, byte currentMaxLevel, EvolutionRuleTweak tweak) => new() { Species = link.Species, Form = link.Form, @@ -93,6 +95,20 @@ public static class EvolutionReversal // Temporarily store these and overwrite them when we clean the list. LevelMin = link.Method.Level, - LevelUpRequired = link.Method.LevelUp, + LevelUpRequired = GetLevelUp(link.Method.LevelUp, currentMaxLevel, tweak), }; + + /// + /// Gets the level up requirement for the evolution. + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte GetLevelUp(byte flag, byte currentMaxLevel, EvolutionRuleTweak tweak) + { + if (flag == 0) + return 0; + if (currentMaxLevel == 100 && tweak.AllowLevelUpEvolution100) + return 0; + return flag; + } } diff --git a/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReversePersonal.cs b/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReversePersonal.cs index e9c6b1e11..9a8ccbdc7 100644 --- a/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReversePersonal.cs +++ b/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReversePersonal.cs @@ -47,9 +47,10 @@ public sealed class EvolutionReversePersonal(EvolutionMethod[][] Entries, IPerso yield return (s.Species, s.Form); } - public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm + public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, EvolutionRuleTweak tweak, out EvoCriteria result) + where T : ISpeciesForm { ref readonly var node = ref Lineage[head.Species, head.Form]; - return node.TryDevolve(pk, currentMaxLevel, levelMin, skipChecks, out result); + return node.TryDevolve(pk, currentMaxLevel, levelMin, skipChecks, tweak, out result); } } diff --git a/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReverseSpecies.cs b/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReverseSpecies.cs index 3f9e253c7..a8ed9e84d 100644 --- a/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReverseSpecies.cs +++ b/PKHeX.Core/Legality/Evolutions/Reversal/EvolutionReverseSpecies.cs @@ -47,9 +47,10 @@ public sealed class EvolutionReverseSpecies(EvolutionMethod[][] Entries, IPerson yield return (s.Species, s.Form); } - public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm + public bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, EvolutionRuleTweak tweak, out EvoCriteria result) + where T : ISpeciesForm { ref readonly var node = ref Lineage[head.Species, head.Form]; - return node.TryDevolve(pk, currentMaxLevel, levelMin, skipChecks, out result); + return node.TryDevolve(pk, currentMaxLevel, levelMin, skipChecks, tweak, out result); } } diff --git a/PKHeX.Core/Legality/Evolutions/Reversal/IEvolutionReverse.cs b/PKHeX.Core/Legality/Evolutions/Reversal/IEvolutionReverse.cs index be7725250..e7c1851cc 100644 --- a/PKHeX.Core/Legality/Evolutions/Reversal/IEvolutionReverse.cs +++ b/PKHeX.Core/Legality/Evolutions/Reversal/IEvolutionReverse.cs @@ -28,7 +28,8 @@ public interface IEvolutionReverse /// Maximum allowed level for the result /// Minimum level for the result /// Skip evolution exclusion checks + /// Rule tweaks to use when checking evolution criteria /// Resulting evolution criteria /// True if the de-evolution is possible and is valid. - bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, out EvoCriteria result) where T : ISpeciesForm; + bool TryDevolve(T head, PKM pk, byte currentMaxLevel, byte levelMin, bool skipChecks, EvolutionRuleTweak tweak, out EvoCriteria result) where T : ISpeciesForm; }