Minor clean

This commit is contained in:
Kurt
2025-04-13 11:58:42 -05:00
parent 76f2705c9c
commit 4da88ac063
3 changed files with 80 additions and 73 deletions

View File

@@ -3,23 +3,57 @@
namespace PKHeX.Core;
/// <summary>
/// Logic for checking shiny state.
/// </summary>
public static class ShinyUtil
{
/// <summary>
/// Computes a shiny PID from the provided values.
/// </summary>
/// <param name="tid">Trainer ID.</param>
/// <param name="sid">Trainer Secret ID.</param>
/// <param name="pid">Entity PID.</param>
/// <param name="type">Shiny XOR type.</param>
/// <returns>Shiny PID.</returns>
public static uint GetShinyPID(in ushort tid, in ushort sid, in uint pid, in uint type)
{
var low = pid & 0xFFFF;
return ((type ^ tid ^ sid ^ low) << 16) | low;
}
/// <summary>
/// Checks if the PID is shiny.
/// </summary>
/// <param name="id32">Combined Trainer ID and Secret ID.</param>
/// <param name="pid">Entity PID.</param>
/// <param name="cmp">Comparison threshold.</param>
/// <returns>True if shiny, false otherwise.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool GetIsShiny(in uint id32, in uint pid, [ConstantExpected(Max = 16, Min = 8)] uint cmp = 16) => GetShinyXor(id32, pid) < cmp;
public static uint GetShinyXor(in uint pid, in uint id32)
{
var xor = pid ^ id32;
return (xor ^ (xor >> 16)) & 0xFFFF;
}
/// <summary>
/// Computes the shiny XOR value.
/// </summary>
/// <param name="pid">Entity PID.</param>
/// <param name="id32">Combined Trainer ID and Secret ID.</param>
/// <returns>Shiny XOR value.</returns>
public static uint GetShinyXor(in uint pid, in uint id32) => GetShinyXor(pid ^ id32);
/// <summary>
/// Computes the shiny XOR value.
/// </summary>
/// <param name="component">Combined/raw value to compute with.</param>
/// <returns>Shiny XOR value.</returns>
public static uint GetShinyXor(in uint component) => (component ^ (component >> 16)) & 0xFFFF;
/// <summary>
/// Forces the shiny state of the PID.
/// </summary>
/// <param name="isShiny">Indicates if the PID should be shiny.</param>
/// <param name="pid">Entity PID.</param>
/// <param name="id32">Combined Trainer ID and Secret ID.</param>
/// <param name="xorType">Shiny XOR type.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ForceShinyState(bool isShiny, ref uint pid, uint id32, in uint xorType)
{
@@ -35,5 +69,11 @@ public static void ForceShinyState(bool isShiny, ref uint pid, uint id32, in uin
}
}
public static bool GetIsShinyGB(ushort dv16) => ((dv16 & 0xFFF) == 0xAAA) && (((dv16 >> 12) & 2) != 0);
/// <summary>
/// Checks if the PID is shiny.
/// </summary>
/// <remarks>Used for Gen 2.</remarks>
/// <param name="dv16">16-bit DVs.</param>
/// <returns>True if shiny, false otherwise.</returns>
public static bool GetIsShinyGB(ushort dv16) => (dv16 & 0x2FFF) == 0x2AAA;
}

View File

