From 335803817244bb6ee0f31369d8f6800a266b634c Mon Sep 17 00:00:00 2001 From: Kurt Date: Fri, 26 Apr 2024 01:33:19 -0500 Subject: [PATCH] Add ball deferral & met level leniency for gen3/4 Fixes some issues reported via discord --- .../ByGeneration/EncounterGenerator3.cs | 58 ++++++++++---- .../ByGeneration/EncounterGenerator4.cs | 71 ++++++++++++------ .../Legality/Evolutions/EvolutionChain.cs | 9 +++ .../EvolutionGroup/EvolutionUtil.cs | 12 +++ ...putzi_-_81DD3D8C0FFD safari gen3 level.pk6 | Bin 0 -> 260 bytes ...autifly_-_02EC2BFA04AE gen3 l5 silcoon.pk7 | Bin 0 -> 260 bytes 6 files changed, 115 insertions(+), 35 deletions(-) create mode 100644 Tests/PKHeX.Core.Tests/Legality/Legal/Generation 6/0061_-_Quaputzi_-_81DD3D8C0FFD safari gen3 level.pk6 create mode 100644 Tests/PKHeX.Core.Tests/Legality/Legal/Generation 7 Transfer/0267_-_Beautifly_-_02EC2BFA04AE gen3 l5 silcoon.pk7 diff --git a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator3.cs b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator3.cs index 854f9b1b8..3ea7d1667 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator3.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator3.cs @@ -21,6 +21,29 @@ public IEnumerable GetEncounters(PKM pk, LegalInfo info) return GetEncounters(pk, chain, info); } + private enum DeferralType + { + None, + PIDIV, + Tile, + Ball, + SlotNumber, + } + + private struct Deferral + { + public DeferralType Type; + public IEncounterable? Encounter; + + public void Update(DeferralType type, IEncounterable enc) + { + if (Type >= type) + return; + Type = type; + Encounter = enc; + } + } + public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, LegalInfo info) { if (chain.Length == 0) @@ -29,8 +52,7 @@ public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, Le info.PIDIV = MethodFinder.Analyze(pk); var game = pk.Version; var iterator = new EncounterEnumerator3(pk, chain, game); - IEncounterable? deferType = null; - EncounterSlot3? deferSlot = null; + Deferral defer = default; var leadQueue = new LeadEncounterQueue(); bool emerald = pk.E; @@ -43,7 +65,12 @@ public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, Le var e = enc.Encounter; if (!IsTypeCompatible(e, pk, info.PIDIV.Type)) { - deferType ??= e; + defer.Update(DeferralType.PIDIV, e); + continue; + } + if (!IsBallCompatible(e, pk)) + { + defer.Update(DeferralType.Ball, e); continue; } if (e is not EncounterSlot3 slot) @@ -76,7 +103,7 @@ public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, Le var lead = LeadFinder.GetLeadInfo3(slot, info.PIDIV, evo, emerald, gender, pk.Format); if (!lead.IsValid()) { - deferSlot ??= slot; + defer.Update(DeferralType.SlotNumber, slot); continue; } leadQueue.Insert(lead, slot); @@ -90,19 +117,22 @@ public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, Le if (leadQueue.List.Count != 0) yield break; - // Error will be flagged later if this is chosen. - if (deferSlot != null) - { - info.ManualFlag = EncounterYieldFlag.InvalidFrame; - yield return deferSlot; - } - else if (deferType != null) - { + // Errors will be flagged later for those not manually handled below. + if (defer.Encounter is not { } lastResort) + yield break; + if (defer.Type is DeferralType.PIDIV) info.ManualFlag = EncounterYieldFlag.InvalidPIDIV; - yield return deferType; - } + else if (defer.Type is DeferralType.Tile) + info.ManualFlag = EncounterYieldFlag.InvalidFrame; + yield return lastResort; } + private static bool IsBallCompatible(IFixedBall e, PKM pk) => e.FixedBall switch + { + Ball.Safari when pk.Ball is (byte)Ball.Safari => true, + _ => pk.Ball is not (byte)Ball.Safari, + }; + private static bool IsTypeCompatible(IEncounterTemplate enc, PKM pk, PIDType type) { if (enc is IRandomCorrelation r) diff --git a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator4.cs b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator4.cs index dad2113f3..84879e13c 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator4.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator4.cs @@ -26,14 +26,35 @@ public IEnumerable GetPossible(PKM pk, EvoCriteria[] chain, Game yield return enc; } + private enum DeferralType + { + None, + PIDIV, + Tile, + Ball, + SlotNumber, + } + + private struct Deferral + { + public DeferralType Type; + public IEncounterable? Encounter; + + public void Update(DeferralType type, IEncounterable enc) + { + if (Type >= type) + return; + Type = type; + Encounter = enc; + } + } + public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, LegalInfo info) { info.PIDIV = MethodFinder.Analyze(pk); var game = pk.Version; var iterator = new EncounterEnumerator4(pk, chain, game); - EncounterSlot4? deferSlot = null; - IEncounterable? deferTile = null; - IEncounterable? deferType = null; + Deferral defer = default; var leadQueue = new LeadEncounterQueue(); foreach (var enc in iterator) @@ -41,17 +62,25 @@ public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, Le var e = enc.Encounter; if (!IsTileCompatible(e, pk)) { - deferTile ??= e; + defer.Update(DeferralType.Tile, e); continue; } if (!IsTypeCompatible(e, pk, info.PIDIV.Type)) { - deferType ??= e; + defer.Update(DeferralType.PIDIV, e); + continue; + } + if (!IsBallCompatible(e, pk)) + { + defer.Update(DeferralType.Ball, e); continue; } if (e is not EncounterSlot4 slot) { - yield return e; + if (pk.Ball is (byte)Ball.Safari or (byte)Ball.Sport) + defer.Update(DeferralType.Ball, e); + else + yield return e; continue; } @@ -59,7 +88,7 @@ public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, Le var lead = LeadFinder.GetLeadInfo4(pk, slot, info.PIDIV, evo); if (!lead.IsValid()) { - deferSlot ??= slot; + defer.Update(DeferralType.SlotNumber, slot); continue; } leadQueue.Insert(lead, slot); @@ -73,23 +102,23 @@ public IEnumerable GetEncounters(PKM pk, EvoCriteria[] chain, Le if (leadQueue.List.Count != 0) yield break; - // Error will be flagged later if this is chosen. - if (deferTile != null) - { - yield return deferTile; - } - else if (deferSlot != null) - { - info.ManualFlag = EncounterYieldFlag.InvalidFrame; - yield return deferSlot; - } - else if (deferType != null) - { + // Errors will be flagged later for those not manually handled below. + if (defer.Encounter is not { } lastResort) + yield break; + if (defer.Type is DeferralType.PIDIV) info.ManualFlag = EncounterYieldFlag.InvalidPIDIV; - yield return deferType; - } + else if (defer.Type is DeferralType.Tile) + info.ManualFlag = EncounterYieldFlag.InvalidFrame; + yield return lastResort; } + private static bool IsBallCompatible(IFixedBall e, PKM pk) => e.FixedBall switch + { + Ball.Safari when pk.Ball is (byte)Ball.Safari => true, + Ball.Sport when pk.Ball is (byte)Ball.Sport => true, + _ => pk.Ball is not ((byte)Ball.Safari or (byte)Ball.Sport), + }; + private static bool IsTileCompatible(IEncounterTemplate enc, PKM pk) { if (pk is not IGroundTile e) diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs b/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs index 38821591c..ab2921969 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs @@ -91,6 +91,8 @@ public static EvoCriteria[] GetOriginChain(PKM pk, EvolutionOrigin enc, ushort e return []; var chain = result[..count]; + if (IsMetLost(pk, enc)) // Original met level lost, need to be more permissive on evos. + EvolutionUtil.ConditionEncounterNoMet(chain); return chain.ToArray(); } @@ -121,6 +123,13 @@ public static int GetOriginChain(Span result, PKM pk, EvolutionOrig return count; } + private static bool IsMetLost(PKM pk, EvolutionOrigin enc) => enc.Generation switch + { + >= 5 => false, + <= 2 => pk is not ICaughtData2 { MetLevel: not 0 }, + _ => enc.Generation != pk.Format, + }; + private static int DevolveFrom(Span result, PKM pk, EvolutionOrigin enc, EntityContext context, ushort encSpecies, bool discard) { var group = EvolutionGroupUtil.GetGroup(context); diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionUtil.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionUtil.cs index 842c772b8..ebbd35d4b 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionUtil.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionUtil.cs @@ -163,4 +163,16 @@ private static int CleanEvolve(Span result) } return i; } + + public static void ConditionEncounterNoMet(Span chain) + { + // Allow for under-leveled evolutions for purposes of finding an under-leveled evolved encounter. + // e.g. a level 5 Silcoon encounter slot (normally needs level 7). + for (int i = 0; i < chain.Length - 1; i++) + { + ref var evo = ref chain[i]; + if (evo.Method.IsLevelUpRequired()) + evo = evo with { LevelMin = (byte)(chain[i + 1].LevelMin + evo.LevelUpRequired) }; + } + } } diff --git a/Tests/PKHeX.Core.Tests/Legality/Legal/Generation 6/0061_-_Quaputzi_-_81DD3D8C0FFD safari gen3 level.pk6 b/Tests/PKHeX.Core.Tests/Legality/Legal/Generation 6/0061_-_Quaputzi_-_81DD3D8C0FFD safari gen3 level.pk6 new file mode 100644 index 0000000000000000000000000000000000000000..d2d76bd5f61e73ca317913417cb0a78f0328a969 GIT binary patch literal 260 zcmey%-($Czu;K7i}5P>1fz{qZhEa=9-$ifO22m;zv%#Z=pSp*k@Fx=pL2^L8p U+pv^1g@MJ8oe`lKt^$<-0R12nh5!Hn literal 0 HcmV?d00001 diff --git a/Tests/PKHeX.Core.Tests/Legality/Legal/Generation 7 Transfer/0267_-_Beautifly_-_02EC2BFA04AE gen3 l5 silcoon.pk7 b/Tests/PKHeX.Core.Tests/Legality/Legal/Generation 7 Transfer/0267_-_Beautifly_-_02EC2BFA04AE gen3 l5 silcoon.pk7 new file mode 100644 index 0000000000000000000000000000000000000000..1e0906e0bb1cf27c62033727161f1ea486991774 GIT binary patch literal 260 zcmZ3-@=Ke6;SCcvBLjo$gd2|iEDQ`TK=wMII5z_$1CWasI5DI$Br=pTlrUs6q%q_$ zRKitfF}Q=-a*}W%C?jxoyp|hKZ6ZT9P&Wnu+Kvp|7#LZY;R3-xT?GsoK--GY^t!>- lNU(scG%RK5VqnZ;WnzL!Z~+;LKq$(<%OK7m$sh=o0068m6;%KL literal 0 HcmV?d00001