From 09e7f18fbb33635e35cf9ffcbfd3322403780f8e Mon Sep 17 00:00:00 2001
From: sora10pls <17801814+sora10pls@users.noreply.github.com>
Date: Sun, 27 Sep 2026 08:13:11 -0400
Subject: [PATCH] GO: handle min IV for trades with brand new friends
---
.../Encounters/Templates/GO/EncounterSlot7GO.cs | 2 ++
.../Encounters/Templates/GO/EncounterSlot8GO.cs | 5 ++---
.../Encounters/Templates/GO/IPogoSlot.cs | 16 +++++++++++++++-
.../Legality/Encounters/Templates/GO/PogoType.cs | 11 +++++++++--
4 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot7GO.cs b/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot7GO.cs
index beb7d0969..33a5e6932 100644
--- a/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot7GO.cs
+++ b/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot7GO.cs
@@ -23,6 +23,7 @@ public sealed record EncounterSlot7GO(ushort DayStart, ushort DayEnd, ushort Spe
public byte LevelMax => EncountersGO.MAX_LEVEL;
public bool IsLocalDayStart => Flags.HasFlag(PogoFlags.LocalDateStart);
public bool IsLocalDayEnd => Flags.HasFlag(PogoFlags.LocalDateEnd);
+ public bool IsAlwaysSpecialTrade => Flags.HasFlag(PogoFlags.AlwaysSpecialTrade);
public string Name => $"GO Encounter ({Version})";
public string LongName
@@ -164,4 +165,5 @@ public enum PogoFlags : byte
LocalDateStart = 1 << 0,
LocalDateEnd = 1 << 1,
FeaturedWildArea = 1 << 2,
+ AlwaysSpecialTrade = 1 << 4,
}
diff --git a/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot8GO.cs b/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot8GO.cs
index 63bf5d2e1..eee2fb27c 100644
--- a/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot8GO.cs
+++ b/PKHeX.Core/Legality/Encounters/Templates/GO/EncounterSlot8GO.cs
@@ -22,6 +22,7 @@ public sealed record EncounterSlot8GO(ushort DayStart, ushort DayEnd, ushort Spe
public byte LevelMax => EncountersGO.MAX_LEVEL;
public bool IsLocalDayStart => Flags.HasFlag(PogoFlags.LocalDateStart);
public bool IsLocalDayEnd => Flags.HasFlag(PogoFlags.LocalDateEnd);
+ public bool IsAlwaysSpecialTrade => Flags.HasFlag(PogoFlags.AlwaysSpecialTrade);
public string Name => $"GO Encounter ({Version})";
public string LongName
@@ -249,8 +250,6 @@ public EncounterMatchRating GetMatchRating(PKM pk)
return EncounterMatchRating.DeferredErrors;
if (pk is ITeraType ro && IsTeraTypeMismatch(ro.TeraTypeOriginal, PersonalTable.SV[Species, Form]))
return EncounterMatchRating.DeferredErrors;
- if (!this.GetIVsValid(pk))
- return EncounterMatchRating.Deferred;
return EncounterMatchRating.Match;
}
@@ -294,7 +293,7 @@ private bool IsMatchPartial(PKM pk)
{
if (!IsWithinDistributionWindow(pk))
return true;
- if (!this.GetIVsAboveMinimum(pk))
+ if (!this.GetIVsValid(pk))
return true;
// Eevee & Glaceon have different base friendships. Make sure if it is invalid that we yield the other encounter before.
diff --git a/PKHeX.Core/Legality/Encounters/Templates/GO/IPogoSlot.cs b/PKHeX.Core/Legality/Encounters/Templates/GO/IPogoSlot.cs
index d91120e15..30d700671 100644
--- a/PKHeX.Core/Legality/Encounters/Templates/GO/IPogoSlot.cs
+++ b/PKHeX.Core/Legality/Encounters/Templates/GO/IPogoSlot.cs
@@ -16,6 +16,9 @@ public interface IPogoSlot : IPogoDateRange
/// Minimum IV value for the encounter.
byte MinimumIV { get; }
+
+ /// If trading this Pokémon always results in a Special Trade.
+ bool IsAlwaysSpecialTrade { get; }
}
///
@@ -42,9 +45,20 @@ private static bool GetIVsAboveMinimum(PKM pk, int min)
public static bool GetIVsValid(this IPogoSlot slot, PKM pk)
{
- if (!slot.GetIVsAboveMinimum(pk))
+ if (!slot.GetIVsAboveMinimum(pk) && slot.IsAlwaysSpecialTrade)
return false;
+ // when trading with new friends, the IV floor is 0 before reaching Good Friends, as long as it is not a Special Trade
+ if (slot.MinimumIV == 1 && (pk.IV_HP == 1 || (pk.IV_ATK == 1 && pk.IV_SPA == 1) || (pk.IV_DEF == 1 && pk.IV_SPD == 1)))
+ {
+ if (pk.IsShiny)
+ return false;
+ if (SpeciesCategory.IsSpecialPokemon(pk.Species))
+ return false;
+ if (slot.Type.IsShadow)
+ return false;
+ }
+
// HP * 2 | 1 -> HP
// ATK * 2 | 1 -> ATK&SPA
// DEF * 2 | 1 -> DEF&SPD
diff --git a/PKHeX.Core/Legality/Encounters/Templates/GO/PogoType.cs b/PKHeX.Core/Legality/Encounters/Templates/GO/PogoType.cs
index d9b7a3f7b..d9d9f9e1b 100644
--- a/PKHeX.Core/Legality/Encounters/Templates/GO/PogoType.cs
+++ b/PKHeX.Core/Legality/Encounters/Templates/GO/PogoType.cs
@@ -77,6 +77,13 @@ or PogoType.RaidShadow
or PogoType.RaidShadowMythical
or PogoType.RaidShadowUltraBeast;
+ public bool IsShadow => type is PogoType.Shadow
+ or PogoType.ShadowMythical
+ or PogoType.ShadowUltraBeast
+ or PogoType.RaidShadow
+ or PogoType.RaidShadowMythical
+ or PogoType.RaidShadowUltraBeast;
+
public bool IsMaxBattle => type is PogoType.MaxBattle
or PogoType.MaxBattleMythical
or PogoType.MaxBattleUltraBeast
@@ -119,8 +126,8 @@ public bool IsSafariBallUsable(PogoType type, PogoFlags flags)
{
if (ball is PogoBallRestriction.OnlySafari)
return true;
- if (!flags.HasFlag(PogoFlags.FeaturedWildArea) && (type.IsRaid || type.IsMaxBattle))
- return false;
+ if (type.IsRaid || type.IsMaxBattle)
+ return flags.HasFlag(PogoFlags.FeaturedWildArea);
return type switch
{