@@ -79,6 +79,9 @@ internal static class GBRestrictions
_ => false,
};
/// <summary>
/// Indicates if the species will always evolve if traded to a Generation 1 player.
/// </summary>
internal static bool IsTradeEvolution1(ushort species) => species is (int)Kadabra or (int)Machoke or (int)Graveler or (int)Haunter;
public static bool RateMatchesEncounter(ushort species, GameVersion version, byte rate)
@@ -121,7 +124,7 @@ private static bool GetCatchRateMatchesPreEvolution(PK1 pk, byte rate)
/// </summary>
/// <param name="pk">Data to check</param>
/// <returns>true if it can inhabit, false if it can not.</returns>
internal static bool CanInhabitGen1(this PKM pk)
private static bool CanOriginateGen1(this PKM pk)
{
// Korean Gen2 games can't trade-back because there are no Gen1 Korean games released
if (pk.Korean || pk.IsEgg)
@@ -131,14 +134,17 @@ internal static bool CanInhabitGen1(this PKM pk)
// If you put a Pokémon in the N64 box, the met info is retained, even if you switch over to a Gen1 game to teach it TMs
// You can use rare candies from within the lab, so level-up moves from RBY context can be learned this way as well
// Stadium 2 is GB Cart Era only (not 3DS Virtual Console).
if (pk is ICaughtData2 {CaughtData: not 0} && !ParseSettings.AllowGBStadium2)
// This method is only called for Encounter enumeration; if it has Gen2 data, it is not a Gen1 encounter.
if (pk is ICaughtData2 {CaughtData: not 0})
return false;
// Sanity check species, if it could have existed as a pre-evolution.
ushort species = pk.Species;
if (species <= MaxSpeciesID_1)
return true;
return IsEvolvedFromGen1Species(species);
return CanVisitGen1(pk.Species);
}
internal static bool CanVisitGen1(ushort species)
{
return species <= MaxSpeciesID_1 || IsEvolvedFromGen1Species(species);
}
/// <summary>
@@ -151,7 +157,7 @@ internal static PotentialGBOrigin GetTradebackStatusInitial(PKM pk)
return GetTradebackStatusRBY(pk1);
if (pk.Format == 2 || pk.VC2) // Check for impossible Tradeback scenarios
return !pk.CanInhabitGen1() ? Gen2Only : Either;
return !pk.CanOriginateGen1() ? Gen2Only : Either;
// VC2 is released, we can assume it will be TradebackType.Any.
// Is impossible to differentiate a VC1 Pokémon traded to Gen7 after VC2 is available.
@@ -183,50 +189,26 @@ private static PotentialGBOrigin GetTradebackStatusRBY(PK1 pk)
return Gen1Only;
}
public static TimeCapsuleEvaluation IsTimeCapsuleTransferred(PKM pk, ReadOnlySpan<MoveResult> moves, IEncounterTemplate enc)
public static TimeCapsuleEvaluation IsTimeCapsuleTransferred(PK1 pk, ReadOnlySpan<MoveResult> moves, IEncounterTemplate enc)
{
foreach (var z in moves)
if (enc.Generation == 2)
return Transferred21;
var rate = pk.CatchRate;
if (rate == 0)
return Transferred12;
if (MoveInfo.IsAnyFromGeneration(2, moves))
{
if (z.Generation == enc.Generation || z.Generation is not (1 or 2))
continue;
if (pk is PK1 {CatchRate: not 0} g1 && !IsTradebackCatchRate(g1.CatchRate))
if (pk is {CatchRate: not 0} && !IsTradebackCatchRate(pk.CatchRate))
return BadCatchRate;
return enc.Generation == 2 ? Transferred21 : Transferred12;
return Transferred12;
}
if (pk is not GBPKM gb)
{
return enc.Generation switch
{
1 when pk.VC2 => Transferred12,
2 when pk.VC1 => Transferred21,
_ => NotTransferred,
};
}
if (gb is ICaughtData2 pk2)
{
if (enc.Generation == 1)
return Transferred12;
if (pk2.CaughtData != 0)
return NotTransferred;
if (enc.Version == C)
return Transferred21;
return Indeterminate;
}
if (gb is PK1 pk1)
{
var rate = pk1.CatchRate;
if (rate == 0)
return Transferred12;
bool isTradebackItem = IsTradebackCatchRate(rate);
if (IsCatchRateMatchEncounter(enc, pk1))
return isTradebackItem ? Indeterminate : NotTransferred;
return isTradebackItem ? Transferred12 : BadCatchRate;
}
return Indeterminate;
bool isTradebackItem = IsTradebackCatchRate(rate);
if (IsCatchRateMatchEncounter(enc, pk))
return isTradebackItem ? Indeterminate : NotTransferred;
return isTradebackItem ? Transferred12 : BadCatchRate;
}
private static bool IsCatchRateMatchEncounter(IEncounterTemplate enc, PK1 pk1) => enc switch
@@ -291,14 +273,3 @@ public enum TimeCapsuleEvaluation
/// </summary>
BadCatchRate,
}
/// <summary>
/// Extension methods for <see cref="TimeCapsuleEvaluation"/>.
/// </summary>
public static class TimeCapsuleEvlautationExtensions
{
/// <summary>
/// Indicates if the <see cref="eval"/> definitely transferred via Time Capsule.
/// </summary>
public static bool WasTimeCapsuleTransferred(this TimeCapsuleEvaluation eval) => eval is not (Indeterminate or NotTransferred or BadCatchRate);
}

View File

@@ -42,16 +42,12 @@ public SimpleTrainerInfo(ITrainerInfo other, GameVersion specified) : this(speci
Language = other.Language;
Generation = other.Generation;
Context = other.Context;
if (Context is not (EntityContext.Gen6 or EntityContext.Gen7))
{
ConsoleRegion = Region = Country = 0;
}
else if (other is IRegionOriginReadOnly r)
{
ConsoleRegion = r.ConsoleRegion;
Region = r.Region;
Country = r.Country;
}
return;
var geo = other.GetRegionOrigin(other.Language);
ConsoleRegion = geo.ConsoleRegion;
Region = geo.Region;
Country = geo.Country;
}
}