From 7c60363b384820e4ffce7fe21d9e73daf7e2d8b6 Mon Sep 17 00:00:00 2001 From: Kurt Date: Sun, 15 Aug 2021 08:40:44 -0700 Subject: [PATCH] Rework match ranking to have multi levels of deferral --- .../Encounters/EncounterMatchRating.cs | 12 +++- .../EncounterSlot/EncounterSlot8.cs | 12 ++-- .../EncounterStatic/EncounterStatic.cs | 6 +- .../EncounterStatic/EncounterStatic8.cs | 6 +- .../EncounterStatic/EncounterStatic8Nest.cs | 29 ++++++---- .../ByGeneration/EncounterGenerator8.cs | 55 +++++++++---------- .../Verifiers/Ability/AbilityVerifier.cs | 2 +- .../Legality/Verifiers/MemoryPermissions.cs | 8 ++- 8 files changed, 71 insertions(+), 59 deletions(-) diff --git a/PKHeX.Core/Legality/Encounters/EncounterMatchRating.cs b/PKHeX.Core/Legality/Encounters/EncounterMatchRating.cs index e7965f923..411bc94aa 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterMatchRating.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterMatchRating.cs @@ -2,16 +2,22 @@ namespace PKHeX.Core { public enum EncounterMatchRating { - /// Unused - None, - /// Matches all data, no other matches will be better. Match, /// Matches most data, might have a better match later. Deferred, + /// Matches most data, might have a better match later. Less preferred than due to potentially small errors in secondary data. + DeferredSecondary, + + /// Matches most data, might have a better match later. Less preferred than due to small errors in secondary data. + DeferredErrors, + /// Matches some data, but will likely have a better match later. PartialMatch, + + /// Unused + None, } } diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8.cs index 40a3067c8..6342bd99d 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8.cs @@ -93,25 +93,25 @@ public override EncounterMatchRating GetMatchRating(PKM pkm) if (pkm is IRibbonSetMark8 m) { if (m.RibbonMarkCurry && (Weather & AreaWeather8.All) == 0) - return EncounterMatchRating.Deferred; + return EncounterMatchRating.DeferredErrors; if (m.RibbonMarkFishing && (Weather & AreaWeather8.Fishing) == 0) - return EncounterMatchRating.Deferred; + return EncounterMatchRating.DeferredErrors; // Check if it has a mark and the weather does not permit the mark. // Tree/Fishing slots should be deferred here and are checked later. if (!Weather.IsMarkCompatible(m)) - return EncounterMatchRating.Deferred; + return EncounterMatchRating.DeferredErrors; // Galar Mine hidden encounters can only be found via Curry or Fishing. if(Location is (30 or 54) && SlotType is AreaSlotType8.HiddenMain && !m.RibbonMarkCurry && !SlotType.CanEncounterViaFishing(Weather)) - return EncounterMatchRating.PartialMatch; + return EncounterMatchRating.DeferredErrors; } var req = GetRequirement(pkm); return req switch { - MustHave when !IsOverworldCorrelationCorrect(pkm) => EncounterMatchRating.Deferred, - MustNotHave when IsOverworldCorrelationCorrect(pkm) => EncounterMatchRating.Deferred, + MustHave when !IsOverworldCorrelationCorrect(pkm) => EncounterMatchRating.DeferredErrors, + MustNotHave when IsOverworldCorrelationCorrect(pkm) => EncounterMatchRating.DeferredErrors, _ => EncounterMatchRating.Match, }; } diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs index fb08df8c0..1fb4af2f4 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs @@ -289,15 +289,13 @@ public virtual EncounterMatchRating GetMatchRating(PKM pkm) { if (IsMatchPartial(pkm)) return EncounterMatchRating.PartialMatch; - if (IsMatchDeferred(pkm)) - return EncounterMatchRating.Deferred; - return EncounterMatchRating.Match; + return IsMatchDeferred(pkm); } /// /// Checks if the provided might not be the best match, or even a bad match due to minor reasons. /// - protected virtual bool IsMatchDeferred(PKM pkm) => false; + protected virtual EncounterMatchRating IsMatchDeferred(PKM pkm) => EncounterMatchRating.Match; /// /// Checks if the provided is not an exact match due to minor reasons. diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8.cs index a27c2e275..e15fb12b9 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8.cs @@ -86,7 +86,7 @@ public override EncounterMatchRating GetMatchRating(PKM pkm) var req = GetRequirement(pkm); bool correlation = IsOverworldCorrelationCorrect(pkm); if ((req == MustHave) != correlation) - return EncounterMatchRating.Deferred; + return EncounterMatchRating.DeferredErrors; // Only encounter slots can have these marks; defer for collisions. if (pkm.Species == (int) Core.Species.Shedinja) @@ -94,14 +94,14 @@ public override EncounterMatchRating GetMatchRating(PKM pkm) // Loses Mark on evolution to Shedinja, but not affixed ribbon value. return pkm switch { - IRibbonSetMark8 {RibbonMarkCurry: true} => EncounterMatchRating.Deferred, + IRibbonSetMark8 {RibbonMarkCurry: true} => EncounterMatchRating.DeferredErrors, PK8 {AffixedRibbon: (int) RibbonIndex.MarkCurry} => EncounterMatchRating.Deferred, _ => EncounterMatchRating.Match }; } if (pkm is IRibbonSetMark8 m && (m.RibbonMarkCurry || m.RibbonMarkFishing || m.HasWeatherMark())) - return EncounterMatchRating.Deferred; + return EncounterMatchRating.DeferredErrors; return EncounterMatchRating.Match; } diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8Nest.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8Nest.cs index 36fdc87ea..140cf7f37 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8Nest.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8Nest.cs @@ -43,27 +43,32 @@ public override bool IsMatchExact(PKM pkm, DexLevel evo) return base.IsMatchExact(pkm, evo); } - protected sealed override bool IsMatchDeferred(PKM pkm) + protected sealed override EncounterMatchRating IsMatchDeferred(PKM pkm) { + var rating = EncounterMatchRating.Match; if (Ability != -1) // Any { - bool CanBeHidden() => ((PersonalInfoSWSH) PersonalTable.SWSH.GetFormEntry(Species, Form)).HasHiddenAbility; - // HA-Only is a strict match. Ability Capsule and Patch can potentially change these. - if (Ability == 0 && pkm.AbilityNumber == 4) - return !CanBeHidden(); // 0/1 - if (Ability == 1 && pkm.AbilityNumber != 1) - return pkm.AbilityNumber != 4 || !CanBeHidden(); // 0 - if (Ability == 2 && pkm.AbilityNumber != 2) - return pkm.AbilityNumber != 4 || !CanBeHidden(); // 1 + if (pkm.AbilityNumber == 4) + { + if (Ability is not 4 && !AbilityVerifier.CanAbilityPatch(8, PersonalTable.SWSH.GetFormEntry(Species, Form).Abilities, pkm.Species)) + return EncounterMatchRating.DeferredErrors; + rating = EncounterMatchRating.Deferred; + } + if (pkm.AbilityNumber != Ability) // Fixed regular ability + { + if (Ability is 1 or 2 && !AbilityVerifier.CanAbilityCapsule(8, PersonalTable.SWSH.GetFormEntry(Species, Form).Abilities)) + return EncounterMatchRating.DeferredErrors; + rating = EncounterMatchRating.Deferred; + } } if (pkm is IMemoryOT m && MemoryPermissions.IsMoveKnowMemory(m.OT_Memory) && !Moves.Contains(m.OT_TextVar)) - return true; + return EncounterMatchRating.DeferredSecondary; if (pkm is IMemoryHT h && MemoryPermissions.IsMoveKnowMemory(h.HT_Memory) && !Moves.Contains(h.HT_TextVar)) - return true; + return EncounterMatchRating.DeferredSecondary; - return base.IsMatchDeferred(pkm); + return rating; } protected override bool IsMatchPartial(PKM pkm) diff --git a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator8.cs b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator8.cs index 5dc6e0454..2c658b83d 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator8.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/ByGeneration/EncounterGenerator8.cs @@ -38,8 +38,8 @@ private static IEnumerable GetEncountersMainline(PKM pkm, IReadO if (ctr == 0) yield break; } - IEncounterable? deferred = null; - IEncounterable? partial = null; + IEncounterable? cache = null; + EncounterMatchRating rating = None; // Trades if (pkm.Met_Location == Locations.LinkTrade6NPC) @@ -47,23 +47,19 @@ private static IEnumerable GetEncountersMainline(PKM pkm, IReadO foreach (var z in GetValidEncounterTrades(pkm, chain)) { var match = z.GetMatchRating(pkm); - switch (match) + if (match == Match) { - case Match: yield return z; ++ctr; break; - case Deferred: deferred ??= z; break; - case PartialMatch: partial ??= z; break; + yield return z; + } + else if (match < rating) + { + cache = z; + rating = match; } } - if (ctr != 0) - { - if (deferred != null) - yield return deferred; - - if (partial != null) - yield return partial; - } - + if (cache != null) + yield return cache; yield break; } @@ -71,30 +67,33 @@ private static IEnumerable GetEncountersMainline(PKM pkm, IReadO foreach (var z in GetValidStaticEncounter(pkm, chain)) { var match = z.GetMatchRating(pkm); - switch (match) + if (match == Match) { - case Match: yield return z; break; - case Deferred: deferred ??= z; break; - case PartialMatch: partial ??= z; break; + yield return z; + } + else if (match < rating) + { + cache = z; + rating = match; } } foreach (var z in GetValidWildEncounters(pkm, chain)) { var match = z.GetMatchRating(pkm); - switch (match) + if (match == Match) { - case Match: yield return z; break; - case Deferred: deferred ??= z; break; - case PartialMatch: partial ??= z; break; + yield return z; + } + else if (match < rating) + { + cache = z; + rating = match; } } - if (deferred != null) - yield return deferred; - - if (partial != null) - yield return partial; + if (cache != null) + yield return cache; } } } diff --git a/PKHeX.Core/Legality/Verifiers/Ability/AbilityVerifier.cs b/PKHeX.Core/Legality/Verifiers/Ability/AbilityVerifier.cs index a93702d64..26628c439 100644 --- a/PKHeX.Core/Legality/Verifiers/Ability/AbilityVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/Ability/AbilityVerifier.cs @@ -447,7 +447,7 @@ private static bool IsAbilityCapsuleModified(PKM pkm, IReadOnlyList abiliti return true; } - private static bool CanAbilityCapsule(int format, IReadOnlyList abilities) + public static bool CanAbilityCapsule(int format, IReadOnlyList abilities) { if (format < 6) // Ability Capsule does not exist return false; diff --git a/PKHeX.Core/Legality/Verifiers/MemoryPermissions.cs b/PKHeX.Core/Legality/Verifiers/MemoryPermissions.cs index 051a629ca..e7a6044ba 100644 --- a/PKHeX.Core/Legality/Verifiers/MemoryPermissions.cs +++ b/PKHeX.Core/Legality/Verifiers/MemoryPermissions.cs @@ -173,11 +173,15 @@ private static bool GetCanKnowMove(PKM pkm, int move, int generation, IReadOnlyL return false; for (int i = 1; i <= generation; i++) { - var moves = MoveList.GetValidMoves(pkm, version, evos[i], i, types: MoveSourceType.All); + var chain = evos[i]; + if (chain.Count == 0) + continue; + + var moves = MoveList.GetValidMoves(pkm, version, chain, i, types: MoveSourceType.All); if (moves.Contains(move)) return true; - if (IsOtherFormMove(pkm, evos[i], move, i, GameVersion.Any, types: MoveSourceType.All)) + if (IsOtherFormMove(pkm, chain, move, i, GameVersion.Any, types: MoveSourceType.All)) return true; } return false;