Rework match ranking to have multi levels of deferral

This commit is contained in:
Kurt
2021-08-15 08:40:44 -07:00
parent ff309fc9c5
commit 7c60363b38
8 changed files with 71 additions and 59 deletions

View File

@@ -2,16 +2,22 @@ namespace PKHeX.Core
{
public enum EncounterMatchRating
{
/// <summary> Unused </summary>
None,
/// <summary> Matches all data, no other matches will be better. </summary>
Match,
/// <summary> Matches most data, might have a better match later. </summary>
Deferred,
/// <summary> Matches most data, might have a better match later. Less preferred than <see cref="Deferred"/> due to potentially small errors in secondary data. </summary>
DeferredSecondary,
/// <summary> Matches most data, might have a better match later. Less preferred than <see cref="Deferred"/> due to small errors in secondary data. </summary>
DeferredErrors,
/// <summary> Matches some data, but will likely have a better match later. </summary>
PartialMatch,
/// <summary> Unused </summary>
None,
}
}

View File

@@ -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,
};
}

View File

@@ -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);
}
/// <summary>
/// Checks if the provided <see cref="pkm"/> might not be the best match, or even a bad match due to minor reasons.
/// </summary>
protected virtual bool IsMatchDeferred(PKM pkm) => false;
protected virtual EncounterMatchRating IsMatchDeferred(PKM pkm) => EncounterMatchRating.Match;
/// <summary>
/// Checks if the provided <see cref="pkm"/> is not an exact match due to minor reasons.

View File

@@ -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;
}

View File

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

View File

@@ -38,8 +38,8 @@ private static IEnumerable<IEncounterable> 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<IEncounterable> 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<IEncounterable> 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;
}
}
}

View File

@@ -447,7 +447,7 @@ private static bool IsAbilityCapsuleModified(PKM pkm, IReadOnlyList<int> abiliti
return true;
}
private static bool CanAbilityCapsule(int format, IReadOnlyList<int> abilities)
public static bool CanAbilityCapsule(int format, IReadOnlyList<int> abilities)
{
if (format < 6) // Ability Capsule does not exist
return false;

View File

@@ -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;