mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-05-09 12:35:20 -05:00
Expose shiny potential value
Not really digging it currently as it doesn't cover multi-state like AlwaysStar-Or-Never, but that single edge case can be handled elsewhere
This commit is contained in:
parent
a08330ffd4
commit
f83a9bf833
|
|
@ -14,6 +14,11 @@ public sealed record EncounterEgg(int Species, int Form, int Level, int Generati
|
|||
public int LevelMin => Level;
|
||||
public int LevelMax => Level;
|
||||
public bool IsShiny => false;
|
||||
public int Location => 0;
|
||||
public int EggLocation => Locations.GetDaycareLocation(Generation, Version);
|
||||
public Ball FixedBall => BallBreedLegality.GetDefaultBall(Version, Species);
|
||||
public Shiny Shiny => Shiny.Random;
|
||||
public int Ability => 0;
|
||||
|
||||
public bool CanHaveVoltTackle => Species is (int)Core.Species.Pichu && (Generation > 3 || Version is GameVersion.E);
|
||||
|
||||
|
|
@ -34,7 +39,9 @@ public PKM ConvertToPKM(ITrainerInfo sav, EncounterCriteria criteria)
|
|||
pk.Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, gen);
|
||||
pk.CurrentLevel = Level;
|
||||
pk.Version = (int)version;
|
||||
pk.Ball = (int)BallBreedLegality.GetDefaultBall(Version, Species);
|
||||
|
||||
var ball = FixedBall;
|
||||
pk.Ball = ball is Ball.None ? (int)Ball.Poke : (int)ball;
|
||||
pk.OT_Friendship = pk.PersonalInfo.BaseFriendship;
|
||||
|
||||
SetEncounterMoves(pk, version);
|
||||
|
|
|
|||
|
|
@ -17,9 +17,14 @@ public sealed record EncounterInvalid : IEncounterable
|
|||
public int Generation { get; }
|
||||
public GameVersion Version { get; }
|
||||
public bool IsShiny => false;
|
||||
public Shiny Shiny => Shiny.Never;
|
||||
|
||||
public string Name => "Invalid";
|
||||
public string LongName => "Invalid";
|
||||
public int Location => 0;
|
||||
public int EggLocation => 0;
|
||||
public int Ability => 0;
|
||||
public Ball FixedBall => Ball.None;
|
||||
|
||||
private EncounterInvalid() { }
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ namespace PKHeX.Core
|
|||
/// Wild Encounter Slot data
|
||||
/// </summary>
|
||||
/// <remarks>Wild encounter slots are found as random encounters in-game.</remarks>
|
||||
public abstract record EncounterSlot(EncounterArea Area, int Species, int Form, int LevelMin, int LevelMax) : IEncounterable, ILocation, IEncounterMatch, IFixedAbilityNumber
|
||||
public abstract record EncounterSlot(EncounterArea Area, int Species, int Form, int LevelMin, int LevelMax) : IEncounterable, IEncounterMatch
|
||||
{
|
||||
public abstract int Generation { get; }
|
||||
public bool EggEncounter => false;
|
||||
|
|
@ -17,6 +17,8 @@ public abstract record EncounterSlot(EncounterArea Area, int Species, int Form,
|
|||
public GameVersion Version => Area.Version;
|
||||
public int Location => Area.Location;
|
||||
public int EggLocation => 0;
|
||||
public virtual Ball FixedBall => Ball.None;
|
||||
public virtual Shiny Shiny => Shiny.Random;
|
||||
|
||||
public bool IsFixedLevel => LevelMin == LevelMax;
|
||||
public bool IsRandomLevel => LevelMin != LevelMax;
|
||||
|
|
@ -68,12 +70,6 @@ public virtual string LongName
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a required ball if the wild encounter can only be caught in certain scenarios.
|
||||
/// </summary>
|
||||
/// <returns><see cref="Ball.None"/> if unrestricted, otherwise, a specific ball value.</returns>
|
||||
public virtual Ball GetRequiredBallValue() => Ball.None;
|
||||
|
||||
public PKM ConvertToPKM(ITrainerInfo sav) => ConvertToPKM(sav, EncounterCriteria.Unrestricted);
|
||||
|
||||
public PKM ConvertToPKM(ITrainerInfo sav, EncounterCriteria criteria)
|
||||
|
|
@ -95,7 +91,7 @@ protected virtual void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria
|
|||
pk.Version = (int)version;
|
||||
pk.Nickname = SpeciesName.GetSpeciesNameGeneration(Species, lang, Generation);
|
||||
|
||||
var ball = GetRequiredBallValue();
|
||||
var ball = FixedBall;
|
||||
pk.Ball = (int)(ball == Ball.None ? Ball.Poke : ball);
|
||||
pk.Language = lang;
|
||||
pk.Form = GetWildForm(pk, Form, sav);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ public sealed record EncounterSlot1 : EncounterSlot, INumberedSlot
|
|||
{
|
||||
public override int Generation => 1;
|
||||
public int SlotNumber { get; }
|
||||
public override Ball FixedBall => Ball.Poke;
|
||||
|
||||
public EncounterSlot1(EncounterArea1 area, int species, int min, int max, int slot) : base(area, species, 0, min, max)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ public sealed record EncounterSlot2 : EncounterSlot, INumberedSlot
|
|||
{
|
||||
public override int Generation => 2;
|
||||
public int SlotNumber { get; }
|
||||
public override Ball FixedBall => Ball.Poke;
|
||||
|
||||
public EncounterSlot2(EncounterArea2 area, int species, int min, int max, int slot) : base(area, species, species == 201 ? FormRandom : 0, min, max)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ public record EncounterSlot3 : EncounterSlot, IMagnetStatic, INumberedSlot, ISlo
|
|||
public SlotType Type => Area.Type;
|
||||
|
||||
public int SlotNumber { get; }
|
||||
public override Ball FixedBall => Locations.IsSafariZoneLocation3(Location) ? Ball.Safari : Ball.None;
|
||||
|
||||
public EncounterSlot3(EncounterArea3 area, int species, int form, int min, int max, int slot, int mpi, int mpc, int sti, int stc) : base(area, species, form, min, max)
|
||||
{
|
||||
|
|
@ -36,6 +37,5 @@ public override EncounterMatchRating GetMatchRating(PKM pkm)
|
|||
|
||||
private bool IsDeferredSafari3(bool IsSafariBall) => IsSafariBall != Locations.IsSafariZoneLocation3(Location);
|
||||
|
||||
public override Ball GetRequiredBallValue() => Locations.IsSafariZoneLocation3(Location) ? Ball.Safari : Ball.None;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ public sealed record EncounterSlot4 : EncounterSlot, IMagnetStatic, INumberedSlo
|
|||
public SlotType Type => Area.Type;
|
||||
|
||||
public int SlotNumber { get; }
|
||||
public override Ball FixedBall => GetRequiredBallValue();
|
||||
public bool CanUseRadar => !GameVersion.HGSS.Contains(Version) && GroundTile.HasFlag(GroundTilePermission.Grass);
|
||||
|
||||
public EncounterSlot4(EncounterArea4 area, int species, int form, int min, int max, int slot, int mpi, int mpc, int sti, int stc) : base(area, species, form, min, max)
|
||||
|
|
@ -44,7 +45,7 @@ public override EncounterMatchRating GetMatchRating(PKM pkm)
|
|||
return base.GetMatchRating(pkm);
|
||||
}
|
||||
|
||||
public override Ball GetRequiredBallValue()
|
||||
private Ball GetRequiredBallValue()
|
||||
{
|
||||
if (Type is SlotType.BugContest)
|
||||
return Ball.Sport;
|
||||
|
|
|
|||
|
|
@ -31,6 +31,6 @@ protected override void SetPINGA(PKM pk, EncounterCriteria criteria)
|
|||
|
||||
protected override HiddenAbilityPermission IsHiddenAbilitySlot() => IsSOS ? HiddenAbilityPermission.Possible : HiddenAbilityPermission.Never;
|
||||
|
||||
public override Ball GetRequiredBallValue() => Location == Locations.Pelago7 ? Ball.Poke : Ball.None;
|
||||
public override Ball FixedBall => Location == Locations.Pelago7 ? Ball.Poke : Ball.None;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ public sealed record EncounterSlot8b : EncounterSlot
|
|||
public bool IsUnderground => Area.Location is (>= 508 and <= 617);
|
||||
public bool IsMarsh => Area.Location is (>= 219 and <= 224);
|
||||
public readonly bool IsBCAT;
|
||||
public override Ball FixedBall => IsMarsh ? Ball.Safari : Ball.None;
|
||||
|
||||
public EncounterSlot8b(EncounterArea area, int species, int form, int min, int max, bool isBCAT = false) : base(area, species, form, min, max)
|
||||
{
|
||||
|
|
@ -34,10 +35,6 @@ protected override void SetFormatSpecificData(PKM pk)
|
|||
if (GetBaseEggMove(out int move1))
|
||||
pk.RelearnMove1 = move1;
|
||||
}
|
||||
else if (IsMarsh)
|
||||
{
|
||||
pk.Ball = (int)Ball.Safari;
|
||||
}
|
||||
pk.SetRandomEC();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ namespace PKHeX.Core
|
|||
/// <summary>
|
||||
/// Contains details about an encounter that can be found in <see cref="GameVersion.GO"/>.
|
||||
/// </summary>
|
||||
public abstract record EncounterSlotGO : EncounterSlot, IPogoSlot, IFixedBall
|
||||
public abstract record EncounterSlotGO : EncounterSlot, IPogoSlot
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public int Start { get; }
|
||||
|
|
@ -13,8 +13,7 @@ public abstract record EncounterSlotGO : EncounterSlot, IPogoSlot, IFixedBall
|
|||
/// <inheritdoc/>
|
||||
public int End { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Shiny Shiny { get; }
|
||||
public override Shiny Shiny { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public PogoType Type { get; }
|
||||
|
|
@ -24,7 +23,7 @@ public abstract record EncounterSlotGO : EncounterSlot, IPogoSlot, IFixedBall
|
|||
|
||||
public override bool IsShiny => Shiny.IsShiny();
|
||||
|
||||
public Ball FixedBall => Type.GetValidBall();
|
||||
public override Ball FixedBall => Type.GetValidBall();
|
||||
|
||||
protected EncounterSlotGO(EncounterArea area, int species, int form, int start, int end, Shiny shiny, Gender gender, PogoType type) : base(area, species, form, type.GetMinLevel(), EncountersGO.MAX_LEVEL)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace PKHeX.Core
|
|||
/// <remarks>
|
||||
/// Static Encounters are fixed position encounters with properties that are not subject to Wild Encounter conditions.
|
||||
/// </remarks>
|
||||
public abstract record EncounterStatic(GameVersion Version) : IEncounterable, IMoveset, ILocation, IEncounterMatch, IFixedBall, IFixedAbilityNumber
|
||||
public abstract record EncounterStatic(GameVersion Version) : IEncounterable, IMoveset, IEncounterMatch
|
||||
{
|
||||
public int Species { get; init; }
|
||||
public int Form { get; init; }
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace PKHeX.Core
|
|||
/// <remarks>
|
||||
/// Trade data is fixed level in all cases except for the first few generations of games.
|
||||
/// </remarks>
|
||||
public abstract record EncounterTrade(GameVersion Version) : IEncounterable, IMoveset, ILocation, IEncounterMatch, IFixedBall, IFixedAbilityNumber
|
||||
public abstract record EncounterTrade(GameVersion Version) : IEncounterable, IMoveset, IEncounterMatch
|
||||
{
|
||||
public int Species { get; init; }
|
||||
public int Form { get; init; }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
/// Common Encounter Properties base interface.
|
||||
/// <inheritdoc cref="IEncounterInfo"/>
|
||||
/// </summary>
|
||||
public interface IEncounterable : IEncounterInfo
|
||||
public interface IEncounterable : IEncounterInfo, ILocation, IFixedAbilityNumber, IFixedBall, IShinyPotential
|
||||
{
|
||||
/// <summary>
|
||||
/// Short name to describe the encounter data, usually just indicating which of the main component encounter types the data is.
|
||||
|
|
|
|||
6
PKHeX.Core/Legality/Structures/IResultantShiny.cs
Normal file
6
PKHeX.Core/Legality/Structures/IResultantShiny.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
public interface IResultantShiny
|
||||
{
|
||||
Shiny CanBeShiny { get; }
|
||||
}
|
||||
|
|
@ -153,5 +153,14 @@ public static bool IsEggLocationBred4(int loc, GameVersion ver)
|
|||
GameVersion.BD or GameVersion.SP => Default8bNone,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
public static int GetDaycareLocation(int generation, GameVersion version) => generation switch
|
||||
{
|
||||
1 or 2 or 3 => 0,
|
||||
4 => Daycare4,
|
||||
5 => Daycare5,
|
||||
8 when version is GameVersion.BD or GameVersion.SP => Daycare8b,
|
||||
_ => Daycare5,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1047,13 +1047,13 @@ internal static class BallBreedLegality
|
|||
/// <remarks>Not all things can hatch with a Poké Ball!</remarks>
|
||||
public static Ball GetDefaultBall(GameVersion version, int species)
|
||||
{
|
||||
if (GameVersion.BDSP.Contains(version))
|
||||
if (version is GameVersion.BD or GameVersion.SP)
|
||||
{
|
||||
if (BanInheritedExceptSafari_BDSP.Contains(species))
|
||||
return Ball.Safari;
|
||||
}
|
||||
|
||||
return Ball.Poke;
|
||||
return Ball.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ private CheckResult VerifyBallStatic(LegalityAnalysis data, EncounterStatic s)
|
|||
|
||||
private CheckResult VerifyBallWild(LegalityAnalysis data, EncounterSlot w)
|
||||
{
|
||||
var req = w.GetRequiredBallValue();
|
||||
var req = w.FixedBall;
|
||||
if (req != None)
|
||||
return VerifyBallEquals(data, (int) req);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace PKHeX.Core
|
|||
/// <summary>
|
||||
/// Mystery Gift Template File
|
||||
/// </summary>
|
||||
public abstract class MysteryGift : IEncounterable, IMoveset, IRelearn, ILocation, IFixedBall, IFixedAbilityNumber
|
||||
public abstract class MysteryGift : IEncounterable, IMoveset, IRelearn
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether or not the given length of bytes is valid for a mystery gift.
|
||||
|
|
@ -133,6 +133,13 @@ public virtual GameVersion Version
|
|||
public virtual IReadOnlyList<int> Relearn { get => Array.Empty<int>(); set { } }
|
||||
public virtual int[] IVs { get => Array.Empty<int>(); set { } }
|
||||
public virtual bool IsShiny => false;
|
||||
|
||||
public virtual Shiny Shiny
|
||||
{
|
||||
get => Shiny.Never;
|
||||
init => throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public virtual bool IsEgg { get => false; set { } }
|
||||
public virtual int HeldItem { get => -1; set { } }
|
||||
public virtual int AbilityType { get => -1; set { } }
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public override string CardTitle
|
|||
public override IReadOnlyList<int> Moves { get => Gift.Moves; set => Gift.Moves = value; }
|
||||
public override int HeldItem { get => Gift.HeldItem; set => Gift.HeldItem = value; }
|
||||
public override bool IsShiny => Gift.IsShiny;
|
||||
public override Shiny Shiny => Gift.Shiny;
|
||||
public override bool IsEgg { get => Gift.IsEgg; set => Gift.IsEgg = value; }
|
||||
public override int Gender { get => Gift.Gender; set => Gift.Gender = value; }
|
||||
public override int Form { get => Gift.Form; set => Gift.Form = value; }
|
||||
|
|
|
|||
|
|
@ -329,6 +329,13 @@ private void SetPID(PKM pk, int av)
|
|||
pk.PID &= 0xFFFEFFFF;
|
||||
}
|
||||
|
||||
public override Shiny Shiny => PIDType switch
|
||||
{
|
||||
1 => Shiny.Random,
|
||||
2 => Shiny.Always,
|
||||
_ => Shiny.Never,
|
||||
};
|
||||
|
||||
private void SetIVs(PKM pk)
|
||||
{
|
||||
Span<int> finalIVs = stackalloc int[6];
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ private enum GiftType
|
|||
public override string CardTitle { get => "Raw Gift (PGT)"; set { } }
|
||||
public override int CardID { get => -1; set { } }
|
||||
public override bool GiftUsed { get => false; set { } }
|
||||
public override Shiny Shiny => IsEgg ? Shiny.Random : PK.PID == 1 ? Shiny.Never : IsShiny ? Shiny.Always : Shiny.Never;
|
||||
|
||||
public PGT() : this(new byte[Size]) { }
|
||||
public PGT(byte[] data) : base(data) { }
|
||||
|
|
|
|||
|
|
@ -134,6 +134,7 @@ public override int Quantity
|
|||
// Pokémon Properties
|
||||
public override bool IsPokémon { get => CardType == 0; set { if (value) CardType = 0; } }
|
||||
public override bool IsShiny => PIDType == Shiny.Always;
|
||||
public override Shiny Shiny => PIDType;
|
||||
|
||||
public override int TID
|
||||
{
|
||||
|
|
|
|||
|
|
@ -85,27 +85,36 @@ public override int Quantity
|
|||
// Pokémon Properties
|
||||
public override bool IsPokémon { get => CardType == GiftType.Pokemon; set { if (value) CardType = GiftType.Pokemon; } }
|
||||
|
||||
public override bool IsShiny
|
||||
public override bool IsShiny => Shiny.IsShiny();
|
||||
|
||||
public override Shiny Shiny
|
||||
{
|
||||
get
|
||||
{
|
||||
var type = PIDType;
|
||||
if (type is Shiny.AlwaysStar or Shiny.AlwaysSquare)
|
||||
return true;
|
||||
if (type != Shiny.FixedValue)
|
||||
return false;
|
||||
|
||||
// Player owned anti-shiny fixed PID
|
||||
if (TID == 0 && SID == 0)
|
||||
return false;
|
||||
|
||||
var pid = PID;
|
||||
var psv = (int)((pid >> 16 ^ (pid & 0xFFFF)) >> 4);
|
||||
var tsv = (TID ^ SID) >> 4;
|
||||
return (psv ^ tsv) == 0;
|
||||
if (type is not Shiny.FixedValue)
|
||||
return type;
|
||||
return GetShinyXor() switch
|
||||
{
|
||||
0 => Shiny.AlwaysSquare,
|
||||
<= 15 => Shiny.AlwaysStar,
|
||||
_ => Shiny.Never,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private int GetShinyXor()
|
||||
{
|
||||
// Player owned anti-shiny fixed PID
|
||||
if (TID == 0 && SID == 0)
|
||||
return int.MaxValue;
|
||||
|
||||
var pid = PID;
|
||||
var psv = (int)(pid >> 16 ^ (pid & 0xFFFF));
|
||||
var tsv = (TID ^ SID);
|
||||
return psv ^ tsv;
|
||||
}
|
||||
|
||||
public override int TID
|
||||
{
|
||||
get => ReadUInt16LittleEndian(Data.AsSpan(CardStart + 0x20));
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public sealed class WC3 : MysteryGift, IRibbonSetEvent3, ILangNicknamedTemplate
|
|||
public override bool IsEgg { get; set; }
|
||||
public override IReadOnlyList<int> Moves { get; set; } = Array.Empty<int>();
|
||||
public bool NotDistributed { get; init; }
|
||||
public Shiny Shiny { get; init; } = Shiny.Random;
|
||||
public override Shiny Shiny { get; init; } = Shiny.Random;
|
||||
public bool Fateful { get; init; } // Obedience Flag
|
||||
|
||||
// Mystery Gift Properties
|
||||
|
|
|
|||
|
|
@ -122,7 +122,36 @@ private uint Day
|
|||
|
||||
// Pokémon Properties
|
||||
public override bool IsPokémon { get => CardType == 0; set { if (value) CardType = 0; } }
|
||||
public override bool IsShiny => PIDType == Shiny.Always;
|
||||
public override bool IsShiny => Shiny.IsShiny();
|
||||
|
||||
public override Shiny Shiny
|
||||
{
|
||||
get
|
||||
{
|
||||
var type = PIDType;
|
||||
if (type is not Shiny.FixedValue)
|
||||
return type;
|
||||
return GetShinyXor() switch
|
||||
{
|
||||
0 => Shiny.AlwaysSquare,
|
||||
<= 15 => Shiny.AlwaysStar,
|
||||
_ => Shiny.Never,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private int GetShinyXor()
|
||||
{
|
||||
// Player owned anti-shiny fixed PID
|
||||
if (TID == 0 && SID == 0)
|
||||
return int.MaxValue;
|
||||
|
||||
var pid = PID;
|
||||
var psv = (int)(pid >> 16 ^ (pid & 0xFFFF));
|
||||
var tsv = (TID ^ SID);
|
||||
return psv ^ tsv;
|
||||
}
|
||||
|
||||
public override int TID { get => ReadUInt16LittleEndian(Data.AsSpan(0x68)); set => WriteUInt16LittleEndian(Data.AsSpan(0x68), (ushort)value); }
|
||||
public override int SID { get => ReadUInt16LittleEndian(Data.AsSpan(0x6A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x6A), (ushort)value); }
|
||||
public int OriginGame { get => Data[0x6C]; set => Data[0x6C] = (byte)value; }
|
||||
|
|
|
|||
|
|
@ -137,7 +137,35 @@ public override int Quantity
|
|||
|
||||
// Pokémon Properties
|
||||
public override bool IsPokémon { get => CardType == 0; set { if (value) CardType = 0; } }
|
||||
public override bool IsShiny => PIDType == Shiny.Always;
|
||||
public override bool IsShiny => Shiny.IsShiny();
|
||||
|
||||
public override Shiny Shiny
|
||||
{
|
||||
get
|
||||
{
|
||||
var type = PIDType;
|
||||
if (type is not Shiny.FixedValue)
|
||||
return type;
|
||||
return GetShinyXor() switch
|
||||
{
|
||||
0 => Shiny.AlwaysSquare,
|
||||
<= 15 => Shiny.AlwaysStar,
|
||||
_ => Shiny.Never,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private int GetShinyXor()
|
||||
{
|
||||
// Player owned anti-shiny fixed PID
|
||||
if (TID == 0 && SID == 0)
|
||||
return int.MaxValue;
|
||||
|
||||
var pid = PID;
|
||||
var psv = (int)(pid >> 16 ^ (pid & 0xFFFF));
|
||||
var tsv = (TID ^ SID);
|
||||
return psv ^ tsv;
|
||||
}
|
||||
|
||||
public override int TID
|
||||
{
|
||||
|
|
|
|||
|
|
@ -79,27 +79,36 @@ public override int Quantity
|
|||
// Pokémon Properties
|
||||
public override bool IsPokémon { get => CardType == GiftType.Pokemon; set { if (value) CardType = GiftType.Pokemon; } }
|
||||
|
||||
public override bool IsShiny
|
||||
public override bool IsShiny => Shiny.IsShiny();
|
||||
|
||||
public override Shiny Shiny
|
||||
{
|
||||
get
|
||||
{
|
||||
var type = PIDType;
|
||||
if (type is Shiny.AlwaysStar or Shiny.AlwaysSquare)
|
||||
return true;
|
||||
if (type != Shiny.FixedValue)
|
||||
return false;
|
||||
|
||||
// Player owned anti-shiny fixed PID
|
||||
if (TID == 0 && SID == 0)
|
||||
return false;
|
||||
|
||||
var pid = PID;
|
||||
var psv = (int)((pid >> 16 ^ (pid & 0xFFFF)) >> 4);
|
||||
var tsv = (TID ^ SID) >> 4;
|
||||
return (psv ^ tsv) == 0;
|
||||
if (type is not Shiny.FixedValue)
|
||||
return type;
|
||||
return GetShinyXor() switch
|
||||
{
|
||||
0 => Shiny.AlwaysSquare,
|
||||
<= 15 => Shiny.AlwaysStar,
|
||||
_ => Shiny.Never,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private int GetShinyXor()
|
||||
{
|
||||
// Player owned anti-shiny fixed PID
|
||||
if (TID == 0 && SID == 0)
|
||||
return int.MaxValue;
|
||||
|
||||
var pid = PID;
|
||||
var psv = (int)(pid >> 16 ^ (pid & 0xFFFF));
|
||||
var tsv = (TID ^ SID);
|
||||
return psv ^ tsv;
|
||||
}
|
||||
|
||||
public override int TID
|
||||
{
|
||||
get => ReadUInt16LittleEndian(Data.AsSpan(CardStart + 0x20));
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ public LanguageID LanguageReceived
|
|||
public override bool IsMatchExact(PKM pkm, DexLevel evo) => false;
|
||||
protected override bool IsMatchDeferred(PKM pkm) => false;
|
||||
protected override bool IsMatchPartial(PKM pkm) => false;
|
||||
public override Shiny Shiny => Shiny.Never;
|
||||
|
||||
public override int Location { get; set; }
|
||||
public override int EggLocation { get; set; }
|
||||
|
|
|
|||
9
PKHeX.Core/PKM/Shared/IShinyPotential.cs
Normal file
9
PKHeX.Core/PKM/Shared/IShinyPotential.cs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Interface that exposes a shiny potential state indicating what kinds of <see cref="Core.Shiny"/> can be expressed.
|
||||
/// </summary>
|
||||
public interface IShinyPotential
|
||||
{
|
||||
Shiny Shiny { get; }
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user