mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 06:34:19 +00:00
Initial support for Pokémon HOME 3.0.0 (#3899)
* Heavily rewrites the `PKH` abstractions. * Uses HOME's core-side classes as the transfer middlemen instead of direct A->B transfers. * Revises logic to account for most of HOME's quirks (scale/height copying, safe refuge PLA) Future revisions hinge on better handling of evotree (need better metadata about existing as specific evolutions in each game). --------- Co-authored-by: sora10pls <17801814+sora10pls@users.noreply.github.com> Co-authored-by: Lusamine <30205550+Lusamine@users.noreply.github.com>
This commit is contained in:
parent
92258f6755
commit
1174e354b1
75 changed files with 1829 additions and 1548 deletions
|
@ -64,4 +64,6 @@ public static class BallExtensions
|
|||
/// <param name="ball">Ball ID</param>
|
||||
/// <returns>True if Apricorn, false if not.</returns>
|
||||
public static bool IsApricornBall(this Ball ball) => ball is >= Ball.Fast and <= Ball.Moon;
|
||||
|
||||
public static bool IsLegendBall(this Ball ball) => ball is >= Ball.LAPoke and <= Ball.LAOrigin;
|
||||
}
|
||||
|
|
|
@ -156,10 +156,12 @@ public sealed class MetDataSource
|
|||
Util.AddCBWithOffset(locations, s.Gen8.Met6, 60000, Locations8.Met6);
|
||||
|
||||
// Add in the BDSP+PLA magic met locations.
|
||||
locations.Add(new ComboItem($"{s.EggName} (BD/SP)", Locations.HOME_SWSHBDSPEgg));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)BD], Locations.HOME_SWBD));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)SP], Locations.HOME_SHSP));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)PLA], Locations.HOME_SWLA));
|
||||
locations.Add(new ComboItem($"{s.EggName} (HOME)", LocationsHOME.SWSHEgg));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)SL], LocationsHOME.SWSL));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)VL], LocationsHOME.SHVL));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)BD], LocationsHOME.SWBD));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)SP], LocationsHOME.SHSP));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)PLA], LocationsHOME.SWLA));
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
@ -174,10 +176,10 @@ public sealed class MetDataSource
|
|||
Util.AddCBWithOffset(locations, s.Gen8a.Met6, 60000, Locations8a.Met6);
|
||||
|
||||
// Add in the BDSP+PLA magic met locations.
|
||||
locations.Add(new ComboItem($"{s.EggName} (BD/SP)", Locations.HOME_SWSHBDSPEgg));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)BD], Locations.HOME_SWBD));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)SP], Locations.HOME_SHSP));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)PLA], Locations.HOME_SWLA));
|
||||
locations.Add(new ComboItem($"{s.EggName} (HOME)", LocationsHOME.SWSHEgg));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)BD], LocationsHOME.SWBD));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)SP], LocationsHOME.SHSP));
|
||||
locations.Add(new ComboItem(s.gamelist[(int)PLA], LocationsHOME.SWLA));
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
|
|
@ -238,14 +238,16 @@ public static class GameUtil
|
|||
var max = obj.MaxGameID;
|
||||
if (max == Legal.MaxGameID_7b) // edge case
|
||||
return new[] {GO, GP, GE};
|
||||
if (max == Legal.MaxGameID_8)
|
||||
max = Legal.MaxGameID_8a;
|
||||
var versions = GameVersions
|
||||
.Where(version => (GameVersion)obj.MinGameID <= version && version <= (GameVersion)max);
|
||||
if (generation < 0)
|
||||
return versions;
|
||||
if (max == Legal.MaxGameID_7 && generation == 7)
|
||||
versions = versions.Where(version => version != GO);
|
||||
|
||||
// HOME allows up-reach to Gen9
|
||||
if (generation >= 8)
|
||||
generation = 9;
|
||||
return versions.Where(version => version.GetGeneration() <= generation);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,45 +103,9 @@ public static class Locations
|
|||
/// <summary> Generation 8 Gift from Pokémon HOME </summary>
|
||||
public const ushort HOME8 = 30018;
|
||||
|
||||
public const ushort HOME_SHSP = 59998; // SP traded to (SW)SH
|
||||
public const ushort HOME_SWBD = 59999; // BD traded to SW(SH)
|
||||
public const ushort HOME_SWLA = 60000; // PLA traded to SW(SH)
|
||||
public const ushort HOME_SWSHBDSPEgg = 65534; // -2 = 8bNone-1..
|
||||
/// <summary> Generation 8 BD/SP Magic location for "None" since 0 is an actual met location. </summary>
|
||||
public const ushort Default8bNone = 65535;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SW/SH-context <see cref="GameVersion"/> when an external entity from the input <see cref="ver"/> resides in SW/SH.
|
||||
/// </summary>
|
||||
public static int GetVersionSWSH(int ver) => (GameVersion)ver switch
|
||||
{
|
||||
GameVersion.PLA => (int)GameVersion.SW,
|
||||
GameVersion.BD => (int)GameVersion.SW,
|
||||
GameVersion.SP => (int)GameVersion.SH,
|
||||
_ => ver,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SW/SH-context Met Location when an external entity from the input <see cref="ver"/> resides in SW/SH.
|
||||
/// </summary>
|
||||
public static ushort GetMetSWSH(ushort loc, int ver) => (GameVersion)ver switch
|
||||
{
|
||||
GameVersion.PLA => HOME_SWLA,
|
||||
GameVersion.BD => HOME_SWBD,
|
||||
GameVersion.SP => HOME_SHSP,
|
||||
_ => loc,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the met location is a valid location for the input <see cref="ver"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Relevant when a BD/SP entity is transferred to SW/SH.</remarks>
|
||||
public static bool IsValidMetBDSP(ushort loc, int ver) => loc switch
|
||||
{
|
||||
HOME_SHSP when ver == (int)GameVersion.SH => true,
|
||||
HOME_SWBD when ver == (int)GameVersion.SW => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the egg location value for a traded unhatched egg.
|
||||
/// </summary>
|
||||
|
|
109
PKHeX.Core/Game/Locations/LocationsHOME.cs
Normal file
109
PKHeX.Core/Game/Locations/LocationsHOME.cs
Normal file
|
@ -0,0 +1,109 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Logic for SW/SH met locations from HOME.
|
||||
/// </summary>
|
||||
public static class LocationsHOME
|
||||
{
|
||||
// 60000 - (version - PLA)
|
||||
private const int RemapCount = 5;
|
||||
public const ushort SHVL = 59996; // VL traded to (SW)SH
|
||||
public const ushort SWSL = 59997; // SL traded to SW(SH)
|
||||
public const ushort SHSP = 59998; // SP traded to (SW)SH
|
||||
public const ushort SWBD = 59999; // BD traded to SW(SH)
|
||||
public const ushort SWLA = 60000; // PLA traded to SW(SH)
|
||||
|
||||
public const ushort SWSHEgg = 65534; // -2 = 8bNone-1..
|
||||
|
||||
/// <summary>
|
||||
/// Gets the external entity version needs to be remapped into a SW/SH location.
|
||||
/// </summary>
|
||||
/// <param name="version"></param>
|
||||
/// <returns>True if a known remap exists.</returns>
|
||||
public static bool IsVersionRemapNeeded(int version) => GetRemapIndex(version) < RemapCount;
|
||||
|
||||
private static int GetRemapIndex(int version) => version - (int)GameVersion.PLA;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the SW/SH-context Met Location is one of the remapped HOME locations.
|
||||
/// </summary>
|
||||
public static bool IsLocationSWSH(int met) => met switch
|
||||
{
|
||||
SHVL or SWSL or SHSP or SWBD or SWLA => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the SW/SH-context Egg Location is valid with respect to the <see cref="original"/> location.
|
||||
/// </summary>
|
||||
public static bool IsLocationSWSHEgg(int ver, int met, int egg, ushort original)
|
||||
{
|
||||
if (original > SWLA && egg == SWSHEgg)
|
||||
return true;
|
||||
|
||||
// >60000 can be reset to Link Trade (30001), then altered differently.
|
||||
var expect = GetMetSWSH(original, ver);
|
||||
return expect == met && expect == egg;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SW/SH-context Egg Location when an external entity from the input <see cref="ver"/> resides in SW/SH.
|
||||
/// </summary>
|
||||
public static ushort GetLocationSWSHEgg(int ver, ushort egg)
|
||||
{
|
||||
if (egg == 0)
|
||||
return 0;
|
||||
if (egg > SWLA)
|
||||
return SWSHEgg;
|
||||
// >60000 can be reset to Link Trade (30001), then altered differently.
|
||||
return GetMetSWSH(egg, ver);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SW/SH-context <see cref="GameVersion"/> when an external entity from the input <see cref="ver"/> resides in SW/SH.
|
||||
/// </summary>
|
||||
public static int GetVersionSWSH(int ver) => (GameVersion)ver switch
|
||||
{
|
||||
GameVersion.PLA => (int)GameVersion.SW,
|
||||
GameVersion.BD => (int)GameVersion.SW,
|
||||
GameVersion.SP => (int)GameVersion.SH,
|
||||
GameVersion.SL => (int)GameVersion.SW,
|
||||
GameVersion.VL => (int)GameVersion.SH,
|
||||
_ => ver,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SW/SH-context Met Location when an external entity from the input <see cref="ver"/> resides in SW/SH.
|
||||
/// </summary>
|
||||
public static ushort GetMetSWSH(ushort loc, int ver) => (GameVersion)ver switch
|
||||
{
|
||||
GameVersion.PLA => SWLA,
|
||||
GameVersion.BD => SWBD,
|
||||
GameVersion.SP => SHSP,
|
||||
GameVersion.SL => SWSL,
|
||||
GameVersion.VL => SHVL,
|
||||
_ => loc,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the met location is a valid location for the input <see cref="ver"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Relevant when a BD/SP entity is transferred to SW/SH.</remarks>
|
||||
public static bool IsValidMetBDSP(ushort loc, int ver) => loc switch
|
||||
{
|
||||
SHSP when ver == (int)GameVersion.SH => true,
|
||||
SWBD when ver == (int)GameVersion.SW => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the met location is a valid location for the input <see cref="ver"/>.
|
||||
/// </summary>
|
||||
/// <remarks>Relevant when a S/V entity is transferred to SW/SH.</remarks>
|
||||
public static bool IsValidMetSV(ushort loc, int ver) => loc switch
|
||||
{
|
||||
SHVL when ver == (int)GameVersion.SH => true,
|
||||
SWSL when ver == (int)GameVersion.SW => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
|
@ -176,9 +176,6 @@ public sealed class ItemStorage9SV : IItemStorage
|
|||
0016, // Cherish Ball
|
||||
|
||||
0111, // Odd Keystone
|
||||
0112, // [AUCTION] Griseous Orb
|
||||
0135, // [AUCTION] Adamant Orb
|
||||
0136, // [AUCTION] Lustrous Orb
|
||||
|
||||
0208, // Enigma Berry
|
||||
0209, // Micle Berry
|
||||
|
@ -186,23 +183,6 @@ public sealed class ItemStorage9SV : IItemStorage
|
|||
0211, // Jaboca Berry
|
||||
0212, // Rowap Berry
|
||||
|
||||
0298, // [AUCTION] Flame Plate
|
||||
0299, // [AUCTION] Splash Plate
|
||||
0300, // [AUCTION] Zap Plate
|
||||
0301, // [AUCTION] Meadow Plate
|
||||
0302, // [AUCTION] Icicle Plate
|
||||
0303, // [AUCTION] Fist Plate
|
||||
0304, // [AUCTION] Toxic Plate
|
||||
0305, // [AUCTION] Earth Plate
|
||||
0306, // [AUCTION] Sky Plate
|
||||
0307, // [AUCTION] Mind Plate
|
||||
0308, // [AUCTION] Insect Plate
|
||||
0309, // [AUCTION] Stone Plate
|
||||
0310, // [AUCTION] Spooky Plate
|
||||
0311, // [AUCTION] Draco Plate
|
||||
0312, // [AUCTION] Dread Plate
|
||||
0313, // [AUCTION] Iron Plate
|
||||
|
||||
0485, // Red Apricorn
|
||||
0486, // Blue Apricorn
|
||||
0487, // Yellow Apricorn
|
||||
|
@ -213,21 +193,13 @@ public sealed class ItemStorage9SV : IItemStorage
|
|||
|
||||
0499, // Sport Ball
|
||||
0500, // Park Ball
|
||||
0644, // [AUCTION] Pixie Plate
|
||||
0708, // Lumiose Galette
|
||||
0709, // Shalour Sable
|
||||
|
||||
1103, // [AUCTION] Rusted Sword
|
||||
1104, // [AUCTION] Rusted Shield
|
||||
|
||||
1230, // TM00 - Mega Punch (Nothing learns, not obtainable even though it is assigned a move.)
|
||||
|
||||
1582, // [AUCTION] Galarica Cuff
|
||||
1592, // [AUCTION] Galarica Wreath
|
||||
|
||||
1777, // [AUCTION] Adamant Crystal
|
||||
1778, // [AUCTION] Lustrous Globe
|
||||
1779, // [AUCTION] Griseous Core
|
||||
1582, // Galarica Cuff
|
||||
1592, // Galarica Wreath
|
||||
|
||||
1785, // Strange Ball
|
||||
};
|
||||
|
|
|
@ -104,14 +104,14 @@ public static class Legal
|
|||
internal const int MaxMoveID_8a = (int)Move.TakeHeart;
|
||||
internal const int MaxItemID_8a = 1828; // Legend Plate
|
||||
internal const int MaxBallID_8a = (int)Ball.LAOrigin;
|
||||
internal const int MaxGameID_8a = (int)GameVersion.SP;
|
||||
//internal const int MaxGameID_8a = (int)GameVersion.SP;
|
||||
internal const int MaxAbilityID_8a = MaxAbilityID_8_R2;
|
||||
|
||||
internal const int MaxSpeciesID_8b = MaxSpeciesID_4; // Arceus-493
|
||||
internal const int MaxMoveID_8b = MaxMoveID_8_R2;
|
||||
internal const int MaxItemID_8b = 1822; // DS Sounds
|
||||
internal const int MaxBallID_8b = (int)Ball.LAOrigin;
|
||||
internal const int MaxGameID_8b = (int)GameVersion.SP;
|
||||
//internal const int MaxGameID_8b = (int)GameVersion.SP;
|
||||
internal const int MaxAbilityID_8b = MaxAbilityID_8_R2;
|
||||
|
||||
internal const int MaxSpeciesID_9 = (int)Species.IronLeaves;
|
||||
|
@ -121,6 +121,7 @@ public static class Legal
|
|||
|
||||
internal const int MaxBallID_9 = (int)Ball.LAOrigin;
|
||||
internal const int MaxGameID_9 = (int)GameVersion.VL;
|
||||
internal const int MaxGameID_HOME = MaxGameID_9;
|
||||
|
||||
internal static readonly ushort[] HeldItems_GSC = ItemStorage2.GetAllHeld();
|
||||
internal static readonly ushort[] HeldItems_RS = ItemStorage3RS.GetAllHeld();
|
||||
|
|
|
@ -112,5 +112,9 @@ public static class EncounterServerDate
|
|||
{0502, (new(2023, 03, 31), new(2023, 07, 01))}, // TCG Flying Lechonk
|
||||
{0503, (new(2023, 04, 13), new(2023, 04, 18))}, // Gavin's Palafin (-1 start date tolerance for GMT-10 regions)
|
||||
{0025, (new(2023, 04, 21), new(2023, 07, 01))}, // Pokémon Center Pikachu (Mini & Jumbo)
|
||||
|
||||
{9021, (new(2023, 05, 30), Never)}, // Hidden Ability Sprigatito
|
||||
{9022, (new(2023, 05, 30), Never)}, // Hidden Ability Fuecoco
|
||||
{9023, (new(2023, 05, 30), Never)}, // Hidden Ability Quaxly
|
||||
};
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ public sealed record EncounterSlot8a : EncounterSlot, IAlphaReadOnly, IMasteryIn
|
|||
|
||||
private EncounterMatchRating GetMatchRatingInternal(PKM pk)
|
||||
{
|
||||
if (pk is IAlpha a && a.IsAlpha != IsAlpha)
|
||||
if (!MarkRules.IsMarkValidAlpha(pk, IsAlpha))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
if (FlawlessIVCount is not 0 && pk.FlawlessIVCount < FlawlessIVCount)
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
|
|
|
@ -95,14 +95,20 @@ public sealed record EncounterSlot8GO : EncounterSlotGO, IFixedOTFriendship
|
|||
{
|
||||
s.HeightScalar = PokeSizeUtil.GetRandomScalar();
|
||||
s.WeightScalar = PokeSizeUtil.GetRandomScalar();
|
||||
if (pk is IScaledSize3 s3)
|
||||
s3.Scale = s.HeightScalar = PokeSizeUtil.GetRandomScalar();
|
||||
}
|
||||
|
||||
if (OriginFormat is PogoImportFormat.PA8)
|
||||
if (pk is PA8 pa8)
|
||||
{
|
||||
var pa8 = (PA8)pk;
|
||||
pa8.ResetHeight();
|
||||
pa8.ResetWeight();
|
||||
pa8.Scale = pa8.HeightScalar;
|
||||
}
|
||||
else if (pk is PK9 pk9)
|
||||
{
|
||||
var pi = pk9.PersonalInfo;
|
||||
pk9.TeraTypeOriginal = pk9.TeraTypeOverride = TeraTypeUtil.GetTeraTypeImport(pi.Type1, pi.Type2);
|
||||
pk9.Obedience_Level = (byte)pk9.Met_Level;
|
||||
}
|
||||
|
||||
pk.OT_Friendship = OT_Friendship;
|
||||
|
|
|
@ -53,8 +53,8 @@ public sealed record EncounterFixed9 : EncounterStatic, IGemType
|
|||
|
||||
protected override bool IsMatchLocation(PKM pk)
|
||||
{
|
||||
if (!pk.HasOriginalMetLocation)
|
||||
return true;
|
||||
if (pk is PK8)
|
||||
return LocationsHOME.IsValidMetSV((ushort)pk.Met_Location, pk.Version);
|
||||
var loc = pk.Met_Location;
|
||||
return loc == Location0 || loc == Location1 || loc == Location2 || loc == Location3;
|
||||
}
|
||||
|
|
|
@ -211,6 +211,13 @@ public sealed record EncounterMight9 : EncounterStatic, ITeraRaid9
|
|||
_ => throw new ArgumentOutOfRangeException(nameof(b), b, null),
|
||||
};
|
||||
|
||||
protected override bool IsMatchLocation(PKM pk)
|
||||
{
|
||||
if (pk is PK8)
|
||||
return LocationsHOME.IsValidMetSV((ushort)pk.Met_Location, pk.Version);
|
||||
return base.IsMatchLocation(pk);
|
||||
}
|
||||
|
||||
protected override EncounterMatchRating IsMatchDeferred(PKM pk)
|
||||
{
|
||||
if (Ability != AbilityPermission.Any12H)
|
||||
|
|
|
@ -87,8 +87,8 @@ public sealed record EncounterStatic8a(GameVersion Version) : EncounterStatic(Ve
|
|||
protected override bool IsMatchLocation(PKM pk)
|
||||
{
|
||||
if (pk is PK8)
|
||||
return pk.Met_Location == Locations.HOME_SWLA;
|
||||
if (pk is PB8 { Version: (int)GameVersion.PLA, Met_Location: Locations.HOME_SWLA })
|
||||
return pk.Met_Location == LocationsHOME.SWLA;
|
||||
if (pk is PB8 { Version: (int)GameVersion.PLA, Met_Location: LocationsHOME.SWLA })
|
||||
return true;
|
||||
|
||||
return base.IsMatchLocation(pk);
|
||||
|
@ -115,6 +115,9 @@ public sealed record EncounterStatic8a(GameVersion Version) : EncounterStatic(Ve
|
|||
if (!IsForcedMasteryCorrect(pk))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
|
||||
if (!MarkRules.IsMarkValidAlpha(pk, IsAlpha))
|
||||
return EncounterMatchRating.DeferredErrors;
|
||||
|
||||
if (IsAlpha && pk is PA8 { AlphaMove: 0 })
|
||||
return EncounterMatchRating.Deferred;
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ public sealed record EncounterStatic8b : EncounterStatic, IStaticCorrelation8b
|
|||
protected override bool IsMatchLocation(PKM pk)
|
||||
{
|
||||
if (pk is PK8)
|
||||
return Locations.IsValidMetBDSP((ushort)pk.Met_Location, pk.Version);
|
||||
return LocationsHOME.IsValidMetBDSP((ushort)pk.Met_Location, pk.Version);
|
||||
if (!Roaming)
|
||||
return base.IsMatchLocation(pk);
|
||||
return IsRoamingLocation(pk);
|
||||
|
@ -54,12 +54,7 @@ public sealed record EncounterStatic8b : EncounterStatic, IStaticCorrelation8b
|
|||
return pk.Egg_Location == 0;
|
||||
|
||||
if (pk is PK8)
|
||||
{
|
||||
if (EggLocation > 60000 && pk.Egg_Location == Locations.HOME_SWSHBDSPEgg)
|
||||
return true;
|
||||
// >60000 can be reset to Link Trade (30001), then altered differently.
|
||||
return Locations.IsValidMetBDSP((ushort)pk.Egg_Location, pk.Version) && pk.Egg_Location == pk.Met_Location;
|
||||
}
|
||||
return LocationsHOME.IsLocationSWSHEgg(pk.Version, pk.Met_Location, pk.Egg_Location, (ushort)EggLocation);
|
||||
|
||||
// Hatched
|
||||
return pk.Egg_Location == EggLocation || pk.Egg_Location == Locations.LinkTrade6NPC;
|
||||
|
|
|
@ -19,6 +19,13 @@ public sealed record EncounterStatic9(GameVersion Version) : EncounterStatic(Ver
|
|||
|
||||
public SizeType9 ScaleType => NoScalarsDefined ? SizeType9.RANDOM : SizeType9.VALUE;
|
||||
|
||||
protected override bool IsMatchLocation(PKM pk)
|
||||
{
|
||||
if (pk is PK8)
|
||||
return LocationsHOME.IsValidMetSV((ushort)pk.Met_Location, pk.Version);
|
||||
return base.IsMatchLocation(pk);
|
||||
}
|
||||
|
||||
protected override bool IsMatchPartial(PKM pk)
|
||||
{
|
||||
if (pk is IScaledSize v && !NoScalarsDefined)
|
||||
|
@ -30,9 +37,9 @@ public sealed record EncounterStatic9(GameVersion Version) : EncounterStatic(Ver
|
|||
if (v.WeightScalar != Size)
|
||||
return true;
|
||||
}
|
||||
if (pk is PK9 pk9)
|
||||
if (pk is IScaledSize3 s3)
|
||||
{
|
||||
if (pk9.Scale != Size)
|
||||
if (s3.Scale != Size)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,13 @@ public sealed record EncounterTera9 : EncounterStatic, ITeraRaid9
|
|||
_ => throw new ArgumentOutOfRangeException(nameof(b), b, null),
|
||||
};
|
||||
|
||||
protected override bool IsMatchLocation(PKM pk)
|
||||
{
|
||||
if (pk is PK8)
|
||||
return LocationsHOME.IsValidMetSV((ushort)pk.Met_Location, pk.Version);
|
||||
return base.IsMatchLocation(pk);
|
||||
}
|
||||
|
||||
protected override EncounterMatchRating IsMatchDeferred(PKM pk)
|
||||
{
|
||||
if (Ability != Any12H)
|
||||
|
|
|
@ -139,7 +139,7 @@ public sealed class EncounterGenerator8a : IEncounterGenerator
|
|||
// Encounter Slots
|
||||
if (CanBeWildEncounter(pk))
|
||||
{
|
||||
bool hasOriginalLocation = pk is not (PK8 or PB8 { Met_Location: Locations.HOME_SWLA });
|
||||
bool hasOriginalLocation = pk is not (PK8 or PB8 { Met_Location: LocationsHOME.SWLA });
|
||||
var location = pk.Met_Location;
|
||||
foreach (var area in Encounters8a.SlotsLA)
|
||||
{
|
||||
|
|
|
@ -273,9 +273,9 @@ public sealed class EncounterGenerator8b : IEncounterGenerator
|
|||
|
||||
bool wasEgg = pk.Egg_Location switch
|
||||
{
|
||||
Locations.HOME_SWSHBDSPEgg => true, // Regular hatch location (not link trade)
|
||||
Locations.HOME_SWBD => pk.Met_Location == Locations.HOME_SWBD, // Link Trade transferred over must match Met Location
|
||||
Locations.HOME_SHSP => pk.Met_Location == Locations.HOME_SHSP, // Link Trade transferred over must match Met Location
|
||||
LocationsHOME.SWSHEgg => true, // Regular hatch location (not link trade)
|
||||
LocationsHOME.SWBD => pk.Met_Location == LocationsHOME.SWBD, // Link Trade transferred over must match Met Location
|
||||
LocationsHOME.SHSP => pk.Met_Location == LocationsHOME.SHSP, // Link Trade transferred over must match Met Location
|
||||
_ => false,
|
||||
};
|
||||
if (wasEgg && pk.Met_Level == 1)
|
||||
|
@ -294,7 +294,6 @@ public sealed class EncounterGenerator8b : IEncounterGenerator
|
|||
EncounterMatchRating rating = MaxNotMatch;
|
||||
|
||||
// Trades
|
||||
if (!pk.IsEgg)
|
||||
{
|
||||
foreach (var enc in Encounters8b.TradeGift_BDSP)
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using static PKHeX.Core.EncounterStateUtil;
|
||||
using static PKHeX.Core.EncounterTypeGroup;
|
||||
using static PKHeX.Core.EncounterMatchRating;
|
||||
using static PKHeX.Core.GameVersion;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
|
@ -13,7 +14,12 @@ public sealed class EncounterGenerator9 : IEncounterGenerator
|
|||
public IEnumerable<IEncounterable> GetEncounters(PKM pk, LegalInfo info)
|
||||
{
|
||||
var chain = EncounterOrigin.GetOriginChain(pk);
|
||||
return GetEncounters(pk, chain, info);
|
||||
return (GameVersion)pk.Version switch
|
||||
{
|
||||
SW when pk.Met_Location == LocationsHOME.SWSL => Instance.GetEncountersSWSH(pk, chain, SL),
|
||||
SH when pk.Met_Location == LocationsHOME.SHVL => Instance.GetEncountersSWSH(pk, chain, VL),
|
||||
_ => GetEncounters(pk, chain, info),
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<IEncounterable> GetPossible(PKM pk, EvoCriteria[] chain, GameVersion game, EncounterTypeGroup groups)
|
||||
|
@ -32,7 +38,7 @@ public sealed class EncounterGenerator9 : IEncounterGenerator
|
|||
}
|
||||
if (groups.HasFlag(Static))
|
||||
{
|
||||
var table = game == GameVersion.SL ? Encounters9.StaticSL : Encounters9.StaticVL;
|
||||
var table = game == SL ? Encounters9.StaticSL : Encounters9.StaticVL;
|
||||
foreach (var enc in GetPossibleStatic(chain, table))
|
||||
yield return enc;
|
||||
}
|
||||
|
@ -99,7 +105,7 @@ public sealed class EncounterGenerator9 : IEncounterGenerator
|
|||
{
|
||||
foreach (var enc in table)
|
||||
{
|
||||
if (enc.Version != GameVersion.SV && enc.Version != game)
|
||||
if (enc.Version != SV && enc.Version != game)
|
||||
continue;
|
||||
|
||||
foreach (var evo in chain)
|
||||
|
@ -112,6 +118,138 @@ public sealed class EncounterGenerator9 : IEncounterGenerator
|
|||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IEncounterable> GetEncountersSWSH(PKM pk, EvoCriteria[] chain, GameVersion game)
|
||||
{
|
||||
if (pk.FatefulEncounter)
|
||||
{
|
||||
bool yielded = false;
|
||||
foreach (var mg in EncounterEvent.MGDB_G9)
|
||||
{
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
if (evo.Species != mg.Species)
|
||||
continue;
|
||||
|
||||
if (mg.IsMatchExact(pk, evo))
|
||||
{
|
||||
yield return mg;
|
||||
yielded = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (yielded)
|
||||
yield break;
|
||||
}
|
||||
|
||||
bool wasEgg = pk.Egg_Location switch
|
||||
{
|
||||
LocationsHOME.SWSHEgg => true, // Regular hatch location (not link trade)
|
||||
LocationsHOME.SWSL => pk.Met_Location == LocationsHOME.SWSL, // Link Trade transferred over must match Met Location
|
||||
LocationsHOME.SHVL => pk.Met_Location == LocationsHOME.SHVL, // Link Trade transferred over must match Met Location
|
||||
_ => false,
|
||||
};
|
||||
if (wasEgg && pk.Met_Level == 1)
|
||||
{
|
||||
bool yielded = false;
|
||||
var eggs = GetEggs(pk, chain, game);
|
||||
foreach (var egg in eggs)
|
||||
{
|
||||
yield return egg;
|
||||
yielded = true;
|
||||
}
|
||||
if (yielded)
|
||||
yield break;
|
||||
}
|
||||
|
||||
IEncounterable? cache = null;
|
||||
EncounterMatchRating rating = MaxNotMatch;
|
||||
|
||||
// Trades
|
||||
{
|
||||
foreach (var z in Encounters9.TradeGift_SV)
|
||||
{
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
if (z.Version != SV && z.Version != game)
|
||||
continue;
|
||||
if (evo.Species != z.Species)
|
||||
continue;
|
||||
if (!z.IsMatchExact(pk, evo))
|
||||
break;
|
||||
|
||||
var match = z.GetMatchRating(pk);
|
||||
if (match == Match)
|
||||
{
|
||||
yield return z;
|
||||
}
|
||||
else if (match < rating)
|
||||
{
|
||||
cache = z;
|
||||
rating = match;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cache != null)
|
||||
yield return cache;
|
||||
}
|
||||
|
||||
if (pk is not IRibbonIndex r || !r.HasEncounterMark())
|
||||
{
|
||||
var encStatic = game == SL ? Encounters9.StaticSL : Encounters9.StaticVL;
|
||||
foreach (var z in encStatic)
|
||||
{
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
if (evo.Species != z.Species)
|
||||
continue;
|
||||
if (!z.IsMatchExact(pk, evo))
|
||||
break;
|
||||
|
||||
var match = z.GetMatchRating(pk);
|
||||
if (match == Match)
|
||||
{
|
||||
yield return z;
|
||||
}
|
||||
else if (match < rating)
|
||||
{
|
||||
cache = z;
|
||||
rating = match;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wild encounters are more permissive than static encounters.
|
||||
// Can have encounter marks, can have varied scales/shiny states.
|
||||
if (CanBeWildEncounter(pk))
|
||||
{
|
||||
var areas = Encounters9.Slots;
|
||||
foreach (var area in areas)
|
||||
{
|
||||
var slots = area.GetMatchingSlots(pk, chain);
|
||||
foreach (var slot in slots)
|
||||
{
|
||||
var match = slot.GetMatchRating(pk);
|
||||
if (match == Match)
|
||||
{
|
||||
yield return slot;
|
||||
}
|
||||
else if (match < rating)
|
||||
{
|
||||
cache = slot;
|
||||
rating = match;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cache != null)
|
||||
yield return cache;
|
||||
}
|
||||
|
||||
public IEnumerable<IEncounterable> GetEncounters(PKM pk, EvoCriteria[] chain, LegalInfo info)
|
||||
{
|
||||
if (pk.FatefulEncounter)
|
||||
|
@ -162,7 +300,7 @@ public sealed class EncounterGenerator9 : IEncounterGenerator
|
|||
{
|
||||
foreach (var evo in chain)
|
||||
{
|
||||
if (z.Version != GameVersion.SV && z.Version != game)
|
||||
if (z.Version != SV && z.Version != game)
|
||||
continue;
|
||||
if (evo.Species != z.Species)
|
||||
continue;
|
||||
|
@ -189,7 +327,7 @@ public sealed class EncounterGenerator9 : IEncounterGenerator
|
|||
|
||||
if (pk is not IRibbonIndex r || !r.HasEncounterMark())
|
||||
{
|
||||
var encStatic = game == GameVersion.SL ? Encounters9.StaticSL : Encounters9.StaticVL;
|
||||
var encStatic = game == SL ? Encounters9.StaticSL : Encounters9.StaticVL;
|
||||
foreach (var z in encStatic)
|
||||
{
|
||||
foreach (var evo in chain)
|
||||
|
@ -256,7 +394,7 @@ public sealed class EncounterGenerator9 : IEncounterGenerator
|
|||
if (!devolved.InsideLevelRange(EggLevel))
|
||||
yield break;
|
||||
if (version == 0 && pk.IsEgg)
|
||||
version = GameVersion.SL;
|
||||
version = SL;
|
||||
|
||||
// Ensure most devolved species is the same as the egg species.
|
||||
// No split-breed to consider.
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using static PKHeX.Core.GameVersion;
|
||||
using static PKHeX.Core.Locations;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
|
@ -27,9 +26,11 @@ public sealed class EncounterGenerator8X : IEncounterGenerator
|
|||
GO => EncounterGenerator8GO.Instance.GetEncounters(pk, chain, info),
|
||||
PLA => EncounterGenerator8a.Instance.GetEncounters(pk, chain, info),
|
||||
BD or SP => EncounterGenerator8b.Instance.GetEncounters(pk, chain, info),
|
||||
SW when pk.Met_Location == HOME_SWLA => EncounterGenerator8a.Instance.GetEncounters(pk, chain, info),
|
||||
SW when pk.Met_Location == HOME_SWBD => EncounterGenerator8b.Instance.GetEncountersSWSH(pk, chain, BD),
|
||||
SH when pk.Met_Location == HOME_SHSP => EncounterGenerator8b.Instance.GetEncountersSWSH(pk, chain, SP),
|
||||
SW when pk.Met_Location == LocationsHOME.SWLA => EncounterGenerator8a.Instance.GetEncounters(pk, chain, info),
|
||||
SW when pk.Met_Location == LocationsHOME.SWBD => EncounterGenerator8b.Instance.GetEncountersSWSH(pk, chain, BD),
|
||||
SH when pk.Met_Location == LocationsHOME.SHSP => EncounterGenerator8b.Instance.GetEncountersSWSH(pk, chain, SP),
|
||||
SW when pk.Met_Location == LocationsHOME.SWSL => EncounterGenerator9.Instance.GetEncountersSWSH(pk, chain, SL),
|
||||
SH when pk.Met_Location == LocationsHOME.SHVL => EncounterGenerator9.Instance.GetEncountersSWSH(pk, chain, VL),
|
||||
_ => EncounterGenerator8.Instance.GetEncounters(pk, chain, info),
|
||||
};
|
||||
}
|
||||
|
|
|
@ -230,16 +230,21 @@ public static class EncounterVerifier
|
|||
if (pk.Met_Level != level)
|
||||
return GetInvalid(string.Format(LEggFMetLevel_0, level));
|
||||
|
||||
var met = (ushort)pk.Met_Location;
|
||||
bool valid = pk.BDSP // Transferred from BD/SP, now acting like a SW/SH egg.
|
||||
? Locations.IsValidMetBDSP(met, pk.Version)
|
||||
: EggHatchLocation8.IsValidMet8SWSH(met);
|
||||
|
||||
var valid = IsValidMetForeignEggSWSH(pk, (ushort)pk.Met_Location);
|
||||
if (valid)
|
||||
return GetValid(LEggLocation);
|
||||
return GetInvalid(LEggLocationInvalid);
|
||||
}
|
||||
|
||||
private static bool IsValidMetForeignEggSWSH(PKM pk, ushort met)
|
||||
{
|
||||
if (pk.BDSP)
|
||||
return LocationsHOME.IsValidMetBDSP(met, pk.Version);
|
||||
if (pk.SV)
|
||||
return LocationsHOME.IsValidMetSV(met, pk.Version);
|
||||
return EggHatchLocation8.IsValidMet8SWSH(met);
|
||||
}
|
||||
|
||||
private static CheckResult VerifyEncounterEgg8BDSP(PKM pk)
|
||||
{
|
||||
const byte level = 1;
|
||||
|
|
|
@ -12,13 +12,13 @@ public sealed class EvolutionGroup8 : IEvolutionGroup
|
|||
private const int MaxSpecies = Legal.MaxSpeciesID_8a;
|
||||
private const int Generation = 8;
|
||||
|
||||
public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => null;
|
||||
public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => EvolutionGroup9.Instance;
|
||||
public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc)
|
||||
{
|
||||
if (enc.Generation >= Generation)
|
||||
return null;
|
||||
if ((GameVersion)enc.Version is GP or GE or GG or GO)
|
||||
return EvolutionGroup7b.Instance;
|
||||
if (enc.Generation >= Generation)
|
||||
return null;
|
||||
return EvolutionGroup7.Instance;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ public sealed class EvolutionGroup8 : IEvolutionGroup
|
|||
// Block BD/SP transfers that are impossible
|
||||
BlockBDSP(history, enc);
|
||||
|
||||
if (!pk.IsUntraded && !(ParseSettings.IgnoreTransferIfNoTracker && pk is IHomeTrack { Tracker: 0 }))
|
||||
if (!pk.IsUntraded && !(ParseSettings.IgnoreTransferIfNoTracker && pk is IHomeTrack { HasTracker: false }))
|
||||
{
|
||||
CrossPropagate(history);
|
||||
}
|
||||
|
|
|
@ -7,15 +7,9 @@ public sealed class EvolutionGroup9 : IEvolutionGroup
|
|||
public static readonly EvolutionGroup9 Instance = new();
|
||||
private static readonly EvolutionTree Tree9 = EvolutionTree.Evolves9;
|
||||
private const int MaxSpecies = Legal.MaxSpeciesID_9;
|
||||
private const int Generation = 9;
|
||||
|
||||
public IEvolutionGroup? GetNext(PKM pk, EvolutionOrigin enc) => null;
|
||||
public IEvolutionGroup? GetPrevious(PKM pk, EvolutionOrigin enc)
|
||||
{
|
||||
if (enc.Generation >= Generation)
|
||||
return null;
|
||||
return null;
|
||||
}
|
||||
public IEvolutionGroup GetPrevious(PKM pk, EvolutionOrigin enc) => EvolutionGroup8.Instance;
|
||||
|
||||
public bool Append(PKM pk, EvolutionHistory history, ref ReadOnlySpan<EvoCriteria> chain, EvolutionOrigin enc)
|
||||
{
|
||||
|
|
|
@ -226,7 +226,7 @@ public static class MethodFinder
|
|||
|
||||
private static bool GetLCRNGRoamerMatch(Span<uint> seeds, uint top, uint bot, ReadOnlySpan<uint> IVs, out PIDIV pidiv)
|
||||
{
|
||||
if (IVs is not [_, < 7, 0, 0, 0, 0])
|
||||
if (IVs is not [_, <= 7, 0, 0, 0, 0])
|
||||
return GetNonMatch(out pidiv);
|
||||
|
||||
var iv1 = GetIVChunk(IVs[..3]);
|
||||
|
|
|
@ -208,7 +208,7 @@ public static class Encounter9RNG
|
|||
if (enc.Height == 0)
|
||||
{
|
||||
var value = (int)rand.NextInt(0x81) + (int)rand.NextInt(0x80);
|
||||
if (pk is IScaledSize s && s.HeightScalar != value)
|
||||
if (!IsHeightMatchSV(pk, value))
|
||||
return false;
|
||||
}
|
||||
if (enc.Weight == 0)
|
||||
|
@ -226,6 +226,22 @@ public static class Encounter9RNG
|
|||
return true;
|
||||
}
|
||||
|
||||
public static bool IsHeightMatchSV(PKM pk, int value)
|
||||
{
|
||||
// HOME copies Scale to Height. Untouched by HOME must match the value.
|
||||
// Viewing the save file in HOME will alter it too. Tracker definitely indicates it was viewed.
|
||||
if (pk is not (IScaledSize s2 and IScaledSize3 s3))
|
||||
return true;
|
||||
|
||||
// Viewed in HOME.
|
||||
if (s2.HeightScalar == s3.Scale)
|
||||
return true;
|
||||
if (pk is IHomeTrack { HasTracker: true })
|
||||
return false;
|
||||
|
||||
return s2.HeightScalar == value;
|
||||
}
|
||||
|
||||
private static uint GetAdaptedPID(ref Xoroshiro128Plus rand, PKM pk, in GenerateParam9 enc)
|
||||
{
|
||||
var fakeTID = (uint)rand.NextInt();
|
||||
|
|
|
@ -153,11 +153,21 @@ public static class RaidRNG
|
|||
if (pk is IScaledSize s)
|
||||
{
|
||||
var height = (int)rng.NextInt(0x81) + (int)rng.NextInt(0x80);
|
||||
if (s.HeightScalar != height)
|
||||
return false;
|
||||
var weight = (int)rng.NextInt(0x81) + (int)rng.NextInt(0x80);
|
||||
if (s.WeightScalar != weight)
|
||||
return false;
|
||||
if (height == 0 && weight == 0 && pk is IHomeTrack { HasTracker: true})
|
||||
{
|
||||
// HOME rerolls height/weight if both are 0
|
||||
// This behavior started in 3.0.0, so only flag if the context is 9 or above.
|
||||
if (pk.Context is not (EntityContext.Gen8 or EntityContext.Gen8a or EntityContext.Gen8b))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s.HeightScalar != height)
|
||||
return false;
|
||||
if (s.WeightScalar != weight)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -144,7 +144,7 @@ public sealed partial class MemoryContext8 : MemoryContext
|
|||
42 when arg is not (1 or 12 or 22 or 33 or 35 or 37 or 44 or 47 or 53 or 71 or 72 or 76 or 77) => true,
|
||||
|
||||
// {0} sat with {1} on a bench {2}. {4} that {3}.
|
||||
70 when arg is not (12 or 22 or 28 or 33 or 35 or 37 or 38 or 44 or 53 or 77) => true,
|
||||
70 when arg is not (8 or 12 or 22 or 28 or 33 or 35 or 37 or 38 or 44 or 53 or 77) => true,
|
||||
|
||||
_ => !IsGeneralLocation8(arg),
|
||||
};
|
||||
|
|
|
@ -58,6 +58,8 @@ public static class TrainerInfoExtensions
|
|||
pk.HT_Gender = sav.Gender;
|
||||
pk.HT_Friendship = pk.OT_Friendship;
|
||||
pk.CurrentHandler = 1;
|
||||
if (pk is IHandlerLanguage h)
|
||||
h.HT_Language = (byte)sav.Language;
|
||||
|
||||
if (pk is PK6 pk6 && sav is IRegionOrigin o)
|
||||
{
|
||||
|
|
|
@ -14,12 +14,14 @@ public static class AbilityChangeRules
|
|||
/// <param name="enc">Original Encounter</param>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="abilityFlag">Current ability index value</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if possible to obtain <see cref="abilityFlag"/></returns>
|
||||
public static bool IsAbilityStateValid(this IEncounterTemplate enc, EvolutionHistory evosAll, int abilityFlag) => (enc switch
|
||||
public static bool IsAbilityStateValid(this IEncounterTemplate enc, EvolutionHistory evosAll, int abilityFlag, EntityContext current, EntityContext original) => (enc switch
|
||||
{
|
||||
IFixedAbilityNumber f => f.Ability,
|
||||
_ => Any12,
|
||||
}).IsAbilityStateValid(evosAll, abilityFlag);
|
||||
}).IsAbilityStateValid(evosAll, abilityFlag, current, original);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the current <see cref="abilityFlag"/> value is possible to obtain based on the original <see cref="ability"/> and game visiting.
|
||||
|
@ -27,15 +29,17 @@ public static class AbilityChangeRules
|
|||
/// <param name="ability">Original Ability Permitted</param>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="abilityFlag">Current ability index value</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if possible to obtain <see cref="abilityFlag"/></returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static bool IsAbilityStateValid(this AbilityPermission ability, EvolutionHistory evosAll, int abilityFlag) => ability switch
|
||||
public static bool IsAbilityStateValid(this AbilityPermission ability, EvolutionHistory evosAll, int abilityFlag, EntityContext current, EntityContext original) => ability switch
|
||||
{
|
||||
Any12H => true,
|
||||
Any12 => abilityFlag != 4 || IsAbilityPatchPossible(evosAll),
|
||||
OnlyHidden => abilityFlag == 4 || IsAbilityPatchRevertPossible(evosAll, abilityFlag),
|
||||
OnlyFirst => abilityFlag == 1 || (abilityFlag == 4 && IsAbilityPatchPossible(evosAll)) || (abilityFlag != 4 && IsAbilityCapsulePossible(evosAll)),
|
||||
OnlySecond => abilityFlag == 2 || (abilityFlag == 4 && IsAbilityPatchPossible(evosAll)) || (abilityFlag != 4 && IsAbilityCapsulePossible(evosAll)),
|
||||
Any12 => abilityFlag != 4 || IsAbilityPatchPossible(evosAll, current, original),
|
||||
OnlyHidden => abilityFlag == 4 || IsAbilityPatchRevertPossible(evosAll, abilityFlag, current, original),
|
||||
OnlyFirst => abilityFlag == 1 || (abilityFlag == 4 && IsAbilityPatchPossible(evosAll, current, original)) || (abilityFlag != 4 && IsAbilityCapsulePossible(evosAll, current, original)),
|
||||
OnlySecond => abilityFlag == 2 || (abilityFlag == 4 && IsAbilityPatchPossible(evosAll, current, original)) || (abilityFlag != 4 && IsAbilityCapsulePossible(evosAll, current, original)),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(ability), ability, null),
|
||||
};
|
||||
|
||||
|
@ -44,26 +48,30 @@ public static class AbilityChangeRules
|
|||
/// </summary>
|
||||
/// <param name="enc">Original Encounter</param>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if the ability can be changed</returns>
|
||||
public static bool IsAbilityChangeAvailable(this IEncounterTemplate enc, EvolutionHistory evosAll) => (enc switch
|
||||
public static bool IsAbilityChangeAvailable(this IEncounterTemplate enc, EvolutionHistory evosAll, EntityContext current, EntityContext original) => (enc switch
|
||||
{
|
||||
IFixedAbilityNumber f => f.Ability,
|
||||
_ => Any12,
|
||||
}).IsAbilityChangeAvailable(evosAll);
|
||||
}).IsAbilityChangeAvailable(evosAll, current, original);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the original <see cref="ability"/> value can be changed based on the games visited.
|
||||
/// </summary>
|
||||
/// <param name="ability">Original Ability Permitted</param>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if the ability can be changed</returns>
|
||||
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
||||
public static bool IsAbilityChangeAvailable(this AbilityPermission ability, EvolutionHistory evosAll) => ability switch
|
||||
public static bool IsAbilityChangeAvailable(this AbilityPermission ability, EvolutionHistory evosAll, EntityContext current, EntityContext original) => ability switch
|
||||
{
|
||||
Any12H => true,
|
||||
Any12 => IsAbilityPatchAvailable(evosAll),
|
||||
OnlyHidden => IsAbilityPatchRevertAvailable(evosAll),
|
||||
OnlyFirst or OnlySecond => IsAbilityPatchAvailable(evosAll) || IsAbilityCapsuleAvailable(evosAll),
|
||||
Any12 => IsAbilityPatchAvailable(evosAll, current, original),
|
||||
OnlyHidden => IsAbilityPatchRevertAvailable(evosAll, current, original),
|
||||
OnlyFirst or OnlySecond => IsAbilityPatchAvailable(evosAll, current, original) || IsAbilityCapsuleAvailable(evosAll, current, original),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(ability), ability, null),
|
||||
};
|
||||
|
||||
|
@ -71,11 +79,11 @@ public static class AbilityChangeRules
|
|||
/// Checks if the Ability Capsule (1 <-> 2) item is available in any game visited.
|
||||
/// </summary>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if possible</returns>
|
||||
public static bool IsAbilityCapsuleAvailable(EvolutionHistory evosAll)
|
||||
public static bool IsAbilityCapsuleAvailable(EvolutionHistory evosAll, EntityContext current, EntityContext original)
|
||||
{
|
||||
if (evosAll.HasVisitedGen9)
|
||||
return true;
|
||||
if (evosAll.HasVisitedSWSH)
|
||||
return true;
|
||||
if (evosAll.HasVisitedBDSP)
|
||||
|
@ -84,6 +92,10 @@ public static class AbilityChangeRules
|
|||
return true;
|
||||
if (evosAll.HasVisitedGen6)
|
||||
return true;
|
||||
if (IsAbilityRestoredHOME(current, original))
|
||||
return false;
|
||||
if (evosAll.HasVisitedGen9)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -91,18 +103,22 @@ public static class AbilityChangeRules
|
|||
/// Checks if any of the games visited allow applying an Ability Capsule (1 <-> 2) item.
|
||||
/// </summary>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if possible</returns>
|
||||
public static bool IsAbilityCapsulePossible(EvolutionHistory evosAll)
|
||||
public static bool IsAbilityCapsulePossible(EvolutionHistory evosAll, EntityContext current, EntityContext original)
|
||||
{
|
||||
if (evosAll.HasVisitedGen9 && IsCapsulePossible<PersonalTable9SV, PersonalInfo9SV>(evosAll.Gen9, PersonalTable.SV))
|
||||
if (evosAll.HasVisitedSWSH && IsCapsulePossible<PersonalTable8SWSH, PersonalInfo8SWSH, EvoCriteria>(evosAll.Gen8, PersonalTable.SWSH))
|
||||
return true;
|
||||
if (evosAll.HasVisitedSWSH && IsCapsulePossible<PersonalTable8SWSH, PersonalInfo8SWSH>(evosAll.Gen8, PersonalTable.SWSH))
|
||||
if (evosAll.HasVisitedBDSP && IsCapsulePossible<PersonalTable8BDSP, PersonalInfo8BDSP, EvoCriteria>(evosAll.Gen8b, PersonalTable.BDSP))
|
||||
return true;
|
||||
if (evosAll.HasVisitedBDSP && IsCapsulePossible<PersonalTable8BDSP, PersonalInfo8BDSP>(evosAll.Gen8b, PersonalTable.BDSP))
|
||||
if (evosAll.HasVisitedGen7 && IsCapsulePossible<PersonalTable7, PersonalInfo7, EvoCriteria>(evosAll.Gen7, PersonalTable.USUM))
|
||||
return true;
|
||||
if (evosAll.HasVisitedGen7 && IsCapsulePossible<PersonalTable7, PersonalInfo7>(evosAll.Gen7, PersonalTable.USUM))
|
||||
if (evosAll.HasVisitedGen6 && IsCapsulePossible<PersonalTable6AO, PersonalInfo6AO, EvoCriteria>(evosAll.Gen6, PersonalTable.AO))
|
||||
return true;
|
||||
if (evosAll.HasVisitedGen6 && IsCapsulePossible<PersonalTable6AO, PersonalInfo6AO>(evosAll.Gen6, PersonalTable.AO))
|
||||
if (IsAbilityRestoredHOME(current, original))
|
||||
return false;
|
||||
if (evosAll.HasVisitedGen9 && IsCapsulePossible<PersonalTable9SV, PersonalInfo9SV, EvoCriteria>(evosAll.Gen9, PersonalTable.SV))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -111,13 +127,17 @@ public static class AbilityChangeRules
|
|||
/// Checks if the Ability Patch (1/2-> H) item is available in any game visited.
|
||||
/// </summary>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if possible</returns>
|
||||
public static bool IsAbilityPatchAvailable(EvolutionHistory evosAll)
|
||||
public static bool IsAbilityPatchAvailable(EvolutionHistory evosAll, EntityContext current, EntityContext original)
|
||||
{
|
||||
if (evosAll.HasVisitedGen9)
|
||||
return true;
|
||||
if (evosAll.HasVisitedSWSH || evosAll.HasVisitedBDSP)
|
||||
return true;
|
||||
if (IsAbilityRestoredHOME(current, original))
|
||||
return false;
|
||||
if (evosAll.HasVisitedGen9)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -125,14 +145,18 @@ public static class AbilityChangeRules
|
|||
/// Checks if any of the games visited allow applying an Ability Patch (1/2-> H) item.
|
||||
/// </summary>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if possible</returns>
|
||||
public static bool IsAbilityPatchPossible(EvolutionHistory evosAll)
|
||||
public static bool IsAbilityPatchPossible(EvolutionHistory evosAll, EntityContext current, EntityContext original)
|
||||
{
|
||||
if (evosAll.HasVisitedGen9 && IsPatchPossible<PersonalTable9SV, PersonalInfo9SV>(evosAll.Gen9, PersonalTable.SV))
|
||||
if (evosAll.HasVisitedSWSH && IsPatchPossible<PersonalTable8SWSH, PersonalInfo8SWSH, EvoCriteria>(evosAll.Gen8, PersonalTable.SWSH))
|
||||
return true;
|
||||
if (evosAll.HasVisitedSWSH && IsPatchPossible<PersonalTable8SWSH, PersonalInfo8SWSH>(evosAll.Gen8, PersonalTable.SWSH))
|
||||
if (evosAll.HasVisitedBDSP && IsPatchPossible<PersonalTable8BDSP, PersonalInfo8BDSP, EvoCriteria>(evosAll.Gen8b, PersonalTable.BDSP))
|
||||
return true;
|
||||
if (evosAll.HasVisitedBDSP && IsPatchPossible<PersonalTable8BDSP, PersonalInfo8BDSP>(evosAll.Gen8b, PersonalTable.BDSP))
|
||||
if (IsAbilityRestoredHOME(current, original))
|
||||
return false;
|
||||
if (evosAll.HasVisitedGen9 && IsPatchPossible<PersonalTable9SV, PersonalInfo9SV, EvoCriteria>(evosAll.Gen9, PersonalTable.SV))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -141,30 +165,58 @@ public static class AbilityChangeRules
|
|||
/// Checks if any of the games visited allow reverting an Ability Patch (1/2-> H) item.
|
||||
/// </summary>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if possible</returns>
|
||||
public static bool IsAbilityPatchRevertAvailable(EvolutionHistory evosAll)
|
||||
public static bool IsAbilityPatchRevertAvailable(EvolutionHistory evosAll, EntityContext current, EntityContext original)
|
||||
{
|
||||
if (IsAbilityRestoredHOME(current, original))
|
||||
return false;
|
||||
|
||||
if (evosAll.HasVisitedGen9)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsAbilityRestoredHOME(EntityContext current, EntityContext original)
|
||||
{
|
||||
var originalGen = original.Generation();
|
||||
if (originalGen < 9)
|
||||
{
|
||||
// HOME restores abilities if it existed in the current format prior to transferring to a future game with reversion possible.
|
||||
if (originalGen != 8)
|
||||
original = EntityContext.Gen8;
|
||||
if (current == original)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if any of the games visited allow reverting an Ability Patch (1/2-> H) item.
|
||||
/// </summary>
|
||||
/// <param name="evosAll">Evolution and game visitation</param>
|
||||
/// <param name="abilityIndex">Current ability index value</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <param name="original">Original context</param>
|
||||
/// <returns>True if possible</returns>
|
||||
public static bool IsAbilityPatchRevertPossible(EvolutionHistory evosAll, int abilityIndex)
|
||||
public static bool IsAbilityPatchRevertPossible(EvolutionHistory evosAll, int abilityIndex, EntityContext current, EntityContext original)
|
||||
{
|
||||
if (evosAll.HasVisitedGen9 && IsRevertPossible<PersonalTable9SV, PersonalInfo9SV>(evosAll.Gen9, PersonalTable.SV, abilityIndex))
|
||||
return true;
|
||||
// With HOME 3.0, ability modifications are locked to sets of games -- modifying in SV won't change SWSH.
|
||||
if (current == EntityContext.Gen9)
|
||||
{
|
||||
if (IsAbilityRestoredHOME(current, original))
|
||||
return false;
|
||||
if (evosAll.HasVisitedGen9 && IsRevertPossible<PersonalTable9SV, PersonalInfo9SV, EvoCriteria>(evosAll.Gen9, PersonalTable.SV, abilityIndex))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsCapsulePossible<TTable, TInfo>(EvoCriteria[] evos, TTable table)
|
||||
private static bool IsCapsulePossible<TTable, TInfo, TDex>(ReadOnlySpan<TDex> evos, TTable table)
|
||||
where TTable : IPersonalTable<TInfo>
|
||||
where TInfo : class, IPersonalInfo, IPersonalAbility12
|
||||
where TDex : ISpeciesForm
|
||||
{
|
||||
for (int i = evos.Length - 1; i >= 0; i--)
|
||||
{
|
||||
|
@ -176,9 +228,10 @@ public static class AbilityChangeRules
|
|||
return false;
|
||||
}
|
||||
|
||||
private static bool IsPatchPossible<TTable, TInfo>(EvoCriteria[] evos, TTable table)
|
||||
private static bool IsPatchPossible<TTable, TInfo, TDex>(ReadOnlySpan<TDex> evos, TTable table)
|
||||
where TTable : IPersonalTable<TInfo>
|
||||
where TInfo : class, IPersonalInfo, IPersonalAbility12H
|
||||
where TDex : ISpeciesForm
|
||||
{
|
||||
for (int i = evos.Length - 1; i >= 0; i--)
|
||||
{
|
||||
|
@ -201,9 +254,10 @@ public static class AbilityChangeRules
|
|||
};
|
||||
}
|
||||
|
||||
private static bool IsRevertPossible<TTable, TInfo>(EvoCriteria[] evos, TTable table, int abilityIndex)
|
||||
private static bool IsRevertPossible<TTable, TInfo, TDex>(ReadOnlySpan<TDex> evos, TTable table, int abilityIndex)
|
||||
where TTable : IPersonalTable<TInfo>
|
||||
where TInfo : class, IPersonalInfo, IPersonalAbility12H
|
||||
where TDex : ISpeciesForm
|
||||
{
|
||||
bool revert = false;
|
||||
for (var i = evos.Length - 1; i >= 0; i--)
|
||||
|
|
|
@ -73,12 +73,12 @@ public sealed class AbilityVerifier : Verifier
|
|||
|
||||
if (pk.AbilityNumber == 4)
|
||||
{
|
||||
if (AbilityChangeRules.IsAbilityPatchPossible(data.Info.EvoChainsAllGens))
|
||||
if (AbilityChangeRules.IsAbilityPatchPossible(data.Info.EvoChainsAllGens, pk.Context, enc.Context))
|
||||
return GetValid(LAbilityPatchUsed);
|
||||
}
|
||||
else if (enc.Ability == AbilityPermission.OnlyHidden)
|
||||
{
|
||||
if (AbilityChangeRules.IsAbilityPatchRevertPossible(data.Info.EvoChainsAllGens, pk.AbilityNumber))
|
||||
if (AbilityChangeRules.IsAbilityPatchRevertPossible(data.Info.EvoChainsAllGens, pk.AbilityNumber, pk.Context, enc.Context))
|
||||
return GetValid(LAbilityPatchRevertUsed);
|
||||
}
|
||||
}
|
||||
|
@ -163,7 +163,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
var enc = data.Info.EncounterMatch;
|
||||
if (enc.Generation >= 6)
|
||||
{
|
||||
if (IsAbilityCapsuleModified(pk, encounterAbility, data.Info.EvoChainsAllGens))
|
||||
if (IsAbilityCapsuleModified(pk, encounterAbility, data.Info.EvoChainsAllGens, enc.Context))
|
||||
return GetValid(LAbilityCapsuleUsed);
|
||||
if (pk.AbilityNumber != 1 << encounterAbility.GetSingleValue())
|
||||
return INVALID;
|
||||
|
@ -202,7 +202,7 @@ public sealed class AbilityVerifier : Verifier
|
|||
if (state == AbilityState.CanMismatch || encounterAbility == 0)
|
||||
return CheckMatch(pk, abilities, enc.Generation, AbilityState.MustMatch, enc);
|
||||
|
||||
if (IsAbilityCapsuleModified(pk, encounterAbility, data.Info.EvoChainsAllGens))
|
||||
if (IsAbilityCapsuleModified(pk, encounterAbility, data.Info.EvoChainsAllGens, enc.Context))
|
||||
return GetValid(LAbilityCapsuleUsed);
|
||||
|
||||
return INVALID;
|
||||
|
@ -447,9 +447,9 @@ public sealed class AbilityVerifier : Verifier
|
|||
}
|
||||
|
||||
// Ability Capsule can change between 1/2
|
||||
private static bool IsAbilityCapsuleModified(PKM pk, AbilityPermission encounterAbility, EvolutionHistory evos)
|
||||
private static bool IsAbilityCapsuleModified(PKM pk, AbilityPermission encounterAbility, EvolutionHistory evos, EntityContext original)
|
||||
{
|
||||
if (!AbilityChangeRules.IsAbilityCapsulePossible(evos))
|
||||
if (!AbilityChangeRules.IsAbilityCapsulePossible(evos, pk.Context, original))
|
||||
return false; // Not available.
|
||||
if (pk.AbilityNumber == 4)
|
||||
return false; // Cannot alter to hidden ability.
|
||||
|
|
|
@ -25,7 +25,7 @@ public sealed class HyperTrainingVerifier : Verifier
|
|||
return;
|
||||
}
|
||||
|
||||
var minLevel = t.GetHyperTrainMinLevel(data.Info.EvoChainsAllGens);
|
||||
var minLevel = t.GetHyperTrainMinLevel(data.Info.EvoChainsAllGens, pk.Context);
|
||||
if (pk.CurrentLevel < minLevel)
|
||||
{
|
||||
data.AddLine(GetInvalid(string.Format(LHyperTooLow_0, minLevel)));
|
||||
|
|
|
@ -81,7 +81,7 @@ public sealed class MarkVerifier : Verifier
|
|||
return;
|
||||
|
||||
var affix = (RibbonIndex)affixValue;
|
||||
var max = MarkRules.GetMaxAffixValue(data.Entity.Format);
|
||||
var max = MarkRules.GetMaxAffixValue(data.Entity.Format, m is IHomeTrack { HasTracker: true });
|
||||
if (affix > max)
|
||||
{
|
||||
data.AddLine(GetInvalid(string.Format(LRibbonMarkingAffixedF_0, GetRibbonNameSafe(affix))));
|
||||
|
|
|
@ -28,10 +28,8 @@ public sealed class MemoryVerifier : Verifier
|
|||
|
||||
private static bool ShouldHaveNoMemory(LegalityAnalysis data, PKM pk)
|
||||
{
|
||||
if (pk.BDSP || pk.LA)
|
||||
if (pk.BDSP || pk.LA || pk.SV || pk is PK9)
|
||||
return !data.Info.EvoChainsAllGens.HasVisitedSWSH;
|
||||
if (pk is PK9)
|
||||
return true; // No memories.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ public sealed class MiscVerifier : Verifier
|
|||
break;
|
||||
}
|
||||
|
||||
if (pk is IHomeTrack {Tracker: not 0})
|
||||
if (pk is IHomeTrack { HasTracker: true })
|
||||
data.AddLine(GetInvalid(LTransferTrackerShouldBeZero));
|
||||
}
|
||||
else
|
||||
|
@ -138,35 +138,67 @@ public sealed class MiscVerifier : Verifier
|
|||
private void VerifySVStats(LegalityAnalysis data, PK9 pk9)
|
||||
{
|
||||
VerifyStatNature(data, pk9);
|
||||
VerifyTechRecordSV(data, pk9);
|
||||
|
||||
if (!pk9.IsBattleVersionValid(data.Info.EvoChainsAllGens))
|
||||
data.AddLine(GetInvalid(LStatBattleVersionInvalid));
|
||||
|
||||
var enc = data.EncounterOriginal;
|
||||
if (CheckHeightWeightOdds(enc) && pk9 is { HeightScalar: 0, WeightScalar: 0 } && ParseSettings.ZeroHeightWeight != Severity.Valid)
|
||||
data.AddLine(Get(LStatInvalidHeightWeight, ParseSettings.ZeroHeightWeight, Encounter));
|
||||
|
||||
if (enc is EncounterEgg g && UnreleasedSV.Contains(g.Species | g.Form << 11))
|
||||
data.AddLine(GetInvalid(LTransferBad));
|
||||
|
||||
if (pk9.Tracker != 0 && pk9.HeightScalar != pk9.Scale)
|
||||
data.AddLine(GetInvalid(LStatInvalidHeightWeight));
|
||||
if (!IsObedienceLevelValid(pk9, pk9.Obedience_Level, pk9.Met_Level))
|
||||
data.AddLine(GetInvalid(LTransferObedienceLevel));
|
||||
|
||||
if (pk9.Tracker != 0)
|
||||
data.AddLine(GetInvalid(LTransferTrackerShouldBeZero));
|
||||
|
||||
if (enc is EncounterEgg && !Tera9RNG.IsMatchTeraTypePersonalEgg(enc.Species, enc.Form, (byte)pk9.TeraTypeOriginal))
|
||||
data.AddLine(GetInvalid(LTeraTypeMismatch));
|
||||
if (pk9.IsEgg && pk9.TeraTypeOverride != (MoveType)TeraTypeUtil.OverrideNone)
|
||||
data.AddLine(GetInvalid(LTeraTypeIncorrect));
|
||||
|
||||
if (enc is ITeraRaid9)
|
||||
var enc = data.EncounterOriginal;
|
||||
if (pk9 is { HeightScalar: 0, WeightScalar: 0 })
|
||||
{
|
||||
if (data.EncounterMatch.Context.Generation() < 9 && !data.Info.EvoChainsAllGens.HasVisitedPLA) // <=Gen8 rerolls height/weight, never zero.
|
||||
data.AddLine(Get(LStatInvalidHeightWeight, Severity.Invalid, Encounter));
|
||||
else if (CheckHeightWeightOdds(enc) && ParseSettings.ZeroHeightWeight != Severity.Valid)
|
||||
data.AddLine(Get(LStatInvalidHeightWeight, ParseSettings.ZeroHeightWeight, Encounter));
|
||||
}
|
||||
|
||||
if (enc is EncounterEgg { Context: EntityContext.Gen9 } g)
|
||||
{
|
||||
if (UnreleasedSV.Contains(g.Species | g.Form << 11))
|
||||
data.AddLine(GetInvalid(LTransferBad));
|
||||
if (!Tera9RNG.IsMatchTeraTypePersonalEgg(g.Species, g.Form, (byte)pk9.TeraTypeOriginal))
|
||||
data.AddLine(GetInvalid(LTeraTypeMismatch));
|
||||
}
|
||||
else if (enc is ITeraRaid9)
|
||||
{
|
||||
var seed = Tera9RNG.GetOriginalSeed(pk9);
|
||||
data.Info.PIDIV = new PIDIV(PIDType.Tera9, seed);
|
||||
}
|
||||
else if (enc is not { Context: EntityContext.Gen9 } || pk9 is { GO_HOME: true })
|
||||
{
|
||||
if (pk9.TeraTypeOverride == (MoveType)TeraTypeUtil.OverrideNone)
|
||||
data.AddLine(GetInvalid(LTeraTypeIncorrect));
|
||||
else if (GetTeraImportMatch(data.Info.EvoChainsAllGens.Gen9, pk9.TeraTypeOriginal) == -1)
|
||||
data.AddLine(GetInvalid(LTeraTypeIncorrect));
|
||||
}
|
||||
else if (enc is EncounterStatic9 { StarterBoxLegend: true })
|
||||
{
|
||||
// Ride legends cannot be traded or transferred.
|
||||
if (pk9.CurrentHandler != 0 || pk9.Tracker != 0)
|
||||
data.AddLine(GetInvalid(LTransferBad));
|
||||
}
|
||||
}
|
||||
|
||||
VerifyTechRecordSV(data, pk9);
|
||||
public static int GetTeraImportMatch(ReadOnlySpan<EvoCriteria> evos, MoveType actual)
|
||||
{
|
||||
// Sanitize out Form here for Arceus/Silvally -- rewrite via evotree later.
|
||||
if (evos.Length == 0 || evos[0].Species is (int)Species.Arceus or (int)Species.Silvally)
|
||||
return actual == MoveType.Normal ? 0 : -1;
|
||||
for (int i = evos.Length - 1; i >= 0; i--)
|
||||
{
|
||||
var evo = evos[i];
|
||||
var pi = PersonalTable.SV.GetFormEntry(evo.Species, evo.Form);
|
||||
var expect = TeraTypeUtil.GetTeraTypeImport(pi.Type1, pi.Type2);
|
||||
if (expect == actual)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static bool IsObedienceLevelValid(PKM pk, byte current, int expectObey)
|
||||
|
@ -180,20 +212,6 @@ public sealed class MiscVerifier : Verifier
|
|||
|
||||
private static readonly HashSet<int> UnreleasedSV = new()
|
||||
{
|
||||
(int)Species.Diglett | (1 << 11), // Diglett-1
|
||||
(int)Species.Meowth | (1 << 11), // Meowth-1
|
||||
(int)Species.Growlithe | (1 << 11), // Growlithe-1
|
||||
(int)Species.Slowpoke | (1 << 11), // Slowpoke-1
|
||||
(int)Species.Grimer | (1 << 11), // Grimer-1
|
||||
(int)Species.Voltorb | (1 << 11), // Voltorb-1
|
||||
(int)Species.Tauros, // Tauros-0
|
||||
(int)Species.Qwilfish | (1 << 11), // Qwilfish-1
|
||||
(int)Species.Sneasel | (1 << 11), // Sneasel-1
|
||||
(int)Species.Basculin | (2 << 11), // Basculin-2
|
||||
(int)Species.Fennekin, // Fennekin
|
||||
(int)Species.Carbink, // Carbink
|
||||
(int)Species.Grookey, // Grookey
|
||||
|
||||
// Silly workaround for evolution chain reversal not being iteratively implemented -- block cross-gen evolution cases
|
||||
(int)Species.Raichu | (1 << 11), // Raichu-1
|
||||
(int)Species.Typhlosion | (1 << 11), // Typhlosion-1
|
||||
|
|
|
@ -112,10 +112,30 @@ public static class MarkRules
|
|||
return enc is EncounterSlot8 { CanEncounterViaFishing: true };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a <see cref="MarkAlpha"/> mark is valid.
|
||||
/// </summary>
|
||||
public static bool IsMarkValidAlpha(PKM pk, bool wasAlpha)
|
||||
{
|
||||
if (pk is IAlpha a && a.IsAlpha != wasAlpha)
|
||||
return false;
|
||||
if (pk is not IRibbonSetMark9 m)
|
||||
return true;
|
||||
if (m.RibbonMarkAlpha == wasAlpha)
|
||||
return true;
|
||||
|
||||
// Before HOME 3.0.0, this mark was never set.
|
||||
return pk is PK8 or PB8 or PA8; // Not yet touched HOME 3.0.0
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can have the <see cref="IRibbonSetMark9.RibbonMarkAlpha"/> mark.
|
||||
/// </summary>
|
||||
public static bool IsMarkPresentAlpha(IEncounterTemplate enc) => enc is IAlphaReadOnly { IsAlpha: true};
|
||||
public static bool IsMarkValidAlpha(IEncounterTemplate enc, PKM pk)
|
||||
{
|
||||
var expect = enc is IAlphaReadOnly { IsAlpha: true };
|
||||
return IsMarkValidAlpha(pk, expect);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can have the <see cref="IRibbonSetMark9.RibbonMarkJumbo"/> mark.
|
||||
|
@ -181,9 +201,9 @@ public static class MarkRules
|
|||
/// <summary>
|
||||
/// Gets the maximum obtainable <see cref="RibbonIndex"/> value for the format.
|
||||
/// </summary>
|
||||
public static RibbonIndex GetMaxAffixValue(int entityFormat) => entityFormat switch
|
||||
public static RibbonIndex GetMaxAffixValue(int entityFormat, bool visitedHOME) => entityFormat switch
|
||||
{
|
||||
<= 8 => MarkSlump, // Pioneer and Twinkling Star cannot be selected in SW/SH.
|
||||
<= 8 when !visitedHOME => MarkSlump, // Pioneer and Twinkling Star cannot be selected in SW/SH.
|
||||
_ => MarkTitan, // Max ribbon visible in SV.
|
||||
};
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ public static class RibbonVerifierMark9
|
|||
{
|
||||
public static void Parse(this IRibbonSetMark9 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonMarkAlpha != MarkRules.IsMarkPresentAlpha(args.Encounter))
|
||||
if (!MarkRules.IsMarkValidAlpha(args.Encounter, args.Entity))
|
||||
list.Add(MarkAlpha, !r.RibbonMarkAlpha);
|
||||
if (r.RibbonMarkGourmand && !MarkRules.IsMarkValidGourmand(args.History))
|
||||
list.Add(MarkGourmand);
|
||||
|
|
|
@ -161,10 +161,6 @@ public sealed class TransferVerifier : Verifier
|
|||
|
||||
public void VerifyTransferLegalityG9(LegalityAnalysis data)
|
||||
{
|
||||
var enc = data.EncounterMatch;
|
||||
if (enc.Generation != 9)
|
||||
data.AddLine(GetInvalid(LTransferBad));
|
||||
|
||||
var pk = data.Entity;
|
||||
var pt = PersonalTable.SV;
|
||||
if (!pt.IsPresentInGame(pk.Species, pk.Form))
|
||||
|
@ -178,6 +174,7 @@ public sealed class TransferVerifier : Verifier
|
|||
WC8 { IsHOMEGift: true } => true,
|
||||
WB8 { IsHOMEGift: true } => true,
|
||||
WA8 { IsHOMEGift: true } => true,
|
||||
WC9 { IsHOMEGift: true } => true,
|
||||
_ => enc.Generation < 8,
|
||||
};
|
||||
|
||||
|
@ -188,17 +185,21 @@ public sealed class TransferVerifier : Verifier
|
|||
|
||||
if (pk.LGPE || pk.GO)
|
||||
return; // can have any size value
|
||||
if (s.HeightScalar != 0)
|
||||
data.AddLine(GetInvalid(LTransferBad));
|
||||
if (s.WeightScalar != 0)
|
||||
data.AddLine(GetInvalid(LTransferBad));
|
||||
|
||||
// HOME in 3.0.0 will actively re-roll (0,0) to non-zero values.
|
||||
// Transfer between Gen8 can be done before HOME 3.0.0, so we can allow (0,0) or re-rolled.
|
||||
if (pk.Context is not (EntityContext.Gen8 or EntityContext.Gen8a or EntityContext.Gen8b))
|
||||
{
|
||||
if (s is { HeightScalar: 0, WeightScalar: 0 } && !data.Info.EvoChainsAllGens.HasVisitedPLA)
|
||||
data.AddLine(GetInvalid(LTransferBad));
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifyHOMETracker(LegalityAnalysis data, PKM pk)
|
||||
{
|
||||
// Tracker value is set via Transfer across HOME.
|
||||
// Can't validate the actual values (we aren't the server), so we can only check against zero.
|
||||
if (pk is IHomeTrack {Tracker: 0})
|
||||
if (pk is IHomeTrack { HasTracker: false })
|
||||
{
|
||||
data.AddLine(Get(LTransferTrackerMissing, ParseSettings.Gen8TransferTrackerNotPresent));
|
||||
// To the reader: It seems like the best course of action for setting a tracker is:
|
||||
|
|
|
@ -648,7 +648,7 @@ public sealed class WA8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
|
|||
|
||||
if (OriginGame != 0 && OriginGame != pk.Version)
|
||||
{
|
||||
if (OriginGame is (int)GameVersion.PLA && !(pk.Version is (int)GameVersion.SW && pk.Met_Location == Locations.HOME_SWLA))
|
||||
if (OriginGame is (int)GameVersion.PLA && !(pk.Version is (int)GameVersion.SW && pk.Met_Location == LocationsHOME.SWLA))
|
||||
return false;
|
||||
}
|
||||
if (EncryptionConstant != 0)
|
||||
|
@ -684,7 +684,7 @@ public sealed class WA8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
|
|||
if (!IsMatchEggLocation(pk)) return false;
|
||||
if (pk is PK8)
|
||||
{
|
||||
if (pk.Met_Location != Locations.HOME_SWLA)
|
||||
if (pk.Met_Location != LocationsHOME.SWLA)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -36,7 +36,7 @@ public sealed class WB8 : DataMysteryGift, ILangNick, INature, IRibbonIndex, ICo
|
|||
|
||||
// TODO: public byte RestrictVersion?
|
||||
|
||||
public bool CanBeReceivedByVersion(int v, PKM pk) => v is (int) GameVersion.BD or (int) GameVersion.SP || (pk is PK8 && Locations.IsValidMetBDSP((ushort)pk.Met_Location, pk.Version));
|
||||
public bool CanBeReceivedByVersion(int v, PKM pk) => v is (int) GameVersion.BD or (int) GameVersion.SP || (pk is PK8 && LocationsHOME.IsValidMetBDSP((ushort)pk.Met_Location, pk.Version));
|
||||
|
||||
// General Card Properties
|
||||
|
||||
|
@ -639,9 +639,9 @@ public sealed class WB8 : DataMysteryGift, ILangNick, INature, IRibbonIndex, ICo
|
|||
if (!string.IsNullOrEmpty(OT) && OT != pk.OT_Name) return false;
|
||||
if (OriginGame != 0 && OriginGame != pk.Version)
|
||||
{
|
||||
if (OriginGame is (int)GameVersion.BD && !(pk.Version is (int)GameVersion.SW && pk.Met_Location == Locations.HOME_SWBD))
|
||||
if (OriginGame is (int)GameVersion.BD && !(pk.Version is (int)GameVersion.SW && pk.Met_Location == LocationsHOME.SWBD))
|
||||
return false;
|
||||
if (OriginGame is (int)GameVersion.SP && !(pk.Version is (int)GameVersion.SH && pk.Met_Location == Locations.HOME_SHSP))
|
||||
if (OriginGame is (int)GameVersion.SP && !(pk.Version is (int)GameVersion.SH && pk.Met_Location == LocationsHOME.SHSP))
|
||||
return false;
|
||||
}
|
||||
if (EncryptionConstant != 0)
|
||||
|
@ -678,7 +678,7 @@ public sealed class WB8 : DataMysteryGift, ILangNick, INature, IRibbonIndex, ICo
|
|||
if (!IsMatchEggLocation(pk)) return false;
|
||||
if (pk is PK8)
|
||||
{
|
||||
if (!Locations.IsValidMetBDSP((ushort)pk.Met_Location, pk.Version))
|
||||
if (!LocationsHOME.IsValidMetBDSP((ushort)pk.Met_Location, pk.Version))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -574,7 +574,7 @@ public sealed class WC8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
|
|||
|
||||
if (!tr.IsShiny(pid, 8))
|
||||
return pid;
|
||||
if (IsHOMEGift && IsHOMEShinyPossible())
|
||||
if (IsHOMEGift && !IsHOMEShinyPossible())
|
||||
return ForceAntiShiny(pid);
|
||||
return pid;
|
||||
}
|
||||
|
|
|
@ -31,12 +31,13 @@ public sealed class WC9 : DataMysteryGift, ILangNick, INature, ITeraType, IRibbo
|
|||
|
||||
public byte RestrictVersion { get => Data[0xE]; set => Data[0xE] = value; }
|
||||
|
||||
public bool CanBeReceivedByVersion(int v) => RestrictVersion switch
|
||||
public bool CanBeReceivedByVersion(PKM pk) => RestrictVersion switch
|
||||
{
|
||||
0 when !IsEntity => true, // Whatever, essentially unrestricted for SL/VL receipt. No Entity gifts are 0.
|
||||
1 => v is (int)GameVersion.SL,
|
||||
2 => v is (int)GameVersion.VL,
|
||||
3 => v is (int)GameVersion.SL or (int)GameVersion.VL,
|
||||
1 => pk.Version is (int)GameVersion.SL || pk is PK8 { Met_Location: LocationsHOME.SWSL, Version: (int)GameVersion.SW },
|
||||
2 => pk.Version is (int)GameVersion.VL || pk is PK8 { Met_Location: LocationsHOME.SHVL, Version: (int)GameVersion.SH },
|
||||
3 => pk.Version is (int)GameVersion.SL || pk is PK8 { Met_Location: LocationsHOME.SWSL, Version: (int)GameVersion.SW }
|
||||
|| pk.Version is (int)GameVersion.VL || pk is PK8 { Met_Location: LocationsHOME.SHVL, Version: (int)GameVersion.SH },
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(RestrictVersion), RestrictVersion, null),
|
||||
};
|
||||
|
||||
|
@ -417,6 +418,8 @@ public sealed class WC9 : DataMysteryGift, ILangNick, INature, ITeraType, IRibbo
|
|||
return 0x124 + (index * 0x1C);
|
||||
}
|
||||
|
||||
public bool IsHOMEGift => CardID >= 9000;
|
||||
|
||||
public bool CanHandleOT(int language) => !GetHasOT(language);
|
||||
|
||||
public override GameVersion Version
|
||||
|
@ -492,11 +495,11 @@ public sealed class WC9 : DataMysteryGift, ILangNick, INature, ITeraType, IRibbo
|
|||
// The game doesn't have random tera types.
|
||||
pk.SetMaximumPPCurrent();
|
||||
|
||||
if ((tr.Generation > Generation && OriginGame == 0) || !CanBeReceivedByVersion(pk.Version))
|
||||
if ((tr.Generation > Generation && OriginGame == 0) || !CanBeReceivedByVersion(pk))
|
||||
{
|
||||
// give random valid game
|
||||
do { pk.Version = (int)GameVersion.SL + rnd.Next(2); }
|
||||
while (!CanBeReceivedByVersion(pk.Version));
|
||||
while (!CanBeReceivedByVersion(pk));
|
||||
}
|
||||
|
||||
if (OTGender >= 2)
|
||||
|
@ -711,7 +714,16 @@ public sealed class WC9 : DataMysteryGift, ILangNick, INature, ITeraType, IRibbo
|
|||
{
|
||||
if (!shinyType.IsValid(pk)) return false;
|
||||
if (!IsMatchEggLocation(pk)) return false;
|
||||
if (MetLocation != pk.Met_Location) return false;
|
||||
if (pk is PK8)
|
||||
{
|
||||
if (!LocationsHOME.IsValidMetSV((ushort)pk.Met_Location, pk.Version))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (MetLocation != pk.Met_Location)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (MetLevel != 0 && MetLevel != pk.Met_Level) return false;
|
||||
|
@ -722,7 +734,7 @@ public sealed class WC9 : DataMysteryGift, ILangNick, INature, ITeraType, IRibbo
|
|||
|
||||
if (pk is IScaledSize s)
|
||||
{
|
||||
if (s.HeightScalar != HeightValue)
|
||||
if (!Encounter9RNG.IsHeightMatchSV(pk, HeightValue))
|
||||
return false;
|
||||
if (s.WeightScalar != WeightValue)
|
||||
return false;
|
||||
|
|
|
@ -14,12 +14,13 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
{
|
||||
// Internal Attributes set on creation
|
||||
private readonly Memory<byte> Buffer; // Raw Storage
|
||||
public int SerializedSize => Buffer.Length;
|
||||
private Span<byte> Data => Buffer.Span;
|
||||
|
||||
public GameDataCore(Memory<byte> buffer)
|
||||
{
|
||||
if (buffer.Length != HomeCrypto.SIZE_1CORE)
|
||||
throw new ArgumentException("Invalid Format 1 Core Data!");
|
||||
if (buffer.Length != HomeCrypto.SIZE_CORE)
|
||||
throw new ArgumentException("Invalid Core Data Size!");
|
||||
|
||||
Buffer = buffer;
|
||||
}
|
||||
|
@ -39,200 +40,195 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
public ushort TID16 { get => ReadUInt16LittleEndian(Data[0x0F..]); set => WriteUInt16LittleEndian(Data[0x0F..], value); }
|
||||
public ushort SID16 { get => ReadUInt16LittleEndian(Data[0x11..]); set => WriteUInt16LittleEndian(Data[0x11..], value); }
|
||||
public uint EXP { get => ReadUInt32LittleEndian(Data[0x13..]); set => WriteUInt32LittleEndian(Data[0x13..], value); }
|
||||
public int Ability { get => ReadUInt16LittleEndian(Data[0x17..]); set => WriteUInt16LittleEndian(Data[0x17..], (ushort)value); }
|
||||
public int AbilityNumber { get => Data[0x19] & 7; set => Data[0x19] = (byte)((Data[0x19] & ~7) | (value & 7)); }
|
||||
public bool IsFavorite { get => Data[0x1A] != 0; set => Data[0x1A] = (byte)(value ? 1 : 0); }
|
||||
public int MarkValue { get => ReadUInt16LittleEndian(Data[0x1B..]); set => WriteUInt16LittleEndian(Data[0x1B..], (ushort)value); }
|
||||
public uint PID { get => ReadUInt32LittleEndian(Data[0x1D..]); set => WriteUInt32LittleEndian(Data[0x1D..], value); }
|
||||
public int Nature { get => Data[0x21]; set => Data[0x21] = (byte)value; }
|
||||
public int StatNature { get => Data[0x22]; set => Data[0x22] = (byte)value; }
|
||||
public bool FatefulEncounter { get => Data[0x23] != 0; set => Data[0x23] = (byte)(value ? 1 : 0); }
|
||||
public int Gender { get => Data[0x24]; set => Data[0x24] = (byte)value; }
|
||||
public byte Form { get => Data[0x25]; set => WriteUInt16LittleEndian(Data[0x25..], value); }
|
||||
public int EV_HP { get => Data[0x27]; set => Data[0x27] = (byte)value; }
|
||||
public int EV_ATK { get => Data[0x28]; set => Data[0x28] = (byte)value; }
|
||||
public int EV_DEF { get => Data[0x29]; set => Data[0x29] = (byte)value; }
|
||||
public int EV_SPE { get => Data[0x2A]; set => Data[0x2A] = (byte)value; }
|
||||
public int EV_SPA { get => Data[0x2B]; set => Data[0x2B] = (byte)value; }
|
||||
public int EV_SPD { get => Data[0x2C]; set => Data[0x2C] = (byte)value; }
|
||||
public byte CNT_Cool { get => Data[0x2D]; set => Data[0x2D] = value; }
|
||||
public byte CNT_Beauty { get => Data[0x2E]; set => Data[0x2E] = value; }
|
||||
public byte CNT_Cute { get => Data[0x2F]; set => Data[0x2F] = value; }
|
||||
public byte CNT_Smart { get => Data[0x30]; set => Data[0x30] = value; }
|
||||
public byte CNT_Tough { get => Data[0x31]; set => Data[0x31] = value; }
|
||||
public byte CNT_Sheen { get => Data[0x32]; set => Data[0x32] = value; }
|
||||
private byte PKRS { get => Data[0x33]; set => Data[0x33] = value; }
|
||||
public int PKRS_Days { get => PKRS & 0xF; set => PKRS = (byte)((PKRS & ~0xF) | value); }
|
||||
public int PKRS_Strain { get => PKRS >> 4; set => PKRS = (byte)((PKRS & 0xF) | (value << 4)); }
|
||||
public bool IsFavorite { get => Data[0x17] != 0; set => Data[0x17] = (byte)(value ? 1 : 0); }
|
||||
public int MarkValue { get => ReadUInt16LittleEndian(Data[0x18..]); set => WriteUInt16LittleEndian(Data[0x18..], (ushort)value); }
|
||||
public uint PID { get => ReadUInt32LittleEndian(Data[0x1A..]); set => WriteUInt32LittleEndian(Data[0x1A..], value); }
|
||||
public int Nature { get => Data[0x1E]; set => Data[0x1E] = (byte)value; }
|
||||
public int StatNature { get => Data[0x1F]; set => Data[0x1F] = (byte)value; }
|
||||
public bool FatefulEncounter { get => Data[0x20] != 0; set => Data[0x20] = (byte)(value ? 1 : 0); }
|
||||
public int Gender { get => Data[0x21]; set => Data[0x21] = (byte)value; }
|
||||
public byte Form { get => Data[0x22]; set => WriteUInt16LittleEndian(Data[0x22..], value); }
|
||||
public int EV_HP { get => Data[0x24]; set => Data[0x24] = (byte)value; }
|
||||
public int EV_ATK { get => Data[0x25]; set => Data[0x25] = (byte)value; }
|
||||
public int EV_DEF { get => Data[0x26]; set => Data[0x26] = (byte)value; }
|
||||
public int EV_SPE { get => Data[0x27]; set => Data[0x27] = (byte)value; }
|
||||
public int EV_SPA { get => Data[0x28]; set => Data[0x28] = (byte)value; }
|
||||
public int EV_SPD { get => Data[0x29]; set => Data[0x29] = (byte)value; }
|
||||
public byte CNT_Cool { get => Data[0x2A]; set => Data[0x2A] = value; }
|
||||
public byte CNT_Beauty { get => Data[0x2B]; set => Data[0x2B] = value; }
|
||||
public byte CNT_Cute { get => Data[0x2C]; set => Data[0x2C] = value; }
|
||||
public byte CNT_Smart { get => Data[0x2D]; set => Data[0x2D] = value; }
|
||||
public byte CNT_Tough { get => Data[0x2E]; set => Data[0x2E] = value; }
|
||||
public byte CNT_Sheen { get => Data[0x2F]; set => Data[0x2F] = value; }
|
||||
|
||||
private bool GetFlag(int offset, int bit) => FlagUtil.GetFlag(Data, offset, bit);
|
||||
private void SetFlag(int offset, int bit, bool value) => FlagUtil.SetFlag(Data, offset, bit, value);
|
||||
|
||||
public bool RibbonChampionKalos { get => GetFlag(0x34, 0); set => SetFlag(0x34, 0, value); }
|
||||
public bool RibbonChampionG3 { get => GetFlag(0x34, 1); set => SetFlag(0x34, 1, value); }
|
||||
public bool RibbonChampionSinnoh { get => GetFlag(0x34, 2); set => SetFlag(0x34, 2, value); }
|
||||
public bool RibbonBestFriends { get => GetFlag(0x34, 3); set => SetFlag(0x34, 3, value); }
|
||||
public bool RibbonTraining { get => GetFlag(0x34, 4); set => SetFlag(0x34, 4, value); }
|
||||
public bool RibbonBattlerSkillful { get => GetFlag(0x34, 5); set => SetFlag(0x34, 5, value); }
|
||||
public bool RibbonBattlerExpert { get => GetFlag(0x34, 6); set => SetFlag(0x34, 6, value); }
|
||||
public bool RibbonEffort { get => GetFlag(0x34, 7); set => SetFlag(0x34, 7, value); }
|
||||
public bool RibbonChampionKalos { get => GetFlag(0x30, 0); set => SetFlag(0x30, 0, value); }
|
||||
public bool RibbonChampionG3 { get => GetFlag(0x30, 1); set => SetFlag(0x30, 1, value); }
|
||||
public bool RibbonChampionSinnoh { get => GetFlag(0x30, 2); set => SetFlag(0x30, 2, value); }
|
||||
public bool RibbonBestFriends { get => GetFlag(0x30, 3); set => SetFlag(0x30, 3, value); }
|
||||
public bool RibbonTraining { get => GetFlag(0x30, 4); set => SetFlag(0x30, 4, value); }
|
||||
public bool RibbonBattlerSkillful { get => GetFlag(0x30, 5); set => SetFlag(0x30, 5, value); }
|
||||
public bool RibbonBattlerExpert { get => GetFlag(0x30, 6); set => SetFlag(0x30, 6, value); }
|
||||
public bool RibbonEffort { get => GetFlag(0x30, 7); set => SetFlag(0x30, 7, value); }
|
||||
|
||||
public bool RibbonAlert { get => GetFlag(0x35, 0); set => SetFlag(0x35, 0, value); }
|
||||
public bool RibbonShock { get => GetFlag(0x35, 1); set => SetFlag(0x35, 1, value); }
|
||||
public bool RibbonDowncast { get => GetFlag(0x35, 2); set => SetFlag(0x35, 2, value); }
|
||||
public bool RibbonCareless { get => GetFlag(0x35, 3); set => SetFlag(0x35, 3, value); }
|
||||
public bool RibbonRelax { get => GetFlag(0x35, 4); set => SetFlag(0x35, 4, value); }
|
||||
public bool RibbonSnooze { get => GetFlag(0x35, 5); set => SetFlag(0x35, 5, value); }
|
||||
public bool RibbonSmile { get => GetFlag(0x35, 6); set => SetFlag(0x35, 6, value); }
|
||||
public bool RibbonGorgeous { get => GetFlag(0x35, 7); set => SetFlag(0x35, 7, value); }
|
||||
public bool RibbonAlert { get => GetFlag(0x31, 0); set => SetFlag(0x31, 0, value); }
|
||||
public bool RibbonShock { get => GetFlag(0x31, 1); set => SetFlag(0x31, 1, value); }
|
||||
public bool RibbonDowncast { get => GetFlag(0x31, 2); set => SetFlag(0x31, 2, value); }
|
||||
public bool RibbonCareless { get => GetFlag(0x31, 3); set => SetFlag(0x31, 3, value); }
|
||||
public bool RibbonRelax { get => GetFlag(0x31, 4); set => SetFlag(0x31, 4, value); }
|
||||
public bool RibbonSnooze { get => GetFlag(0x31, 5); set => SetFlag(0x31, 5, value); }
|
||||
public bool RibbonSmile { get => GetFlag(0x31, 6); set => SetFlag(0x31, 6, value); }
|
||||
public bool RibbonGorgeous { get => GetFlag(0x31, 7); set => SetFlag(0x31, 7, value); }
|
||||
|
||||
public bool RibbonRoyal { get => GetFlag(0x36, 0); set => SetFlag(0x36, 0, value); }
|
||||
public bool RibbonGorgeousRoyal { get => GetFlag(0x36, 1); set => SetFlag(0x36, 1, value); }
|
||||
public bool RibbonArtist { get => GetFlag(0x36, 2); set => SetFlag(0x36, 2, value); }
|
||||
public bool RibbonFootprint { get => GetFlag(0x36, 3); set => SetFlag(0x36, 3, value); }
|
||||
public bool RibbonRecord { get => GetFlag(0x36, 4); set => SetFlag(0x36, 4, value); }
|
||||
public bool RibbonLegend { get => GetFlag(0x36, 5); set => SetFlag(0x36, 5, value); }
|
||||
public bool RibbonCountry { get => GetFlag(0x36, 6); set => SetFlag(0x36, 6, value); }
|
||||
public bool RibbonNational { get => GetFlag(0x36, 7); set => SetFlag(0x36, 7, value); }
|
||||
public bool RibbonRoyal { get => GetFlag(0x32, 0); set => SetFlag(0x32, 0, value); }
|
||||
public bool RibbonGorgeousRoyal { get => GetFlag(0x32, 1); set => SetFlag(0x32, 1, value); }
|
||||
public bool RibbonArtist { get => GetFlag(0x32, 2); set => SetFlag(0x32, 2, value); }
|
||||
public bool RibbonFootprint { get => GetFlag(0x32, 3); set => SetFlag(0x32, 3, value); }
|
||||
public bool RibbonRecord { get => GetFlag(0x32, 4); set => SetFlag(0x32, 4, value); }
|
||||
public bool RibbonLegend { get => GetFlag(0x32, 5); set => SetFlag(0x32, 5, value); }
|
||||
public bool RibbonCountry { get => GetFlag(0x32, 6); set => SetFlag(0x32, 6, value); }
|
||||
public bool RibbonNational { get => GetFlag(0x32, 7); set => SetFlag(0x32, 7, value); }
|
||||
|
||||
public bool RibbonEarth { get => GetFlag(0x37, 0); set => SetFlag(0x37, 0, value); }
|
||||
public bool RibbonWorld { get => GetFlag(0x37, 1); set => SetFlag(0x37, 1, value); }
|
||||
public bool RibbonClassic { get => GetFlag(0x37, 2); set => SetFlag(0x37, 2, value); }
|
||||
public bool RibbonPremier { get => GetFlag(0x37, 3); set => SetFlag(0x37, 3, value); }
|
||||
public bool RibbonEvent { get => GetFlag(0x37, 4); set => SetFlag(0x37, 4, value); }
|
||||
public bool RibbonBirthday { get => GetFlag(0x37, 5); set => SetFlag(0x37, 5, value); }
|
||||
public bool RibbonSpecial { get => GetFlag(0x37, 6); set => SetFlag(0x37, 6, value); }
|
||||
public bool RibbonSouvenir { get => GetFlag(0x37, 7); set => SetFlag(0x37, 7, value); }
|
||||
public bool RibbonEarth { get => GetFlag(0x33, 0); set => SetFlag(0x33, 0, value); }
|
||||
public bool RibbonWorld { get => GetFlag(0x33, 1); set => SetFlag(0x33, 1, value); }
|
||||
public bool RibbonClassic { get => GetFlag(0x33, 2); set => SetFlag(0x33, 2, value); }
|
||||
public bool RibbonPremier { get => GetFlag(0x33, 3); set => SetFlag(0x33, 3, value); }
|
||||
public bool RibbonEvent { get => GetFlag(0x33, 4); set => SetFlag(0x33, 4, value); }
|
||||
public bool RibbonBirthday { get => GetFlag(0x33, 5); set => SetFlag(0x33, 5, value); }
|
||||
public bool RibbonSpecial { get => GetFlag(0x33, 6); set => SetFlag(0x33, 6, value); }
|
||||
public bool RibbonSouvenir { get => GetFlag(0x33, 7); set => SetFlag(0x33, 7, value); }
|
||||
|
||||
// ribbon u32
|
||||
public bool RibbonWishing { get => GetFlag(0x38, 0); set => SetFlag(0x38, 0, value); }
|
||||
public bool RibbonChampionBattle { get => GetFlag(0x38, 1); set => SetFlag(0x38, 1, value); }
|
||||
public bool RibbonChampionRegional { get => GetFlag(0x38, 2); set => SetFlag(0x38, 2, value); }
|
||||
public bool RibbonChampionNational { get => GetFlag(0x38, 3); set => SetFlag(0x38, 3, value); }
|
||||
public bool RibbonChampionWorld { get => GetFlag(0x38, 4); set => SetFlag(0x38, 4, value); }
|
||||
public bool HasContestMemoryRibbon { get => GetFlag(0x38, 5); set => SetFlag(0x38, 5, value); }
|
||||
public bool HasBattleMemoryRibbon { get => GetFlag(0x38, 6); set => SetFlag(0x38, 6, value); }
|
||||
public bool RibbonChampionG6Hoenn { get => GetFlag(0x38, 7); set => SetFlag(0x38, 7, value); }
|
||||
public bool RibbonWishing { get => GetFlag(0x34, 0); set => SetFlag(0x34, 0, value); }
|
||||
public bool RibbonChampionBattle { get => GetFlag(0x34, 1); set => SetFlag(0x34, 1, value); }
|
||||
public bool RibbonChampionRegional { get => GetFlag(0x34, 2); set => SetFlag(0x34, 2, value); }
|
||||
public bool RibbonChampionNational { get => GetFlag(0x34, 3); set => SetFlag(0x34, 3, value); }
|
||||
public bool RibbonChampionWorld { get => GetFlag(0x34, 4); set => SetFlag(0x34, 4, value); }
|
||||
public bool HasContestMemoryRibbon { get => GetFlag(0x34, 5); set => SetFlag(0x34, 5, value); }
|
||||
public bool HasBattleMemoryRibbon { get => GetFlag(0x34, 6); set => SetFlag(0x34, 6, value); }
|
||||
public bool RibbonChampionG6Hoenn { get => GetFlag(0x34, 7); set => SetFlag(0x34, 7, value); }
|
||||
|
||||
public bool RibbonContestStar { get => GetFlag(0x39, 0); set => SetFlag(0x39, 0, value); }
|
||||
public bool RibbonMasterCoolness { get => GetFlag(0x39, 1); set => SetFlag(0x39, 1, value); }
|
||||
public bool RibbonMasterBeauty { get => GetFlag(0x39, 2); set => SetFlag(0x39, 2, value); }
|
||||
public bool RibbonMasterCuteness { get => GetFlag(0x39, 3); set => SetFlag(0x39, 3, value); }
|
||||
public bool RibbonMasterCleverness { get => GetFlag(0x39, 4); set => SetFlag(0x39, 4, value); }
|
||||
public bool RibbonMasterToughness { get => GetFlag(0x39, 5); set => SetFlag(0x39, 5, value); }
|
||||
public bool RibbonChampionAlola { get => GetFlag(0x39, 6); set => SetFlag(0x39, 6, value); }
|
||||
public bool RibbonBattleRoyale { get => GetFlag(0x39, 7); set => SetFlag(0x39, 7, value); }
|
||||
public bool RibbonContestStar { get => GetFlag(0x35, 0); set => SetFlag(0x35, 0, value); }
|
||||
public bool RibbonMasterCoolness { get => GetFlag(0x35, 1); set => SetFlag(0x35, 1, value); }
|
||||
public bool RibbonMasterBeauty { get => GetFlag(0x35, 2); set => SetFlag(0x35, 2, value); }
|
||||
public bool RibbonMasterCuteness { get => GetFlag(0x35, 3); set => SetFlag(0x35, 3, value); }
|
||||
public bool RibbonMasterCleverness { get => GetFlag(0x35, 4); set => SetFlag(0x35, 4, value); }
|
||||
public bool RibbonMasterToughness { get => GetFlag(0x35, 5); set => SetFlag(0x35, 5, value); }
|
||||
public bool RibbonChampionAlola { get => GetFlag(0x35, 6); set => SetFlag(0x35, 6, value); }
|
||||
public bool RibbonBattleRoyale { get => GetFlag(0x35, 7); set => SetFlag(0x35, 7, value); }
|
||||
|
||||
public bool RibbonBattleTreeGreat { get => GetFlag(0x3A, 0); set => SetFlag(0x3A, 0, value); }
|
||||
public bool RibbonBattleTreeMaster { get => GetFlag(0x3A, 1); set => SetFlag(0x3A, 1, value); }
|
||||
public bool RibbonChampionGalar { get => GetFlag(0x3A, 2); set => SetFlag(0x3A, 2, value); }
|
||||
public bool RibbonTowerMaster { get => GetFlag(0x3A, 3); set => SetFlag(0x3A, 3, value); }
|
||||
public bool RibbonMasterRank { get => GetFlag(0x3A, 4); set => SetFlag(0x3A, 4, value); }
|
||||
public bool RibbonMarkLunchtime { get => GetFlag(0x3A, 5); set => SetFlag(0x3A, 5, value); }
|
||||
public bool RibbonMarkSleepyTime { get => GetFlag(0x3A, 6); set => SetFlag(0x3A, 6, value); }
|
||||
public bool RibbonMarkDusk { get => GetFlag(0x3A, 7); set => SetFlag(0x3A, 7, value); }
|
||||
public bool RibbonBattleTreeGreat { get => GetFlag(0x36, 0); set => SetFlag(0x36, 0, value); }
|
||||
public bool RibbonBattleTreeMaster { get => GetFlag(0x36, 1); set => SetFlag(0x36, 1, value); }
|
||||
public bool RibbonChampionGalar { get => GetFlag(0x36, 2); set => SetFlag(0x36, 2, value); }
|
||||
public bool RibbonTowerMaster { get => GetFlag(0x36, 3); set => SetFlag(0x36, 3, value); }
|
||||
public bool RibbonMasterRank { get => GetFlag(0x36, 4); set => SetFlag(0x36, 4, value); }
|
||||
public bool RibbonMarkLunchtime { get => GetFlag(0x36, 5); set => SetFlag(0x36, 5, value); }
|
||||
public bool RibbonMarkSleepyTime { get => GetFlag(0x36, 6); set => SetFlag(0x36, 6, value); }
|
||||
public bool RibbonMarkDusk { get => GetFlag(0x36, 7); set => SetFlag(0x36, 7, value); }
|
||||
|
||||
public bool RibbonMarkDawn { get => GetFlag(0x3B, 0); set => SetFlag(0x3B, 0, value); }
|
||||
public bool RibbonMarkCloudy { get => GetFlag(0x3B, 1); set => SetFlag(0x3B, 1, value); }
|
||||
public bool RibbonMarkRainy { get => GetFlag(0x3B, 2); set => SetFlag(0x3B, 2, value); }
|
||||
public bool RibbonMarkStormy { get => GetFlag(0x3B, 3); set => SetFlag(0x3B, 3, value); }
|
||||
public bool RibbonMarkSnowy { get => GetFlag(0x3B, 4); set => SetFlag(0x3B, 4, value); }
|
||||
public bool RibbonMarkBlizzard { get => GetFlag(0x3B, 5); set => SetFlag(0x3B, 5, value); }
|
||||
public bool RibbonMarkDry { get => GetFlag(0x3B, 6); set => SetFlag(0x3B, 6, value); }
|
||||
public bool RibbonMarkSandstorm { get => GetFlag(0x3B, 7); set => SetFlag(0x3B, 7, value); }
|
||||
public bool RibbonMarkDawn { get => GetFlag(0x37, 0); set => SetFlag(0x37, 0, value); }
|
||||
public bool RibbonMarkCloudy { get => GetFlag(0x37, 1); set => SetFlag(0x37, 1, value); }
|
||||
public bool RibbonMarkRainy { get => GetFlag(0x37, 2); set => SetFlag(0x37, 2, value); }
|
||||
public bool RibbonMarkStormy { get => GetFlag(0x37, 3); set => SetFlag(0x37, 3, value); }
|
||||
public bool RibbonMarkSnowy { get => GetFlag(0x37, 4); set => SetFlag(0x37, 4, value); }
|
||||
public bool RibbonMarkBlizzard { get => GetFlag(0x37, 5); set => SetFlag(0x37, 5, value); }
|
||||
public bool RibbonMarkDry { get => GetFlag(0x37, 6); set => SetFlag(0x37, 6, value); }
|
||||
public bool RibbonMarkSandstorm { get => GetFlag(0x37, 7); set => SetFlag(0x37, 7, value); }
|
||||
|
||||
public byte RibbonCountMemoryContest { get => Data[0x3C]; set => HasContestMemoryRibbon = (Data[0x3C] = value) != 0; }
|
||||
public byte RibbonCountMemoryBattle { get => Data[0x3D]; set => HasBattleMemoryRibbon = (Data[0x3D] = value) != 0; }
|
||||
public byte RibbonCountMemoryContest { get => Data[0x38]; set => HasContestMemoryRibbon = (Data[0x38] = value) != 0; }
|
||||
public byte RibbonCountMemoryBattle { get => Data[0x39]; set => HasBattleMemoryRibbon = (Data[0x39] = value) != 0; }
|
||||
// !!! no padding, unlike PKM formats!
|
||||
|
||||
// 0x3E Ribbon 3
|
||||
public bool RibbonMarkMisty { get => GetFlag(0x3E, 0); set => SetFlag(0x3E, 0, value); }
|
||||
public bool RibbonMarkDestiny { get => GetFlag(0x3E, 1); set => SetFlag(0x3E, 1, value); }
|
||||
public bool RibbonMarkFishing { get => GetFlag(0x3E, 2); set => SetFlag(0x3E, 2, value); }
|
||||
public bool RibbonMarkCurry { get => GetFlag(0x3E, 3); set => SetFlag(0x3E, 3, value); }
|
||||
public bool RibbonMarkUncommon { get => GetFlag(0x3E, 4); set => SetFlag(0x3E, 4, value); }
|
||||
public bool RibbonMarkRare { get => GetFlag(0x3E, 5); set => SetFlag(0x3E, 5, value); }
|
||||
public bool RibbonMarkRowdy { get => GetFlag(0x3E, 6); set => SetFlag(0x3E, 6, value); }
|
||||
public bool RibbonMarkAbsentMinded { get => GetFlag(0x3E, 7); set => SetFlag(0x3E, 7, value); }
|
||||
public bool RibbonMarkMisty { get => GetFlag(0x3A, 0); set => SetFlag(0x3A, 0, value); }
|
||||
public bool RibbonMarkDestiny { get => GetFlag(0x3A, 1); set => SetFlag(0x3A, 1, value); }
|
||||
public bool RibbonMarkFishing { get => GetFlag(0x3A, 2); set => SetFlag(0x3A, 2, value); }
|
||||
public bool RibbonMarkCurry { get => GetFlag(0x3A, 3); set => SetFlag(0x3A, 3, value); }
|
||||
public bool RibbonMarkUncommon { get => GetFlag(0x3A, 4); set => SetFlag(0x3A, 4, value); }
|
||||
public bool RibbonMarkRare { get => GetFlag(0x3A, 5); set => SetFlag(0x3A, 5, value); }
|
||||
public bool RibbonMarkRowdy { get => GetFlag(0x3A, 6); set => SetFlag(0x3A, 6, value); }
|
||||
public bool RibbonMarkAbsentMinded { get => GetFlag(0x3A, 7); set => SetFlag(0x3A, 7, value); }
|
||||
|
||||
public bool RibbonMarkJittery { get => GetFlag(0x3F, 0); set => SetFlag(0x3F, 0, value); }
|
||||
public bool RibbonMarkExcited { get => GetFlag(0x3F, 1); set => SetFlag(0x3F, 1, value); }
|
||||
public bool RibbonMarkCharismatic { get => GetFlag(0x3F, 2); set => SetFlag(0x3F, 2, value); }
|
||||
public bool RibbonMarkCalmness { get => GetFlag(0x3F, 3); set => SetFlag(0x3F, 3, value); }
|
||||
public bool RibbonMarkIntense { get => GetFlag(0x3F, 4); set => SetFlag(0x3F, 4, value); }
|
||||
public bool RibbonMarkZonedOut { get => GetFlag(0x3F, 5); set => SetFlag(0x3F, 5, value); }
|
||||
public bool RibbonMarkJoyful { get => GetFlag(0x3F, 6); set => SetFlag(0x3F, 6, value); }
|
||||
public bool RibbonMarkAngry { get => GetFlag(0x3F, 7); set => SetFlag(0x3F, 7, value); }
|
||||
public bool RibbonMarkJittery { get => GetFlag(0x3B, 0); set => SetFlag(0x3B, 0, value); }
|
||||
public bool RibbonMarkExcited { get => GetFlag(0x3B, 1); set => SetFlag(0x3B, 1, value); }
|
||||
public bool RibbonMarkCharismatic { get => GetFlag(0x3B, 2); set => SetFlag(0x3B, 2, value); }
|
||||
public bool RibbonMarkCalmness { get => GetFlag(0x3B, 3); set => SetFlag(0x3B, 3, value); }
|
||||
public bool RibbonMarkIntense { get => GetFlag(0x3B, 4); set => SetFlag(0x3B, 4, value); }
|
||||
public bool RibbonMarkZonedOut { get => GetFlag(0x3B, 5); set => SetFlag(0x3B, 5, value); }
|
||||
public bool RibbonMarkJoyful { get => GetFlag(0x3B, 6); set => SetFlag(0x3B, 6, value); }
|
||||
public bool RibbonMarkAngry { get => GetFlag(0x3B, 7); set => SetFlag(0x3B, 7, value); }
|
||||
|
||||
public bool RibbonMarkSmiley { get => GetFlag(0x40, 0); set => SetFlag(0x40, 0, value); }
|
||||
public bool RibbonMarkTeary { get => GetFlag(0x40, 1); set => SetFlag(0x40, 1, value); }
|
||||
public bool RibbonMarkUpbeat { get => GetFlag(0x40, 2); set => SetFlag(0x40, 2, value); }
|
||||
public bool RibbonMarkPeeved { get => GetFlag(0x40, 3); set => SetFlag(0x40, 3, value); }
|
||||
public bool RibbonMarkIntellectual { get => GetFlag(0x40, 4); set => SetFlag(0x40, 4, value); }
|
||||
public bool RibbonMarkFerocious { get => GetFlag(0x40, 5); set => SetFlag(0x40, 5, value); }
|
||||
public bool RibbonMarkCrafty { get => GetFlag(0x40, 6); set => SetFlag(0x40, 6, value); }
|
||||
public bool RibbonMarkScowling { get => GetFlag(0x40, 7); set => SetFlag(0x40, 7, value); }
|
||||
public bool RibbonMarkSmiley { get => GetFlag(0x3C, 0); set => SetFlag(0x3C, 0, value); }
|
||||
public bool RibbonMarkTeary { get => GetFlag(0x3C, 1); set => SetFlag(0x3C, 1, value); }
|
||||
public bool RibbonMarkUpbeat { get => GetFlag(0x3C, 2); set => SetFlag(0x3C, 2, value); }
|
||||
public bool RibbonMarkPeeved { get => GetFlag(0x3C, 3); set => SetFlag(0x3C, 3, value); }
|
||||
public bool RibbonMarkIntellectual { get => GetFlag(0x3C, 4); set => SetFlag(0x3C, 4, value); }
|
||||
public bool RibbonMarkFerocious { get => GetFlag(0x3C, 5); set => SetFlag(0x3C, 5, value); }
|
||||
public bool RibbonMarkCrafty { get => GetFlag(0x3C, 6); set => SetFlag(0x3C, 6, value); }
|
||||
public bool RibbonMarkScowling { get => GetFlag(0x3C, 7); set => SetFlag(0x3C, 7, value); }
|
||||
|
||||
public bool RibbonMarkKindly { get => GetFlag(0x41, 0); set => SetFlag(0x41, 0, value); }
|
||||
public bool RibbonMarkFlustered { get => GetFlag(0x41, 1); set => SetFlag(0x41, 1, value); }
|
||||
public bool RibbonMarkPumpedUp { get => GetFlag(0x41, 2); set => SetFlag(0x41, 2, value); }
|
||||
public bool RibbonMarkZeroEnergy { get => GetFlag(0x41, 3); set => SetFlag(0x41, 3, value); }
|
||||
public bool RibbonMarkPrideful { get => GetFlag(0x41, 4); set => SetFlag(0x41, 4, value); }
|
||||
public bool RibbonMarkUnsure { get => GetFlag(0x41, 5); set => SetFlag(0x41, 5, value); }
|
||||
public bool RibbonMarkHumble { get => GetFlag(0x41, 6); set => SetFlag(0x41, 6, value); }
|
||||
public bool RibbonMarkThorny { get => GetFlag(0x41, 7); set => SetFlag(0x41, 7, value); }
|
||||
public bool RibbonMarkKindly { get => GetFlag(0x3D, 0); set => SetFlag(0x3D, 0, value); }
|
||||
public bool RibbonMarkFlustered { get => GetFlag(0x3D, 1); set => SetFlag(0x3D, 1, value); }
|
||||
public bool RibbonMarkPumpedUp { get => GetFlag(0x3D, 2); set => SetFlag(0x3D, 2, value); }
|
||||
public bool RibbonMarkZeroEnergy { get => GetFlag(0x3D, 3); set => SetFlag(0x3D, 3, value); }
|
||||
public bool RibbonMarkPrideful { get => GetFlag(0x3D, 4); set => SetFlag(0x3D, 4, value); }
|
||||
public bool RibbonMarkUnsure { get => GetFlag(0x3D, 5); set => SetFlag(0x3D, 5, value); }
|
||||
public bool RibbonMarkHumble { get => GetFlag(0x3D, 6); set => SetFlag(0x3D, 6, value); }
|
||||
public bool RibbonMarkThorny { get => GetFlag(0x3D, 7); set => SetFlag(0x3D, 7, value); }
|
||||
|
||||
public bool RibbonMarkVigor { get => GetFlag(0x42, 0); set => SetFlag(0x42, 0, value); }
|
||||
public bool RibbonMarkSlump { get => GetFlag(0x42, 1); set => SetFlag(0x42, 1, value); }
|
||||
public bool RibbonHisui { get => GetFlag(0x42, 2); set => SetFlag(0x42, 2, value); }
|
||||
public bool RibbonTwinklingStar { get => GetFlag(0x42, 3); set => SetFlag(0x42, 3, value); }
|
||||
public bool RibbonChampionPaldea { get => GetFlag(0x42, 4); set => SetFlag(0x42, 4, value); }
|
||||
public bool RibbonMarkJumbo { get => GetFlag(0x42, 5); set => SetFlag(0x42, 5, value); }
|
||||
public bool RibbonMarkMini { get => GetFlag(0x42, 6); set => SetFlag(0x42, 6, value); }
|
||||
public bool RibbonMarkItemfinder { get => GetFlag(0x42, 7); set => SetFlag(0x42, 7, value); }
|
||||
public bool RibbonMarkVigor { get => GetFlag(0x3E, 0); set => SetFlag(0x3E, 0, value); }
|
||||
public bool RibbonMarkSlump { get => GetFlag(0x3E, 1); set => SetFlag(0x3E, 1, value); }
|
||||
public bool RibbonHisui { get => GetFlag(0x3E, 2); set => SetFlag(0x3E, 2, value); }
|
||||
public bool RibbonTwinklingStar { get => GetFlag(0x3E, 3); set => SetFlag(0x3E, 3, value); }
|
||||
public bool RibbonChampionPaldea { get => GetFlag(0x3E, 4); set => SetFlag(0x3E, 4, value); }
|
||||
public bool RibbonMarkJumbo { get => GetFlag(0x3E, 5); set => SetFlag(0x3E, 5, value); }
|
||||
public bool RibbonMarkMini { get => GetFlag(0x3E, 6); set => SetFlag(0x3E, 6, value); }
|
||||
public bool RibbonMarkItemfinder { get => GetFlag(0x3E, 7); set => SetFlag(0x3E, 7, value); }
|
||||
|
||||
public bool RibbonMarkPartner { get => GetFlag(0x43, 0); set => SetFlag(0x43, 0, value); }
|
||||
public bool RibbonMarkGourmand { get => GetFlag(0x43, 1); set => SetFlag(0x43, 1, value); }
|
||||
public bool RibbonOnceInALifetime { get => GetFlag(0x43, 2); set => SetFlag(0x43, 2, value); }
|
||||
public bool RibbonMarkAlpha { get => GetFlag(0x43, 3); set => SetFlag(0x43, 3, value); }
|
||||
public bool RibbonMarkMightiest { get => GetFlag(0x43, 4); set => SetFlag(0x43, 4, value); }
|
||||
public bool RibbonMarkTitan { get => GetFlag(0x43, 5); set => SetFlag(0x43, 5, value); }
|
||||
public bool RIB45_6 { get => GetFlag(0x43, 6); set => SetFlag(0x43, 6, value); }
|
||||
public bool RIB45_7 { get => GetFlag(0x43, 7); set => SetFlag(0x43, 7, value); }
|
||||
public bool RibbonMarkPartner { get => GetFlag(0x3F, 0); set => SetFlag(0x3F, 0, value); }
|
||||
public bool RibbonMarkGourmand { get => GetFlag(0x3F, 1); set => SetFlag(0x3F, 1, value); }
|
||||
public bool RibbonOnceInALifetime { get => GetFlag(0x3F, 2); set => SetFlag(0x3F, 2, value); }
|
||||
public bool RibbonMarkAlpha { get => GetFlag(0x3F, 3); set => SetFlag(0x3F, 3, value); }
|
||||
public bool RibbonMarkMightiest { get => GetFlag(0x3F, 4); set => SetFlag(0x3F, 4, value); }
|
||||
public bool RibbonMarkTitan { get => GetFlag(0x3F, 5); set => SetFlag(0x3F, 5, value); }
|
||||
public bool RIB45_6 { get => GetFlag(0x3F, 6); set => SetFlag(0x3F, 6, value); }
|
||||
public bool RIB45_7 { get => GetFlag(0x3F, 7); set => SetFlag(0x3F, 7, value); }
|
||||
|
||||
public bool RIB46_0 { get => GetFlag(0x44, 0); set => SetFlag(0x44, 0, value); }
|
||||
public bool RIB46_1 { get => GetFlag(0x44, 1); set => SetFlag(0x44, 1, value); }
|
||||
public bool RIB46_2 { get => GetFlag(0x44, 2); set => SetFlag(0x44, 2, value); }
|
||||
public bool RIB46_3 { get => GetFlag(0x44, 3); set => SetFlag(0x44, 3, value); }
|
||||
public bool RIB46_4 { get => GetFlag(0x44, 4); set => SetFlag(0x44, 4, value); }
|
||||
public bool RIB46_5 { get => GetFlag(0x44, 5); set => SetFlag(0x44, 5, value); }
|
||||
public bool RIB46_6 { get => GetFlag(0x44, 6); set => SetFlag(0x44, 6, value); }
|
||||
public bool RIB46_7 { get => GetFlag(0x44, 7); set => SetFlag(0x44, 7, value); }
|
||||
public bool RIB46_0 { get => GetFlag(0x40, 0); set => SetFlag(0x40, 0, value); }
|
||||
public bool RIB46_1 { get => GetFlag(0x40, 1); set => SetFlag(0x40, 1, value); }
|
||||
public bool RIB46_2 { get => GetFlag(0x40, 2); set => SetFlag(0x40, 2, value); }
|
||||
public bool RIB46_3 { get => GetFlag(0x40, 3); set => SetFlag(0x40, 3, value); }
|
||||
public bool RIB46_4 { get => GetFlag(0x40, 4); set => SetFlag(0x40, 4, value); }
|
||||
public bool RIB46_5 { get => GetFlag(0x40, 5); set => SetFlag(0x40, 5, value); }
|
||||
public bool RIB46_6 { get => GetFlag(0x40, 6); set => SetFlag(0x40, 6, value); }
|
||||
public bool RIB46_7 { get => GetFlag(0x40, 7); set => SetFlag(0x40, 7, value); }
|
||||
|
||||
public bool RIB47_0 { get => GetFlag(0x45, 0); set => SetFlag(0x45, 0, value); }
|
||||
public bool RIB47_1 { get => GetFlag(0x45, 1); set => SetFlag(0x45, 1, value); }
|
||||
public bool RIB47_2 { get => GetFlag(0x45, 2); set => SetFlag(0x45, 2, value); }
|
||||
public bool RIB47_3 { get => GetFlag(0x45, 3); set => SetFlag(0x45, 3, value); }
|
||||
public bool RIB47_4 { get => GetFlag(0x45, 4); set => SetFlag(0x45, 4, value); }
|
||||
public bool RIB47_5 { get => GetFlag(0x45, 5); set => SetFlag(0x45, 5, value); }
|
||||
public bool RIB47_6 { get => GetFlag(0x45, 6); set => SetFlag(0x45, 6, value); }
|
||||
public bool RIB47_7 { get => GetFlag(0x45, 7); set => SetFlag(0x45, 7, value); }
|
||||
public bool RIB47_0 { get => GetFlag(0x41, 0); set => SetFlag(0x41, 0, value); }
|
||||
public bool RIB47_1 { get => GetFlag(0x41, 1); set => SetFlag(0x41, 1, value); }
|
||||
public bool RIB47_2 { get => GetFlag(0x41, 2); set => SetFlag(0x41, 2, value); }
|
||||
public bool RIB47_3 { get => GetFlag(0x41, 3); set => SetFlag(0x41, 3, value); }
|
||||
public bool RIB47_4 { get => GetFlag(0x41, 4); set => SetFlag(0x41, 4, value); }
|
||||
public bool RIB47_5 { get => GetFlag(0x41, 5); set => SetFlag(0x41, 5, value); }
|
||||
public bool RIB47_6 { get => GetFlag(0x41, 6); set => SetFlag(0x41, 6, value); }
|
||||
public bool RIB47_7 { get => GetFlag(0x41, 7); set => SetFlag(0x41, 7, value); }
|
||||
|
||||
public int RibbonCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x34..]) & 0b00000000_00011111__11111111_11111111__11111111_11111111__11111111_11111111)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x3E..]) & 0b00000000_00000000__00000100_00011100__00000000_00000000__00000000_00000000);
|
||||
public int MarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x34..]) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x3E..]) & 0b00000000_00000000__00111011_11100011__11111111_11111111__11111111_11111111);
|
||||
public int RibbonMarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x34..]) & 0b11111111_11111111__11111111_11111111__11111111_11111111__11111111_11111111)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x3E..]) & 0b00000000_00000000__00111111_11111111__11111111_11111111__11111111_11111111);
|
||||
public int RibbonCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x30..]) & 0b00000000_00011111__11111111_11111111__11111111_11111111__11111111_11111111)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x3A..]) & 0b00000000_00000000__00000100_00011100__00000000_00000000__00000000_00000000);
|
||||
public int MarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x30..]) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x3A..]) & 0b00000000_00000000__00111011_11100011__11111111_11111111__11111111_11111111);
|
||||
public int RibbonMarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x30..]) & 0b11111111_11111111__11111111_11111111__11111111_11111111__11111111_11111111)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x3A..]) & 0b00000000_00000000__00111111_11111111__11111111_11111111__11111111_11111111);
|
||||
|
||||
public bool HasMarkEncounter8 => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x34..]) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x3E..]) & 0b00000000_00000000__00000000_00000011__11111111_11111111__11111111_11111111) != 0;
|
||||
public bool HasMarkEncounter9 => (Data[0x43] & 0b00111000) != 0;
|
||||
public bool HasMarkEncounter8 => BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x30..]) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data[0x3A..]) & 0b00000000_00000000__00000000_00000011__11111111_11111111__11111111_11111111) != 0;
|
||||
public bool HasMarkEncounter9 => (Data[0x3F] & 0b00111000) != 0;
|
||||
|
||||
public byte HeightScalar { get => Data[0x46]; set => Data[0x46] = value; }
|
||||
public byte WeightScalar { get => Data[0x47]; set => Data[0x47] = value; }
|
||||
public byte HeightScalar { get => Data[0x42]; set => Data[0x42] = value; }
|
||||
public byte WeightScalar { get => Data[0x43]; set => Data[0x43] = value; }
|
||||
|
||||
public Span<byte> Nickname_Trash => Data.Slice(0x48, 26);
|
||||
public Span<byte> Nickname_Trash => Data.Slice(0x44, 26);
|
||||
|
||||
public string Nickname
|
||||
{
|
||||
|
@ -240,59 +236,59 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
set => StringConverter8.SetString(Nickname_Trash, value, 12, StringConverterOption.None);
|
||||
}
|
||||
|
||||
public int Stat_HPCurrent { get => ReadUInt16LittleEndian(Data[0x62..]); set => WriteUInt16LittleEndian(Data[0x62..], (ushort)value); }
|
||||
public int IV_HP { get => Data[0x64]; set => Data[0x64] = (byte)value; }
|
||||
public int IV_ATK { get => Data[0x65]; set => Data[0x65] = (byte)value; }
|
||||
public int IV_DEF { get => Data[0x66]; set => Data[0x66] = (byte)value; }
|
||||
public int IV_SPE { get => Data[0x67]; set => Data[0x67] = (byte)value; }
|
||||
public int IV_SPA { get => Data[0x68]; set => Data[0x68] = (byte)value; }
|
||||
public int IV_SPD { get => Data[0x69]; set => Data[0x69] = (byte)value; }
|
||||
public bool IsEgg { get => Data[0x6A] != 0; set => Data[0x6A] = (byte)(value ? 1 : 0); }
|
||||
public bool IsNicknamed { get => Data[0x6B] != 0; set => Data[0x6B] = (byte)(value ? 1 : 0); }
|
||||
public int Status_Condition { get => ReadInt32LittleEndian(Data[0x6C..]); set => WriteInt32LittleEndian(Data[0x6C..], value); }
|
||||
public Span<byte> HT_Trash => Data.Slice(0x70, 26);
|
||||
public int Stat_HPCurrent { get => ReadUInt16LittleEndian(Data[0x5E..]); set => WriteUInt16LittleEndian(Data[0x5E..], (ushort)value); }
|
||||
public int IV_HP { get => Data[0x60]; set => Data[0x60] = (byte)value; }
|
||||
public int IV_ATK { get => Data[0x61]; set => Data[0x61] = (byte)value; }
|
||||
public int IV_DEF { get => Data[0x62]; set => Data[0x62] = (byte)value; }
|
||||
public int IV_SPE { get => Data[0x63]; set => Data[0x63] = (byte)value; }
|
||||
public int IV_SPA { get => Data[0x64]; set => Data[0x64] = (byte)value; }
|
||||
public int IV_SPD { get => Data[0x65]; set => Data[0x65] = (byte)value; }
|
||||
public bool IsEgg { get => Data[0x66] != 0; set => Data[0x66] = (byte)(value ? 1 : 0); }
|
||||
public bool IsNicknamed { get => Data[0x67] != 0; set => Data[0x67] = (byte)(value ? 1 : 0); }
|
||||
public int Status_Condition { get => ReadInt32LittleEndian(Data[0x68..]); set => WriteInt32LittleEndian(Data[0x68..], value); }
|
||||
public Span<byte> HT_Trash => Data.Slice(0x6C, 26);
|
||||
public string HT_Name
|
||||
{
|
||||
get => StringConverter8.GetString(HT_Trash);
|
||||
set => StringConverter8.SetString(HT_Trash, value, 12, StringConverterOption.None);
|
||||
}
|
||||
public int HT_Gender { get => Data[0x8A]; set => Data[0x8A] = (byte)value; }
|
||||
public byte HT_Language { get => Data[0x8B]; set => Data[0x8B] = value; }
|
||||
public int CurrentHandler { get => Data[0x8C]; set => Data[0x8C] = (byte)value; }
|
||||
public int HT_TrainerID { get => ReadUInt16LittleEndian(Data[0x8D..]); set => WriteUInt16LittleEndian(Data[0x8D..], (ushort)value); } // unused?
|
||||
public int HT_Friendship { get => Data[0x8F]; set => Data[0x8F] = (byte)value; }
|
||||
public byte HT_Intensity { get => Data[0x90]; set => Data[0x90] = value; }
|
||||
public byte HT_Memory { get => Data[0x91]; set => Data[0x91] = value; }
|
||||
public byte HT_Feeling { get => Data[0x92]; set => Data[0x92] = value; }
|
||||
public ushort HT_TextVar { get => ReadUInt16LittleEndian(Data[0x93..]); set => WriteUInt16LittleEndian(Data[0x93..], value); }
|
||||
public int Version { get => Data[0x95]; set => Data[0x95] = (byte)value; }
|
||||
public byte BattleVersion { get => Data[0x96]; set => Data[0x96] = value; }
|
||||
public int Language { get => Data[0x97]; set => Data[0x97] = (byte)value; }
|
||||
public uint FormArgument { get => ReadUInt32LittleEndian(Data[0x98..]); set => WriteUInt32LittleEndian(Data[0x98..], value); }
|
||||
public int HT_Gender { get => Data[0x86]; set => Data[0x86] = (byte)value; }
|
||||
public byte HT_Language { get => Data[0x87]; set => Data[0x87] = value; }
|
||||
public int CurrentHandler { get => Data[0x88]; set => Data[0x88] = (byte)value; }
|
||||
public int HT_TrainerID { get => ReadUInt16LittleEndian(Data[0x89..]); set => WriteUInt16LittleEndian(Data[0x89..], (ushort)value); } // unused?
|
||||
public int HT_Friendship { get => Data[0x8B]; set => Data[0x8B] = (byte)value; }
|
||||
public byte HT_Intensity { get => Data[0x8C]; set => Data[0x8C] = value; }
|
||||
public byte HT_Memory { get => Data[0x8D]; set => Data[0x8D] = value; }
|
||||
public byte HT_Feeling { get => Data[0x8E]; set => Data[0x8E] = value; }
|
||||
public ushort HT_TextVar { get => ReadUInt16LittleEndian(Data[0x8F..]); set => WriteUInt16LittleEndian(Data[0x8F..], value); }
|
||||
public int Version { get => Data[0x91]; set => Data[0x91] = (byte)value; }
|
||||
public byte BattleVersion { get => Data[0x92]; set => Data[0x92] = value; }
|
||||
public int Language { get => Data[0x93]; set => Data[0x93] = (byte)value; }
|
||||
public uint FormArgument { get => ReadUInt32LittleEndian(Data[0x94..]); set => WriteUInt32LittleEndian(Data[0x94..], value); }
|
||||
public byte FormArgumentRemain { get => (byte)FormArgument; set => FormArgument = (FormArgument & ~0xFFu) | value; }
|
||||
public byte FormArgumentElapsed { get => (byte)(FormArgument >> 8); set => FormArgument = (FormArgument & ~0xFF00u) | (uint)(value << 8); }
|
||||
public byte FormArgumentMaximum { get => (byte)(FormArgument >> 16); set => FormArgument = (FormArgument & ~0xFF0000u) | (uint)(value << 16); }
|
||||
public sbyte AffixedRibbon { get => (sbyte)Data[0x9C]; set => Data[0x9C] = (byte)value; } // selected ribbon
|
||||
public Span<byte> OT_Trash => Data.Slice(0x9D, 26);
|
||||
public sbyte AffixedRibbon { get => (sbyte)Data[0x98]; set => Data[0x98] = (byte)value; } // selected ribbon
|
||||
public Span<byte> OT_Trash => Data.Slice(0x99, 26);
|
||||
public string OT_Name
|
||||
{
|
||||
get => StringConverter8.GetString(OT_Trash);
|
||||
set => StringConverter8.SetString(OT_Trash, value, 12, StringConverterOption.None);
|
||||
}
|
||||
public int OT_Friendship { get => Data[0xB7]; set => Data[0xB7] = (byte)value; }
|
||||
public byte OT_Intensity { get => Data[0xB8]; set => Data[0xB8] = value; }
|
||||
public byte OT_Memory { get => Data[0xB9]; set => Data[0xB9] = value; }
|
||||
public ushort OT_TextVar { get => ReadUInt16LittleEndian(Data[0xBA..]); set => WriteUInt16LittleEndian(Data[0xBA..], value); }
|
||||
public byte OT_Feeling { get => Data[0xBC]; set => Data[0xBC] = value; }
|
||||
public int Egg_Year { get => Data[0xBD]; set => Data[0xBD] = (byte)value; }
|
||||
public int Egg_Month { get => Data[0xBE]; set => Data[0xBE] = (byte)value; }
|
||||
public int Egg_Day { get => Data[0xBF]; set => Data[0xBF] = (byte)value; }
|
||||
public int Met_Year { get => Data[0xC0]; set => Data[0xC0] = (byte)value; }
|
||||
public int Met_Month { get => Data[0xC1]; set => Data[0xC1] = (byte)value; }
|
||||
public int Met_Day { get => Data[0xC2]; set => Data[0xC2] = (byte)value; }
|
||||
public int Met_Level { get => Data[0xC3]; set => Data[0xC3] = (byte)value; }
|
||||
public int OT_Gender { get => Data[0xC4]; set => Data[0xC4] = (byte)value; }
|
||||
public byte HyperTrainFlags { get => Data[0xC5]; set => Data[0xC5] = value; }
|
||||
public int OT_Friendship { get => Data[0xB3]; set => Data[0xB3] = (byte)value; }
|
||||
public byte OT_Intensity { get => Data[0xB4]; set => Data[0xB4] = value; }
|
||||
public byte OT_Memory { get => Data[0xB5]; set => Data[0xB5] = value; }
|
||||
public ushort OT_TextVar { get => ReadUInt16LittleEndian(Data[0xB6..]); set => WriteUInt16LittleEndian(Data[0xB6..], value); }
|
||||
public byte OT_Feeling { get => Data[0xB8]; set => Data[0xB8] = value; }
|
||||
public int Egg_Year { get => Data[0xB9]; set => Data[0xB9] = (byte)value; }
|
||||
public int Egg_Month { get => Data[0xBA]; set => Data[0xBA] = (byte)value; }
|
||||
public int Egg_Day { get => Data[0xBB]; set => Data[0xBB] = (byte)value; }
|
||||
public int Met_Year { get => Data[0xBC]; set => Data[0xBC] = (byte)value; }
|
||||
public int Met_Month { get => Data[0xBD]; set => Data[0xBD] = (byte)value; }
|
||||
public int Met_Day { get => Data[0xBE]; set => Data[0xBE] = (byte)value; }
|
||||
public int Met_Level { get => Data[0xBF]; set => Data[0xBF] = (byte)value; }
|
||||
public int OT_Gender { get => Data[0xC0]; set => Data[0xC0] = (byte)value; }
|
||||
public byte HyperTrainFlags { get => Data[0xC1]; set => Data[0xC1] = value; }
|
||||
public bool HT_HP { get => ((HyperTrainFlags >> 0) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 0)) | ((value ? 1 : 0) << 0)); }
|
||||
public bool HT_ATK { get => ((HyperTrainFlags >> 1) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 1)) | ((value ? 1 : 0) << 1)); }
|
||||
public bool HT_DEF { get => ((HyperTrainFlags >> 2) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 2)) | ((value ? 1 : 0) << 2)); }
|
||||
|
@ -300,7 +296,7 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
public bool HT_SPD { get => ((HyperTrainFlags >> 4) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 4)) | ((value ? 1 : 0) << 4)); }
|
||||
public bool HT_SPE { get => ((HyperTrainFlags >> 5) & 1) == 1; set => HyperTrainFlags = (byte)((HyperTrainFlags & ~(1 << 5)) | ((value ? 1 : 0) << 5)); }
|
||||
|
||||
public int HeldItem { get => ReadUInt16LittleEndian(Data[0xC6..]); set => WriteUInt16LittleEndian(Data[0xC6..], (ushort)value); }
|
||||
public int HeldItem { get => ReadUInt16LittleEndian(Data[0xC2..]); set => WriteUInt16LittleEndian(Data[0xC2..], (ushort)value); }
|
||||
|
||||
public int MarkingCount => 6;
|
||||
|
||||
|
@ -321,6 +317,63 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
MarkValue = (MarkValue & ~(0b11 << shift)) | ((value & 3) << shift);
|
||||
}
|
||||
|
||||
public void CopyFrom(PKM pk)
|
||||
{
|
||||
EncryptionConstant = pk.EncryptionConstant;
|
||||
PID = pk.PID;
|
||||
Species = pk.Species;
|
||||
Form = pk.Form;
|
||||
Gender = pk.Gender;
|
||||
TID16 = pk.TID16;
|
||||
SID16 = pk.SID16;
|
||||
EXP = pk.EXP;
|
||||
MarkValue = pk.MarkValue;
|
||||
Nature = pk.Nature;
|
||||
StatNature = pk.StatNature;
|
||||
FatefulEncounter = pk.FatefulEncounter;
|
||||
// HeldItem = pk.HeldItem;
|
||||
IV_HP = pk.IV_HP;
|
||||
IV_ATK = pk.IV_ATK;
|
||||
IV_DEF = pk.IV_DEF;
|
||||
IV_SPE = pk.IV_SPE;
|
||||
IV_SPA = pk.IV_SPA;
|
||||
IV_SPD = pk.IV_SPD;
|
||||
IsEgg = pk.IsEgg;
|
||||
IsNicknamed = pk.IsNicknamed;
|
||||
EV_HP = pk.EV_HP;
|
||||
EV_ATK = pk.EV_ATK;
|
||||
EV_DEF = pk.EV_DEF;
|
||||
EV_SPE = pk.EV_SPE;
|
||||
EV_SPA = pk.EV_SPA;
|
||||
EV_SPD = pk.EV_SPD;
|
||||
|
||||
HT_Gender = pk.HT_Gender;
|
||||
CurrentHandler = pk.CurrentHandler;
|
||||
// pk.HT_TrainerID
|
||||
HT_Friendship = pk.HT_Friendship;
|
||||
|
||||
Version = pk.Version;
|
||||
Language = pk.Language;
|
||||
|
||||
OT_Friendship = pk.OT_Friendship;
|
||||
Egg_Year = pk.Egg_Year;
|
||||
Egg_Month = pk.Egg_Month;
|
||||
Egg_Day = pk.Egg_Day;
|
||||
Met_Year = pk.Met_Year;
|
||||
Met_Month = pk.Met_Month;
|
||||
Met_Day = pk.Met_Day;
|
||||
Met_Level = pk.Met_Level;
|
||||
OT_Gender = pk.OT_Gender;
|
||||
|
||||
CopyConditionalInterfaceFrom(pk);
|
||||
|
||||
pk.OT_Trash.CopyTo(OT_Trash);
|
||||
pk.Nickname_Trash.CopyTo(Nickname_Trash);
|
||||
pk.HT_Trash.CopyTo(HT_Trash);
|
||||
|
||||
CopyConditionalRibbonMarkFrom(pk);
|
||||
}
|
||||
|
||||
public void CopyTo(PKM pk)
|
||||
{
|
||||
pk.EncryptionConstant = EncryptionConstant;
|
||||
|
@ -331,8 +384,6 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
pk.TID16 = TID16;
|
||||
pk.SID16 = SID16;
|
||||
pk.EXP = EXP;
|
||||
pk.Ability = Ability;
|
||||
pk.AbilityNumber = AbilityNumber;
|
||||
pk.MarkValue = MarkValue;
|
||||
pk.Nature = Nature;
|
||||
pk.StatNature = StatNature;
|
||||
|
@ -352,8 +403,6 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
pk.EV_SPE = EV_SPE;
|
||||
pk.EV_SPA = EV_SPA;
|
||||
pk.EV_SPD = EV_SPD;
|
||||
pk.PKRS_Strain = PKRS_Strain;
|
||||
pk.PKRS_Days = PKRS_Days;
|
||||
|
||||
pk.HT_Gender = HT_Gender;
|
||||
pk.CurrentHandler = CurrentHandler;
|
||||
|
@ -373,16 +422,16 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
pk.Met_Level = Met_Level;
|
||||
pk.OT_Gender = OT_Gender;
|
||||
|
||||
CopyConditionalInterface(pk);
|
||||
CopyConditionalInterfaceTo(pk);
|
||||
|
||||
OT_Trash.CopyTo(pk.OT_Trash);
|
||||
Nickname_Trash.CopyTo(pk.Nickname_Trash);
|
||||
HT_Trash.CopyTo(pk.HT_Trash);
|
||||
|
||||
CopyConditionalRibbonMark(pk);
|
||||
CopyConditionalRibbonMarkTo(pk);
|
||||
}
|
||||
|
||||
private void CopyConditionalInterface(PKM pk)
|
||||
private void CopyConditionalInterfaceTo(PKM pk)
|
||||
{
|
||||
if (pk is IScaledSize ss)
|
||||
{
|
||||
|
@ -411,8 +460,8 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
this.CopyContestStatsTo(cm);
|
||||
if (pk is IRibbonSetAffixed affix)
|
||||
affix.AffixedRibbon = AffixedRibbon;
|
||||
if (pk is IHyperTrain ht)
|
||||
ht.HyperTrainFlags = HyperTrainFlags;
|
||||
if (pk is IHyperTrain hy)
|
||||
hy.HyperTrainFlags = HyperTrainFlags;
|
||||
if (pk is IFormArgument fa)
|
||||
fa.FormArgument = FormArgument;
|
||||
if (pk is IBattleVersion bv)
|
||||
|
@ -423,29 +472,74 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
|
|||
home.Tracker = Tracker;
|
||||
}
|
||||
|
||||
private void CopyConditionalRibbonMark(PKM pk)
|
||||
private void CopyConditionalInterfaceFrom(PKM pk)
|
||||
{
|
||||
if (pk is IRibbonSetEvent3 e3)
|
||||
this.CopyRibbonSetEvent3(e3);
|
||||
if (pk is IRibbonSetEvent4 e4)
|
||||
this.CopyRibbonSetEvent4(e4);
|
||||
if (pk is IRibbonSetCommon3 c3)
|
||||
this.CopyRibbonSetCommon3(c3);
|
||||
if (pk is IRibbonSetCommon4 c4)
|
||||
this.CopyRibbonSetCommon4(c4);
|
||||
if (pk is IRibbonSetCommon6 c6)
|
||||
this.CopyRibbonSetCommon6(c6);
|
||||
if (pk is IRibbonSetMemory6 m6)
|
||||
this.CopyRibbonSetMemory6(m6);
|
||||
if (pk is IRibbonSetCommon7 c7)
|
||||
this.CopyRibbonSetCommon7(c7);
|
||||
if (pk is IRibbonSetCommon8 c8)
|
||||
this.CopyRibbonSetCommon8(c8);
|
||||
if (pk is IRibbonSetMark8 m8)
|
||||
this.CopyRibbonSetMark8(m8);
|
||||
if (pk is IRibbonSetCommon9 c9)
|
||||
this.CopyRibbonSetCommon9(c9);
|
||||
if (pk is IRibbonSetMark9 m9)
|
||||
this.CopyRibbonSetMark9(m9);
|
||||
if (pk is IScaledSize ss)
|
||||
{
|
||||
HeightScalar = ss.HeightScalar;
|
||||
WeightScalar = ss.WeightScalar;
|
||||
}
|
||||
|
||||
if (pk is IMemoryOT ot)
|
||||
{
|
||||
OT_Intensity = ot.OT_Intensity;
|
||||
OT_Memory = ot.OT_Memory;
|
||||
OT_TextVar = ot.OT_TextVar;
|
||||
OT_Feeling = ot.OT_Feeling;
|
||||
}
|
||||
if (pk is IMemoryHT ht)
|
||||
{
|
||||
HT_Intensity = ht.HT_Intensity;
|
||||
HT_Memory = ht.HT_Memory;
|
||||
HT_Feeling = ht.HT_Feeling;
|
||||
HT_TextVar = ht.HT_TextVar;
|
||||
}
|
||||
if (pk is IHandlerLanguage hl)
|
||||
HT_Language = hl.HT_Language;
|
||||
|
||||
if (pk is IContestStats cm)
|
||||
cm.CopyContestStatsTo(this);
|
||||
if (pk is IRibbonSetAffixed affix)
|
||||
AffixedRibbon = affix.AffixedRibbon;
|
||||
if (pk is IHyperTrain hy)
|
||||
HyperTrainFlags = hy.HyperTrainFlags;
|
||||
if (pk is IFormArgument fa)
|
||||
FormArgument = fa.FormArgument;
|
||||
if (pk is IBattleVersion bv)
|
||||
BattleVersion = bv.BattleVersion;
|
||||
if (pk is IFavorite fav)
|
||||
IsFavorite = fav.IsFavorite;
|
||||
if (pk is IHomeTrack home)
|
||||
Tracker = home.Tracker;
|
||||
}
|
||||
|
||||
private void CopyConditionalRibbonMarkTo(PKM pk)
|
||||
{
|
||||
if (pk is IRibbonSetEvent3 e3) e3.CopyRibbonSetEvent3 (this);
|
||||
if (pk is IRibbonSetEvent4 e4) e4.CopyRibbonSetEvent4 (this);
|
||||
if (pk is IRibbonSetCommon3 c3) c3.CopyRibbonSetCommon3(this);
|
||||
if (pk is IRibbonSetCommon4 c4) c4.CopyRibbonSetCommon4(this);
|
||||
if (pk is IRibbonSetCommon6 c6) c6.CopyRibbonSetCommon6(this);
|
||||
if (pk is IRibbonSetMemory6 m6) m6.CopyRibbonSetMemory6(this);
|
||||
if (pk is IRibbonSetCommon7 c7) c7.CopyRibbonSetCommon7(this);
|
||||
if (pk is IRibbonSetCommon8 c8) c8.CopyRibbonSetCommon8(this);
|
||||
if (pk is IRibbonSetMark8 m8) m8.CopyRibbonSetMark8 (this);
|
||||
if (pk is IRibbonSetCommon9 c9) c9.CopyRibbonSetCommon9(this);
|
||||
if (pk is IRibbonSetMark9 m9) m9.CopyRibbonSetMark9 (this);
|
||||
}
|
||||
|
||||
private void CopyConditionalRibbonMarkFrom(PKM pk)
|
||||
{
|
||||
if (pk is IRibbonSetEvent3 e3) this.CopyRibbonSetEvent3 (e3);
|
||||
if (pk is IRibbonSetEvent4 e4) this.CopyRibbonSetEvent4 (e4);
|
||||
if (pk is IRibbonSetCommon3 c3) this.CopyRibbonSetCommon3(c3);
|
||||
if (pk is IRibbonSetCommon4 c4) this.CopyRibbonSetCommon4(c4);
|
||||
if (pk is IRibbonSetCommon6 c6) this.CopyRibbonSetCommon6(c6);
|
||||
if (pk is IRibbonSetMemory6 m6) this.CopyRibbonSetMemory6(m6);
|
||||
if (pk is IRibbonSetCommon7 c7) this.CopyRibbonSetCommon7(c7);
|
||||
if (pk is IRibbonSetCommon8 c8) this.CopyRibbonSetCommon8(c8);
|
||||
if (pk is IRibbonSetMark8 m8) this.CopyRibbonSetMark8 (m8);
|
||||
if (pk is IRibbonSetCommon9 c9) this.CopyRibbonSetCommon9(c9);
|
||||
if (pk is IRibbonSetMark9 m9) this.CopyRibbonSetMark9 (m9);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// Side game data for <see cref="PA8"/> data transferred into HOME.
|
||||
/// </summary>
|
||||
public sealed class GameDataPA8 : HomeOptional1, IGameDataSide, IScaledSizeAbsolute
|
||||
public class GameDataPA8 : HomeOptional1, IGameDataSide<PA8>, IScaledSizeAbsolute, IScaledSize3
|
||||
{
|
||||
private const HomeGameDataFormat ExpectFormat = HomeGameDataFormat.PA8;
|
||||
private const int SIZE = HomeCrypto.SIZE_1GAME_PA8;
|
||||
private const int SIZE = HomeCrypto.SIZE_2GAME_PA8;
|
||||
protected override HomeGameDataFormat Format => ExpectFormat;
|
||||
|
||||
public GameDataPA8() : base(SIZE) { }
|
||||
|
@ -22,7 +22,7 @@ public sealed class GameDataPA8 : HomeOptional1, IGameDataSide, IScaledSizeAbsol
|
|||
public bool IsAlpha { get => Data[0x00] != 0; set => Data[0x00] = (byte)(value ? 1 : 0); }
|
||||
public bool IsNoble { get => Data[0x01] != 0; set => Data[0x01] = (byte)(value ? 1 : 0); }
|
||||
public ushort AlphaMove { get => ReadUInt16LittleEndian(Data[0x02..]); set => WriteUInt16LittleEndian(Data[0x02..], value); }
|
||||
public byte HeightScalarCopy { get => Data[0x04]; set => Data[0x04] = value; }
|
||||
public byte Scale { get => Data[0x04]; set => Data[0x04] = value; }
|
||||
|
||||
public ushort Move1 { get => ReadUInt16LittleEndian(Data[0x05..]); set => WriteUInt16LittleEndian(Data[0x05..], value); }
|
||||
public ushort Move2 { get => ReadUInt16LittleEndian(Data[0x07..]); set => WriteUInt16LittleEndian(Data[0x07..], value); }
|
||||
|
@ -61,6 +61,10 @@ public sealed class GameDataPA8 : HomeOptional1, IGameDataSide, IScaledSizeAbsol
|
|||
public int Egg_Location { get => ReadUInt16LittleEndian(Data[0x38..]); set => WriteUInt16LittleEndian(Data[0x38..], (ushort)value); }
|
||||
public int Met_Location { get => ReadUInt16LittleEndian(Data[0x3A..]); set => WriteUInt16LittleEndian(Data[0x3A..], (ushort)value); }
|
||||
|
||||
public byte PKRS { get => Data[0x3C]; set => Data[0x3C] = value; }
|
||||
public ushort Ability { get => ReadUInt16LittleEndian(Data[0x3D..]); set => WriteUInt16LittleEndian(Data[0x3D..], value); }
|
||||
public byte AbilityNumber { get => Data[0x3F]; set => Data[0x3F] = value; }
|
||||
|
||||
// Not stored.
|
||||
public PersonalInfo GetPersonalInfo(ushort species, byte form) => PersonalTable.LA.GetFormEntry(species, form);
|
||||
public int Move1_PPUps { get => 0; set { } }
|
||||
|
@ -72,13 +76,13 @@ public sealed class GameDataPA8 : HomeOptional1, IGameDataSide, IScaledSizeAbsol
|
|||
|
||||
#region Conversion
|
||||
|
||||
public void CopyTo(PA8 pk)
|
||||
public void CopyTo(PA8 pk, PKH pkh)
|
||||
{
|
||||
((IGameDataSide)this).CopyTo(pk);
|
||||
this.CopyTo(pk);
|
||||
pk.IsAlpha = IsAlpha;
|
||||
pk.IsNoble = IsNoble;
|
||||
pk.AlphaMove = AlphaMove;
|
||||
pk.Scale = HeightScalarCopy;
|
||||
pk.Scale = Scale;
|
||||
pk.HeightAbsolute = pk.CalcHeightAbsolute; // Ignore the stored value, be nice and recalculate for the user.
|
||||
pk.WeightAbsolute = pk.CalcWeightAbsolute; // Ignore the stored value, be nice and recalculate for the user.
|
||||
pk.GV_HP = GV_HP;
|
||||
|
@ -89,15 +93,45 @@ public sealed class GameDataPA8 : HomeOptional1, IGameDataSide, IScaledSizeAbsol
|
|||
pk.GV_SPD = GV_SPD;
|
||||
PurchasedRecord.CopyTo(pk.PurchasedRecord);
|
||||
MasteredRecord.CopyTo(pk.MasteredRecord);
|
||||
pk.PKRS = PKRS;
|
||||
pk.AbilityNumber = AbilityNumber;
|
||||
pk.Ability = Ability;
|
||||
}
|
||||
|
||||
public PKM ConvertToPKM(PKH pkh) => ConvertToPA8(pkh);
|
||||
public void CopyFrom(PA8 pk, PKH pkh)
|
||||
{
|
||||
this.CopyFrom(pk);
|
||||
IsAlpha = pk.IsAlpha;
|
||||
IsNoble = pk.IsNoble;
|
||||
AlphaMove = pk.AlphaMove;
|
||||
pkh.HeightScalar = Scale = pk.Scale; // Overwrite Height
|
||||
HeightAbsolute = pk.CalcHeightAbsolute; // Ignore the stored value, be nice and recalculate for the user.
|
||||
WeightAbsolute = pk.CalcHeightAbsolute; // Ignore the stored value, be nice and recalculate for the user.
|
||||
GV_HP = pk.GV_HP;
|
||||
GV_ATK = pk.GV_ATK;
|
||||
GV_DEF = pk.GV_DEF;
|
||||
GV_SPE = pk.GV_SPE;
|
||||
GV_SPA = pk.GV_SPA;
|
||||
GV_SPD = pk.GV_SPD;
|
||||
pk.PurchasedRecord.CopyTo(PurchasedRecord);
|
||||
pk.MasteredRecord.CopyTo(MasteredRecord);
|
||||
PKRS = pk.PKRS;
|
||||
AbilityNumber = (byte)pk.AbilityNumber;
|
||||
Ability = (ushort)pk.Ability;
|
||||
|
||||
public PA8 ConvertToPA8(PKH pkh)
|
||||
// Special: Add the Mark
|
||||
if (pk.IsAlpha)
|
||||
pkh.Core.RibbonMarkAlpha = true;
|
||||
}
|
||||
|
||||
public PA8 ConvertToPKM(PKH pkh)
|
||||
{
|
||||
var pk = new PA8();
|
||||
pkh.CopyTo(pk);
|
||||
CopyTo(pk);
|
||||
CopyTo(pk, pkh);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
pk.RefreshChecksum();
|
||||
return pk;
|
||||
}
|
||||
|
||||
|
@ -106,14 +140,66 @@ public sealed class GameDataPA8 : HomeOptional1, IGameDataSide, IScaledSizeAbsol
|
|||
/// <summary> Reconstructive logic to best apply suggested values. </summary>
|
||||
public static GameDataPA8? TryCreate(PKH pkh)
|
||||
{
|
||||
if (pkh.DataPB7 is { } x)
|
||||
return GameDataPB7.Create<GameDataPA8>(x);
|
||||
if (pkh.DataPB8 is { } b)
|
||||
return GameDataPB8.Create<GameDataPA8>(b);
|
||||
if (pkh.DataPK9 is { } g9)
|
||||
return GameDataPK9.Create<GameDataPA8>(g9);
|
||||
if (pkh.DataPK8 is { } c)
|
||||
return new GameDataPA8 { Ball = c.Met_Location == Locations.HOME_SWLA ? (int)Core.Ball.LAPoke : c.Ball, Met_Location = c.Met_Location, Egg_Location = c.Egg_Location };
|
||||
return null;
|
||||
if (!PersonalTable.LA.IsPresentInGame(pkh.Species, pkh.Form))
|
||||
return null;
|
||||
|
||||
var result = CreateInternal(pkh);
|
||||
if (result == null)
|
||||
return null;
|
||||
|
||||
result.PopulateFromCore(pkh);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static GameDataPA8? CreateInternal(PKH pkh)
|
||||
{
|
||||
var side = GetNearestNeighbor(pkh);
|
||||
if (side == null)
|
||||
return null;
|
||||
|
||||
var result = new GameDataPA8();
|
||||
result.InitializeFrom(side, pkh);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IGameDataSide? GetNearestNeighbor(PKH pkh) => pkh.DataPK9 as IGameDataSide
|
||||
?? pkh.DataPB8 as IGameDataSide
|
||||
?? pkh.DataPK8 as IGameDataSide
|
||||
?? pkh.DataPB7;
|
||||
|
||||
public void InitializeFrom(IGameDataSide side, PKH pkh)
|
||||
{
|
||||
Ball = GetLegendBall(side.Ball);
|
||||
Met_Location = side.Met_Location == Locations.Default8bNone ? 0 : side.Met_Location;
|
||||
Egg_Location = side.Egg_Location == Locations.Default8bNone ? 0 : side.Egg_Location;
|
||||
|
||||
if (side is IScaledSize3 s3)
|
||||
Scale = s3.Scale;
|
||||
else
|
||||
Scale = pkh.HeightScalar;
|
||||
if (side is IPokerusStatus p)
|
||||
PKRS = p.PKRS;
|
||||
if (side is IGameDataSplitAbility a)
|
||||
AbilityNumber = a.AbilityNumber;
|
||||
else
|
||||
AbilityNumber = 1;
|
||||
|
||||
PopulateFromCore(pkh);
|
||||
this.ResetMoves(pkh.Species, pkh.Form, pkh.CurrentLevel, LearnSource8LA.Instance, EntityContext.Gen8a);
|
||||
}
|
||||
|
||||
private static int GetLegendBall(int ball)
|
||||
{
|
||||
if (((Ball)ball).IsLegendBall())
|
||||
return ball;
|
||||
return (byte)Core.Ball.LAPoke;
|
||||
}
|
||||
|
||||
private void PopulateFromCore(PKH pkh)
|
||||
{
|
||||
var pi = PersonalTable.LA.GetFormEntry(pkh.Species, pkh.Form);
|
||||
HeightAbsolute = PA8.GetHeightAbsolute(pi, pkh.HeightScalar);
|
||||
WeightAbsolute = PA8.GetWeightAbsolute(pi, pkh.HeightScalar, pkh.WeightScalar);
|
||||
Ability = (ushort)pi.GetAbilityAtIndex(AbilityNumber >> 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// Side game data for <see cref="PB7"/> data transferred into HOME.
|
||||
/// </summary>
|
||||
public sealed class GameDataPB7 : HomeOptional1, IGameDataSide, IScaledSizeAbsolute, IMemoryOT
|
||||
public sealed class GameDataPB7 : HomeOptional1, IGameDataSide<PB7>, IScaledSizeAbsolute, IMemoryOT
|
||||
{
|
||||
private const HomeGameDataFormat ExpectFormat = HomeGameDataFormat.PB7;
|
||||
private const int SIZE = HomeCrypto.SIZE_1GAME_PB7;
|
||||
private const int SIZE = HomeCrypto.SIZE_2GAME_PB7;
|
||||
protected override HomeGameDataFormat Format => ExpectFormat;
|
||||
|
||||
public GameDataPB7() : base(SIZE) { }
|
||||
|
@ -63,15 +63,19 @@ public sealed class GameDataPB7 : HomeOptional1, IGameDataSide, IScaledSizeAbsol
|
|||
public int Egg_Location { get => ReadUInt16LittleEndian(Data[0x37..]); set => WriteUInt16LittleEndian(Data[0x37..], (ushort)value); }
|
||||
public int Met_Location { get => ReadUInt16LittleEndian(Data[0x39..]); set => WriteUInt16LittleEndian(Data[0x39..], (ushort)value); }
|
||||
|
||||
public byte PKRS { get => Data[0x3B]; set => Data[0x3B] = value; }
|
||||
public ushort Ability { get => ReadUInt16LittleEndian(Data[0x3C..]); set => WriteUInt16LittleEndian(Data[0x3C..], value); }
|
||||
public byte AbilityNumber { get => Data[0x3E]; set => Data[0x3E] = value; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Conversion
|
||||
|
||||
public PersonalInfo GetPersonalInfo(ushort species, byte form) => PersonalTable.GG.GetFormEntry(species, form);
|
||||
|
||||
public void CopyTo(PB7 pk)
|
||||
public void CopyTo(PB7 pk, PKH pkh)
|
||||
{
|
||||
((IGameDataSide)this).CopyTo(pk);
|
||||
this.CopyTo(pk);
|
||||
pk.AV_HP = AV_HP;
|
||||
pk.AV_ATK = AV_ATK;
|
||||
pk.AV_DEF = AV_DEF;
|
||||
|
@ -94,15 +98,52 @@ public sealed class GameDataPB7 : HomeOptional1, IGameDataSide, IScaledSizeAbsol
|
|||
// pk.OT_Feeling
|
||||
pk.Enjoyment = Enjoyment;
|
||||
// pk.GeoPadding = GeoPadding;
|
||||
pk.AbilityNumber = AbilityNumber;
|
||||
pk.Ability = Ability;
|
||||
}
|
||||
|
||||
public PKM ConvertToPKM(PKH pkh) => ConvertToPB7(pkh);
|
||||
public void CopyFrom(PB7 pk, PKH pkh)
|
||||
{
|
||||
this.CopyFrom(pk);
|
||||
AV_HP = pk.AV_HP;
|
||||
AV_ATK = pk.AV_ATK;
|
||||
AV_DEF = pk.AV_DEF;
|
||||
AV_SPE = pk.AV_SPE;
|
||||
AV_SPA = pk.AV_SPA;
|
||||
AV_SPD = pk.AV_SPD;
|
||||
ResortEventState = (byte)pk.ResortEventStatus;
|
||||
HeightAbsolute = pk.CalcHeightAbsolute; // Ignore the stored value, be nice and recalculate for the user.
|
||||
WeightAbsolute = pk.CalcWeightAbsolute; // Ignore the stored value, be nice and recalculate for the user.
|
||||
|
||||
public PB7 ConvertToPB7(PKH pkh)
|
||||
// Some fields are unused as PB7, don't bother copying.
|
||||
FieldEventFatigue1 = pk.FieldEventFatigue1;
|
||||
FieldEventFatigue2 = pk.FieldEventFatigue2;
|
||||
Fullness = pk.Fullness;
|
||||
// Rank = pk.Rank;
|
||||
// OT_Affection
|
||||
// OT_Intensity
|
||||
// OT_Memory
|
||||
// OT_TextVar
|
||||
// OT_Feeling
|
||||
Enjoyment = pk.Enjoyment;
|
||||
// GeoPadding = pk.GeoPadding;
|
||||
AbilityNumber = (byte)pk.AbilityNumber;
|
||||
Ability = (ushort)pk.Ability;
|
||||
|
||||
// All other side formats have HT Language. Just fake a value.
|
||||
if (pkh is { HT_Language: 0, IsUntraded: false })
|
||||
pkh.HT_Language = (byte)pk.Language;
|
||||
}
|
||||
|
||||
public PB7 ConvertToPKM(PKH pkh)
|
||||
{
|
||||
var pk = new PB7();
|
||||
pkh.CopyTo(pk);
|
||||
CopyTo(pk);
|
||||
CopyTo(pk, pkh);
|
||||
|
||||
pk.ResetCalculatedValues();
|
||||
pk.ResetPartyStats();
|
||||
pk.RefreshChecksum();
|
||||
return pk;
|
||||
}
|
||||
|
||||
|
@ -111,39 +152,60 @@ public sealed class GameDataPB7 : HomeOptional1, IGameDataSide, IScaledSizeAbsol
|
|||
/// <summary> Reconstructive logic to best apply suggested values. </summary>
|
||||
public static GameDataPB7? TryCreate(PKH pkh)
|
||||
{
|
||||
int met = 0;
|
||||
int ball = (int)Core.Ball.Poke;
|
||||
if (pkh.DataPK8 is { } x)
|
||||
{
|
||||
met = x.Met_Location;
|
||||
ball = x.Ball;
|
||||
}
|
||||
else if (pkh.DataPB8 is { } y)
|
||||
{
|
||||
met = y.Met_Location;
|
||||
ball = y.Ball;
|
||||
}
|
||||
else if (pkh.DataPA8 is { } z)
|
||||
{
|
||||
met = z.Met_Location;
|
||||
ball = z.Ball;
|
||||
}
|
||||
else if (pkh.DataPK9 is { } g9)
|
||||
{
|
||||
met = g9.Met_Location;
|
||||
ball = g9.Ball;
|
||||
}
|
||||
if (met == 0)
|
||||
if (!PersonalTable.GG.IsPresentInGame(pkh.Species, pkh.Form))
|
||||
return null;
|
||||
|
||||
// There isn't an actual preference since this format cannot naturally backwards transfer.
|
||||
// Just pick out the first one.
|
||||
var result = CreateInternal(pkh);
|
||||
if (result == null)
|
||||
return null;
|
||||
|
||||
result.PopulateFromCore(pkh);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static GameDataPB7? CreateInternal(PKH pkh)
|
||||
{
|
||||
var side = GetNearestNeighbor(pkh);
|
||||
if (side == null)
|
||||
return null;
|
||||
|
||||
var ball = side.Ball;
|
||||
if (pkh.Version is (int)GameVersion.GO)
|
||||
return new GameDataPB7 { Ball = ball, Met_Location = Locations.GO7 };
|
||||
if (pkh.Version is (int)GameVersion.GP or (int)GameVersion.GE)
|
||||
return new GameDataPB7 { Ball = ball, Met_Location = met };
|
||||
return new GameDataPB7 { Ball = ball, Met_Location = side.Met_Location };
|
||||
|
||||
return null;
|
||||
var result = new GameDataPB7();
|
||||
result.InitializeFrom(side, pkh);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void InitializeFrom(IGameDataSide side, PKH pkh)
|
||||
{
|
||||
Met_Location = side.Met_Location == Locations.Default8bNone ? 0 : side.Met_Location;
|
||||
Egg_Location = side.Egg_Location == Locations.Default8bNone ? 0 : side.Egg_Location;
|
||||
|
||||
if (side is IGameDataSplitAbility a)
|
||||
AbilityNumber = a.AbilityNumber;
|
||||
else
|
||||
AbilityNumber = 1;
|
||||
}
|
||||
|
||||
private void PopulateFromCore(PKH pkh)
|
||||
{
|
||||
var pi = PersonalTable.GG.GetFormEntry(pkh.Species, pkh.Form);
|
||||
HeightAbsolute = PB7.GetHeightAbsolute(pi, pkh.HeightScalar);
|
||||
WeightAbsolute = PB7.GetWeightAbsolute(pi, pkh.HeightScalar, pkh.WeightScalar);
|
||||
Ability = (ushort)pi.GetAbilityAtIndex(AbilityNumber >> 1);
|
||||
}
|
||||
|
||||
private static IGameDataSide? GetNearestNeighbor(PKH pkh) => pkh.DataPK9 as IGameDataSide
|
||||
?? pkh.DataPB8 as IGameDataSide
|
||||
?? pkh.DataPK8 as IGameDataSide
|
||||
?? pkh.DataPB7;
|
||||
|
||||
public static T Create<T>(GameDataPB7 data) where T : IGameDataSide, new() => new()
|
||||
{
|
||||
Ball = data.Ball,
|
||||
|
|
|
@ -6,10 +6,10 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// Side game data for <see cref="PB8"/> data transferred into HOME.
|
||||
/// </summary>
|
||||
public sealed class GameDataPB8 : HomeOptional1, IGameDataSide
|
||||
public sealed class GameDataPB8 : HomeOptional1, IGameDataSide<PB8>, IGameDataSplitAbility, IPokerusStatus
|
||||
{
|
||||
private const HomeGameDataFormat ExpectFormat = HomeGameDataFormat.PB8;
|
||||
private const int SIZE = HomeCrypto.SIZE_1GAME_PB8;
|
||||
private const int SIZE = HomeCrypto.SIZE_2GAME_PB8;
|
||||
protected override HomeGameDataFormat Format => ExpectFormat;
|
||||
|
||||
public GameDataPB8() : base(SIZE) { }
|
||||
|
@ -48,25 +48,43 @@ public sealed class GameDataPB8 : HomeOptional1, IGameDataSide
|
|||
public int Egg_Location { get => ReadUInt16LittleEndian(Data[0x27..]); set => WriteUInt16LittleEndian(Data[0x27..], (ushort)value); }
|
||||
public int Met_Location { get => ReadUInt16LittleEndian(Data[0x29..]); set => WriteUInt16LittleEndian(Data[0x29..], (ushort)value); }
|
||||
|
||||
// Rev2 Additions
|
||||
public byte PKRS { get => Data[0x2B]; set => Data[0x2B] = value; }
|
||||
public ushort Ability { get => ReadUInt16LittleEndian(Data[0x2C..]); set => WriteUInt16LittleEndian(Data[0x2C..], value); }
|
||||
public byte AbilityNumber { get => Data[0x2E]; set => Data[0x2E] = value; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Conversion
|
||||
|
||||
public PersonalInfo GetPersonalInfo(ushort species, byte form) => PersonalTable.BDSP.GetFormEntry(species, form);
|
||||
|
||||
public void CopyTo(PB8 pk)
|
||||
public void CopyTo(PB8 pk, PKH pkh)
|
||||
{
|
||||
((IGameDataSide)this).CopyTo(pk);
|
||||
this.CopyTo(pk);
|
||||
// Move Records are not settable in PB8; do not copy even if nonzero (illegal).
|
||||
pk.PKRS = PKRS;
|
||||
pk.AbilityNumber = AbilityNumber;
|
||||
pk.Ability = Ability;
|
||||
}
|
||||
|
||||
public PKM ConvertToPKM(PKH pkh) => ConvertToPB8(pkh);
|
||||
public void CopyFrom(PB8 pk, PKH pkh)
|
||||
{
|
||||
this.CopyFrom(pk);
|
||||
// Move Records are not settable in PB8; do not copy even if nonzero (illegal).
|
||||
PKRS = pk.PKRS;
|
||||
AbilityNumber = (byte)pk.AbilityNumber;
|
||||
Ability = (ushort)pk.Ability;
|
||||
}
|
||||
|
||||
public PB8 ConvertToPB8(PKH pkh)
|
||||
public PB8 ConvertToPKM(PKH pkh)
|
||||
{
|
||||
var pk = new PB8();
|
||||
pkh.CopyTo(pk);
|
||||
CopyTo(pk);
|
||||
CopyTo(pk, pkh);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
pk.RefreshChecksum();
|
||||
return pk;
|
||||
}
|
||||
|
||||
|
@ -75,28 +93,40 @@ public sealed class GameDataPB8 : HomeOptional1, IGameDataSide
|
|||
/// <summary> Reconstructive logic to best apply suggested values. </summary>
|
||||
public static GameDataPB8? TryCreate(PKH pkh)
|
||||
{
|
||||
if (pkh.DataPB7 is { } x)
|
||||
return Create(x);
|
||||
if (pkh.DataPK8 is { } b)
|
||||
return Create(b);
|
||||
if (pkh.DataPA8 is { } a)
|
||||
return Create(a);
|
||||
if (pkh.DataPK9 is { } g9)
|
||||
return Create(g9);
|
||||
return null;
|
||||
var side = GetNearestNeighbor(pkh);
|
||||
if (side == null)
|
||||
return null;
|
||||
|
||||
var result = new GameDataPB8();
|
||||
result.InitializeFrom(side, pkh);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T Create<T>(GameDataPB8 data) where T : IGameDataSide, new() => new()
|
||||
{
|
||||
Ball = data.Ball,
|
||||
Met_Location = data.Met_Location == Locations.Default8bNone ? 0 : data.Met_Location,
|
||||
Egg_Location = data.Egg_Location == Locations.Default8bNone ? 0 : data.Egg_Location,
|
||||
};
|
||||
private static IGameDataSide? GetNearestNeighbor(PKH pkh) => pkh.DataPK9 as IGameDataSide
|
||||
?? pkh.DataPK8 as IGameDataSide
|
||||
?? pkh.DataPB7 as IGameDataSide
|
||||
?? pkh.DataPA8;
|
||||
|
||||
public static GameDataPB8 Create(IGameDataSide data) => new()
|
||||
public void InitializeFrom(IGameDataSide side, PKH pkh)
|
||||
{
|
||||
Ball = data.Ball,
|
||||
Met_Location = data.Met_Location == 0 ? Locations.Default8bNone : data.Met_Location,
|
||||
Egg_Location = data.Egg_Location == 0 ? Locations.Default8bNone : data.Egg_Location,
|
||||
};
|
||||
Ball = side.Ball;
|
||||
Met_Location = side.Met_Location == 0 ? Locations.Default8bNone : side.Met_Location;
|
||||
Egg_Location = side.Egg_Location == 0 ? Locations.Default8bNone : side.Egg_Location;
|
||||
|
||||
if (side is IPokerusStatus p)
|
||||
PKRS = p.PKRS;
|
||||
if (side is IGameDataSplitAbility a)
|
||||
AbilityNumber = a.AbilityNumber;
|
||||
else
|
||||
AbilityNumber = 1;
|
||||
|
||||
PopulateFromCore(pkh);
|
||||
this.ResetMoves(pkh.Species, pkh.Form, pkh.CurrentLevel, LearnSource8BDSP.Instance, EntityContext.Gen8b);
|
||||
}
|
||||
|
||||
private void PopulateFromCore(PKH pkh)
|
||||
{
|
||||
var pi = PersonalTable.BDSP.GetFormEntry(pkh.Species, pkh.Form);
|
||||
Ability = (ushort)pi.GetAbilityAtIndex(AbilityNumber >> 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// Side game data for <see cref="PK8"/> data transferred into HOME.
|
||||
/// </summary>
|
||||
public sealed class GameDataPK8 : HomeOptional1, IGameDataSide, IGigantamax, IDynamaxLevel, ISociability
|
||||
public sealed class GameDataPK8 : HomeOptional1, IGameDataSide<PK8>, IGigantamax, IDynamaxLevel, ISociability, IGameDataSplitAbility, IPokerusStatus
|
||||
{
|
||||
private const HomeGameDataFormat ExpectFormat = HomeGameDataFormat.PK8;
|
||||
private const int SIZE = HomeCrypto.SIZE_1GAME_PK8;
|
||||
private const int SIZE = HomeCrypto.SIZE_2GAME_PK8;
|
||||
protected override HomeGameDataFormat Format => ExpectFormat;
|
||||
|
||||
public GameDataPK8() : base(SIZE) { }
|
||||
|
@ -61,15 +61,20 @@ public sealed class GameDataPK8 : HomeOptional1, IGameDataSide, IGigantamax, IDy
|
|||
public int Egg_Location { get => ReadUInt16LittleEndian(Data[0x40..]); set => WriteUInt16LittleEndian(Data[0x40..], (ushort)value); }
|
||||
public int Met_Location { get => ReadUInt16LittleEndian(Data[0x42..]); set => WriteUInt16LittleEndian(Data[0x42..], (ushort)value); }
|
||||
|
||||
// Rev2 Additions
|
||||
public byte PKRS { get => Data[0x44]; set => Data[0x44] = value; }
|
||||
public ushort Ability { get => ReadUInt16LittleEndian(Data[0x45..]); set => WriteUInt16LittleEndian(Data[0x45..], value); }
|
||||
public byte AbilityNumber { get => Data[0x47]; set => Data[0x47] = value; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Conversion
|
||||
|
||||
public PersonalInfo GetPersonalInfo(ushort species, byte form) => PersonalTable.SWSH.GetFormEntry(species, form);
|
||||
|
||||
public void CopyTo(PK8 pk)
|
||||
public void CopyTo(PK8 pk, PKH pkh)
|
||||
{
|
||||
((IGameDataSide)this).CopyTo(pk);
|
||||
this.CopyTo(pk);
|
||||
pk.CanGigantamax = CanGigantamax;
|
||||
pk.Sociability = Sociability;
|
||||
pk.DynamaxLevel = DynamaxLevel;
|
||||
|
@ -77,15 +82,34 @@ public sealed class GameDataPK8 : HomeOptional1, IGameDataSide, IGigantamax, IDy
|
|||
pk.Palma = Palma;
|
||||
PokeJob.CopyTo(pk.PokeJob);
|
||||
RecordFlags.CopyTo(pk.RecordFlags);
|
||||
pk.PKRS = PKRS;
|
||||
pk.AbilityNumber = AbilityNumber;
|
||||
pk.Ability = Ability;
|
||||
}
|
||||
|
||||
public PKM ConvertToPKM(PKH pkh) => ConvertToPK8(pkh);
|
||||
public void CopyFrom(PK8 pk, PKH pkh)
|
||||
{
|
||||
this.CopyFrom(pk);
|
||||
CanGigantamax = pk.CanGigantamax;
|
||||
Sociability = pk.Sociability;
|
||||
DynamaxLevel = pk.DynamaxLevel;
|
||||
Fullness = pk.Fullness;
|
||||
Palma = pk.Palma;
|
||||
pk.PokeJob.CopyTo(PokeJob);
|
||||
pk.RecordFlags.CopyTo(RecordFlags);
|
||||
PKRS = pk.PKRS;
|
||||
AbilityNumber = (byte)pk.AbilityNumber;
|
||||
Ability = (ushort)pk.Ability;
|
||||
}
|
||||
|
||||
public PK8 ConvertToPK8(PKH pkh)
|
||||
public PK8 ConvertToPKM(PKH pkh)
|
||||
{
|
||||
var pk = new PK8();
|
||||
pkh.CopyTo(pk);
|
||||
CopyTo(pk);
|
||||
CopyTo(pk, pkh);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
pk.RefreshChecksum();
|
||||
return pk;
|
||||
}
|
||||
|
||||
|
@ -95,39 +119,79 @@ public sealed class GameDataPK8 : HomeOptional1, IGameDataSide, IGigantamax, IDy
|
|||
public static GameDataPK8? TryCreate(PKH pkh)
|
||||
{
|
||||
if (pkh.DataPB7 is { } x)
|
||||
return GameDataPB7.Create<GameDataPK8>(x);
|
||||
return CreateViaPB7(pkh, x);
|
||||
|
||||
var side = pkh.DataPB8 as IGameDataSide
|
||||
?? pkh.DataPA8 as IGameDataSide
|
||||
?? pkh.DataPK9;
|
||||
var side = GetNearestNeighbor(pkh);
|
||||
if (side is not null)
|
||||
return Create(side, pkh.Version);
|
||||
return Create(side, pkh);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static GameDataPK8 Create(IGameDataSide side, int ver)
|
||||
// Ignores LGP/E, already preferred if exists.
|
||||
private static IGameDataSide? GetNearestNeighbor(PKH pkh) => pkh.DataPK9 as IGameDataSide
|
||||
?? pkh.DataPB8 as IGameDataSide
|
||||
?? pkh.DataPA8;
|
||||
|
||||
private static GameDataPK8 CreateViaPB7(PKH pkh, GameDataPB7 x)
|
||||
{
|
||||
var result = new GameDataPK8();
|
||||
x.CopyTo(result); // Moves are copied by default.
|
||||
result.AbilityNumber = x.AbilityNumber;
|
||||
|
||||
result.PopulateFromCore(pkh);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static GameDataPK8 Create(IGameDataSide side, PKH pkh)
|
||||
{
|
||||
var result = new GameDataPK8();
|
||||
result.InitializeFrom(side, pkh);
|
||||
|
||||
result.ResetMoves(pkh.Species, pkh.Form, pkh.CurrentLevel, LearnSource8SWSH.Instance, EntityContext.Gen8);
|
||||
return result;
|
||||
}
|
||||
|
||||
public void InitializeFrom(IGameDataSide side, PKH pkh)
|
||||
{
|
||||
// BDSP->SWSH: Set the Met Location to the magic Location, set the Egg Location to 0 if -1, otherwise BDSPEgg
|
||||
// (0 is a valid location, but no eggs can be EggMet there -- only hatched.)
|
||||
// PLA->SWSH: Set the Met Location to the magic Location, set the Egg Location to 0 (no eggs in game).
|
||||
var ver = pkh.Version;
|
||||
var met = side.Met_Location;
|
||||
var ball = GetBall(side.Ball);
|
||||
var egg = GetEggLocation(side.Egg_Location);
|
||||
if (!IsOriginallySWSH(ver, met))
|
||||
RemapMetEgg(ver, ref met, ref egg);
|
||||
return new GameDataPK8 { Ball = ball, Met_Location = met, Egg_Location = egg };
|
||||
Ball = ball;
|
||||
Met_Location = met;
|
||||
Egg_Location = egg;
|
||||
if (side is IGameDataSplitAbility a)
|
||||
AbilityNumber = a.AbilityNumber;
|
||||
if (side is IPokerusStatus p)
|
||||
PKRS = p.PKRS;
|
||||
|
||||
PopulateFromCore(pkh);
|
||||
}
|
||||
|
||||
private void PopulateFromCore(PKH pkh)
|
||||
{
|
||||
var pi = PersonalTable.SWSH.GetFormEntry(pkh.Species, pkh.Form);
|
||||
Ability = (ushort)pi.GetAbilityAtIndex(AbilityNumber >> 1);
|
||||
}
|
||||
|
||||
private static void RemapMetEgg(int ver, ref int met, ref int egg)
|
||||
{
|
||||
var remap = Locations.GetMetSWSH((ushort)met, ver);
|
||||
var remap = LocationsHOME.GetMetSWSH((ushort)met, ver);
|
||||
if (remap == met)
|
||||
return;
|
||||
|
||||
met = remap;
|
||||
egg = Locations.HOME_SWSHBDSPEgg;
|
||||
egg = LocationsHOME.SWSHEgg;
|
||||
}
|
||||
|
||||
private static bool IsOriginallySWSH(int ver, int loc) => ver is (int)GameVersion.SW or (int)GameVersion.SH && !IsFakeMetLocation(loc);
|
||||
private static bool IsFakeMetLocation(int met) => met is Locations.HOME_SWLA or Locations.HOME_SWBD or Locations.HOME_SHSP;
|
||||
private static bool IsFakeMetLocation(int met) => LocationsHOME.IsLocationSWSH(met);
|
||||
private static int GetBall(int ball) => ball > (int)Core.Ball.Beast ? 4 : ball;
|
||||
private static int GetEggLocation(int egg) => egg == Locations.Default8bNone ? 0 : egg;
|
||||
}
|
||||
|
|
|
@ -6,10 +6,10 @@ namespace PKHeX.Core;
|
|||
/// <summary>
|
||||
/// Side game data for <see cref="PK9"/> data transferred into HOME.
|
||||
/// </summary>
|
||||
public sealed class GameDataPK9 : HomeOptional1, IGameDataSide
|
||||
public sealed class GameDataPK9 : HomeOptional1, IGameDataSide<PK9>, IScaledSize3, IGameDataSplitAbility
|
||||
{
|
||||
private const HomeGameDataFormat ExpectFormat = HomeGameDataFormat.PK9;
|
||||
private const int SIZE = HomeCrypto.SIZE_1GAME_PK9;
|
||||
private const int SIZE = HomeCrypto.SIZE_2GAME_PK9;
|
||||
protected override HomeGameDataFormat Format => ExpectFormat;
|
||||
|
||||
public GameDataPK9() : base(SIZE) { }
|
||||
|
@ -19,31 +19,30 @@ public sealed class GameDataPK9 : HomeOptional1, IGameDataSide
|
|||
|
||||
#region Structure
|
||||
|
||||
public ushort Move1 { get => ReadUInt16LittleEndian(Data); set => WriteUInt16LittleEndian(Data, value); }
|
||||
public ushort Move2 { get => ReadUInt16LittleEndian(Data[0x02..]); set => WriteUInt16LittleEndian(Data[0x02..], value); }
|
||||
public ushort Move3 { get => ReadUInt16LittleEndian(Data[0x04..]); set => WriteUInt16LittleEndian(Data[0x04..], value); }
|
||||
public ushort Move4 { get => ReadUInt16LittleEndian(Data[0x06..]); set => WriteUInt16LittleEndian(Data[0x06..], value); }
|
||||
public byte Scale { get => Data[0x00]; set => Data[0x00] = value; }
|
||||
public ushort Move1 { get => ReadUInt16LittleEndian(Data[0x01..]); set => WriteUInt16LittleEndian(Data[0x01..], value); }
|
||||
public ushort Move2 { get => ReadUInt16LittleEndian(Data[0x03..]); set => WriteUInt16LittleEndian(Data[0x03..], value); }
|
||||
public ushort Move3 { get => ReadUInt16LittleEndian(Data[0x05..]); set => WriteUInt16LittleEndian(Data[0x05..], value); }
|
||||
public ushort Move4 { get => ReadUInt16LittleEndian(Data[0x07..]); set => WriteUInt16LittleEndian(Data[0x07..], value); }
|
||||
|
||||
public int Move1_PP { get => Data[0x08]; set => Data[0x08] = (byte)value; }
|
||||
public int Move2_PP { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
public int Move3_PP { get => Data[0x0A]; set => Data[0x0A] = (byte)value; }
|
||||
public int Move4_PP { get => Data[0x0B]; set => Data[0x0B] = (byte)value; }
|
||||
public int Move1_PPUps { get => Data[0x0C]; set => Data[0x0C] = (byte)value; }
|
||||
public int Move2_PPUps { get => Data[0x0D]; set => Data[0x0D] = (byte)value; }
|
||||
public int Move3_PPUps { get => Data[0x0E]; set => Data[0x0E] = (byte)value; }
|
||||
public int Move4_PPUps { get => Data[0x0F]; set => Data[0x0F] = (byte)value; }
|
||||
public int Move1_PP { get => Data[0x09]; set => Data[0x09] = (byte)value; }
|
||||
public int Move2_PP { get => Data[0x0A]; set => Data[0x0A] = (byte)value; }
|
||||
public int Move3_PP { get => Data[0x0B]; set => Data[0x0B] = (byte)value; }
|
||||
public int Move4_PP { get => Data[0x0C]; set => Data[0x0C] = (byte)value; }
|
||||
public int Move1_PPUps { get => Data[0x0D]; set => Data[0x0D] = (byte)value; }
|
||||
public int Move2_PPUps { get => Data[0x0E]; set => Data[0x0E] = (byte)value; }
|
||||
public int Move3_PPUps { get => Data[0x0F]; set => Data[0x0F] = (byte)value; }
|
||||
public int Move4_PPUps { get => Data[0x10]; set => Data[0x10] = (byte)value; }
|
||||
|
||||
public ushort RelearnMove1 { get => ReadUInt16LittleEndian(Data[0x10..]); set => WriteUInt16LittleEndian(Data[0x10..], value); }
|
||||
public ushort RelearnMove2 { get => ReadUInt16LittleEndian(Data[0x12..]); set => WriteUInt16LittleEndian(Data[0x12..], value); }
|
||||
public ushort RelearnMove3 { get => ReadUInt16LittleEndian(Data[0x14..]); set => WriteUInt16LittleEndian(Data[0x14..], value); }
|
||||
public ushort RelearnMove4 { get => ReadUInt16LittleEndian(Data[0x16..]); set => WriteUInt16LittleEndian(Data[0x16..], value); }
|
||||
public int Egg_Location { get => ReadUInt16LittleEndian(Data[0x18..]); set => WriteUInt16LittleEndian(Data[0x18..], (ushort)value); }
|
||||
public int Met_Location { get => ReadUInt16LittleEndian(Data[0x1A..]); set => WriteUInt16LittleEndian(Data[0x1A..], (ushort)value); }
|
||||
|
||||
public int Ball { get => Data[0x1C]; set => Data[0x1C] = (byte)value; }
|
||||
public byte Scale { get => Data[0x1D]; set => Data[0x1D] = value; }
|
||||
public MoveType TeraTypeOriginal { get => (MoveType)Data[0x1E]; set => Data[0x1E] = (byte)value; }
|
||||
public MoveType TeraTypeModified { get => (MoveType)Data[0x1F]; set => Data[0x1F] = (byte)value; }
|
||||
public ushort RelearnMove1 { get => ReadUInt16LittleEndian(Data[0x11..]); set => WriteUInt16LittleEndian(Data[0x11..], value); }
|
||||
public ushort RelearnMove2 { get => ReadUInt16LittleEndian(Data[0x13..]); set => WriteUInt16LittleEndian(Data[0x13..], value); }
|
||||
public ushort RelearnMove3 { get => ReadUInt16LittleEndian(Data[0x15..]); set => WriteUInt16LittleEndian(Data[0x15..], value); }
|
||||
public ushort RelearnMove4 { get => ReadUInt16LittleEndian(Data[0x17..]); set => WriteUInt16LittleEndian(Data[0x17..], value); }
|
||||
public MoveType TeraTypeOriginal { get => (MoveType)Data[0x19]; set => Data[0x19] = (byte)value; }
|
||||
public MoveType TeraTypeOverride { get => (MoveType)Data[0x1A]; set => Data[0x1A] = (byte)value; }
|
||||
public int Ball { get => Data[0x1B]; set => Data[0x1B] = (byte)value; }
|
||||
public int Egg_Location { get => ReadUInt16LittleEndian(Data[0x1C..]); set => WriteUInt16LittleEndian(Data[0x1C..], (ushort)value); }
|
||||
public int Met_Location { get => ReadUInt16LittleEndian(Data[0x1E..]); set => WriteUInt16LittleEndian(Data[0x1E..], (ushort)value); }
|
||||
|
||||
private const int RecordStart = 0x20;
|
||||
private const int RecordCount = PK9.COUNT_RECORD; // Up to 200 TM flags, but not all are used.
|
||||
|
@ -67,28 +66,49 @@ public sealed class GameDataPK9 : HomeOptional1, IGameDataSide
|
|||
public bool GetMoveRecordFlagAny() => RecordFlags.IndexOfAnyExcept<byte>(0) >= 0;
|
||||
public void ClearMoveRecordFlags() => RecordFlags.Clear();
|
||||
|
||||
// Rev2 Additions
|
||||
public byte Obedience_Level { get => Data[0x39]; set => Data[0x39] = value; }
|
||||
public ushort Ability { get => ReadUInt16LittleEndian(Data[0x3A..]); set => WriteUInt16LittleEndian(Data[0x3A..], value); }
|
||||
public byte AbilityNumber { get => Data[0x3C]; set => Data[0x3C] = value; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Conversion
|
||||
|
||||
public PersonalInfo GetPersonalInfo(ushort species, byte form) => PersonalTable.SV.GetFormEntry(species, form);
|
||||
|
||||
public void CopyTo(PK9 pk)
|
||||
public void CopyTo(PK9 pk, PKH pkh)
|
||||
{
|
||||
((IGameDataSide)this).CopyTo(pk);
|
||||
this.CopyTo(pk);
|
||||
pk.Scale = Scale;
|
||||
pk.TeraTypeOriginal = TeraTypeOriginal;
|
||||
pk.TeraTypeOverride = TeraTypeModified;
|
||||
pk.TeraTypeOverride = TeraTypeOverride;
|
||||
RecordFlags.CopyTo(pk.RecordFlags);
|
||||
pk.Obedience_Level = Obedience_Level;
|
||||
pk.Ability = Ability;
|
||||
pk.AbilityNumber = AbilityNumber;
|
||||
}
|
||||
|
||||
public PKM ConvertToPKM(PKH pkh) => ConvertToPK9(pkh);
|
||||
public void CopyFrom(PK9 pk, PKH pkh)
|
||||
{
|
||||
this.CopyFrom(pk);
|
||||
pkh.HeightScalar = Scale = pk.Scale; // Overwrite Height
|
||||
TeraTypeOriginal = pk.TeraTypeOriginal;
|
||||
TeraTypeOverride = pk.TeraTypeOverride;
|
||||
pk.RecordFlags.CopyTo(RecordFlags);
|
||||
Obedience_Level = pk.Obedience_Level;
|
||||
Ability = (ushort)pk.Ability;
|
||||
AbilityNumber = (byte)pk.AbilityNumber;
|
||||
}
|
||||
|
||||
public PK9 ConvertToPK9(PKH pkh)
|
||||
public PK9 ConvertToPKM(PKH pkh)
|
||||
{
|
||||
var pk = new PK9();
|
||||
pkh.CopyTo(pk);
|
||||
CopyTo(pk);
|
||||
CopyTo(pk, pkh);
|
||||
|
||||
pk.ResetPartyStats();
|
||||
pk.RefreshChecksum();
|
||||
return pk;
|
||||
}
|
||||
|
||||
|
@ -100,28 +120,55 @@ public sealed class GameDataPK9 : HomeOptional1, IGameDataSide
|
|||
if (!PersonalTable.SV.IsPresentInGame(pkh.Species, pkh.Form))
|
||||
return null;
|
||||
|
||||
if (pkh.DataPB7 is { } x)
|
||||
return Create(x);
|
||||
if (pkh.DataPK8 is { } b)
|
||||
return Create(b);
|
||||
if (pkh.DataPA8 is { } a)
|
||||
return Create(a);
|
||||
if (pkh.DataPB8 is { } bd)
|
||||
return Create(bd);
|
||||
return null;
|
||||
var result = CreateInternal(pkh);
|
||||
if (result == null)
|
||||
return null;
|
||||
|
||||
result.PopulateFromCore(pkh);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static T Create<T>(GameDataPK9 data) where T : IGameDataSide, new() => new()
|
||||
private static GameDataPK9? CreateInternal(PKH pkh)
|
||||
{
|
||||
Ball = data.Ball,
|
||||
Met_Location = data.Met_Location == Locations.Default8bNone ? 0 : data.Met_Location,
|
||||
Egg_Location = data.Egg_Location == Locations.Default8bNone ? 0 : data.Egg_Location,
|
||||
};
|
||||
var side = GetNearestNeighbor(pkh);
|
||||
if (side == null)
|
||||
return null;
|
||||
|
||||
public static GameDataPK9 Create(IGameDataSide data) => new()
|
||||
var result = new GameDataPK9();
|
||||
result.InitializeFrom(side, pkh);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IGameDataSide? GetNearestNeighbor(PKH pkh) => pkh.DataPK8 as IGameDataSide
|
||||
?? pkh.DataPB8 as IGameDataSide
|
||||
?? pkh.DataPB7 as IGameDataSide
|
||||
?? pkh.DataPA8;
|
||||
|
||||
public void InitializeFrom(IGameDataSide side, PKH pkh)
|
||||
{
|
||||
Ball = data.Ball,
|
||||
Met_Location = data.Met_Location == 0 ? Locations.Default8bNone : data.Met_Location,
|
||||
Egg_Location = data.Egg_Location == 0 ? Locations.Default8bNone : data.Egg_Location,
|
||||
};
|
||||
Ball = side.Ball;
|
||||
Met_Location = side.Met_Location == Locations.Default8bNone ? 0 : side.Met_Location;
|
||||
Egg_Location = side.Egg_Location == Locations.Default8bNone ? 0 : side.Egg_Location;
|
||||
|
||||
if (side is IScaledSize3 s3)
|
||||
Scale = s3.Scale;
|
||||
else
|
||||
Scale = pkh.HeightScalar;
|
||||
if (side is IGameDataSplitAbility a)
|
||||
AbilityNumber = a.AbilityNumber;
|
||||
else
|
||||
AbilityNumber = 1;
|
||||
|
||||
PopulateFromCore(pkh);
|
||||
this.ResetMoves(pkh.Species, pkh.Form, pkh.CurrentLevel, LearnSource9SV.Instance, EntityContext.Gen9);
|
||||
}
|
||||
|
||||
private void PopulateFromCore(PKH pkh)
|
||||
{
|
||||
Obedience_Level = (byte)pkh.Met_Level;
|
||||
|
||||
var pi = PersonalTable.SV.GetFormEntry(pkh.Species, pkh.Form);
|
||||
Ability = (ushort)pi.GetAbilityAtIndex(AbilityNumber >> 1);
|
||||
TeraTypeOriginal = TeraTypeOverride = TeraTypeUtil.GetTeraTypeImport(pi.Type1, pi.Type2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,28 +11,41 @@ namespace PKHeX.Core;
|
|||
/// </summary>
|
||||
public static class HomeCrypto
|
||||
{
|
||||
internal const int Version1 = 1;
|
||||
public const int Version1 = 1;
|
||||
public const int Version2 = 2;
|
||||
|
||||
internal const int SIZE_1HEADER = 0x10; // 16
|
||||
public const int SIZE_1HEADER = 0x10; // 16
|
||||
|
||||
internal const int SIZE_1CORE = 0xC8; // 200
|
||||
public const int SIZE_1CORE = 0xC8; // 200
|
||||
public const int SIZE_1GAME_PB7 = 0x3B; // 59
|
||||
public const int SIZE_1GAME_PK8 = 0x44; // 68
|
||||
public const int SIZE_1GAME_PA8 = 0x3C; // 60
|
||||
public const int SIZE_1GAME_PB8 = 0x2B; // 43
|
||||
public const int SIZE_1STORED = 0x1EE; // 494
|
||||
|
||||
internal const int SIZE_1GAME_PB7 = 0x3B; // 59
|
||||
internal const int SIZE_1GAME_PK8 = 0x44; // 68
|
||||
internal const int SIZE_1GAME_PA8 = 0x3C; // 60
|
||||
internal const int SIZE_1GAME_PB8 = 0x2B; // 43
|
||||
internal const int SIZE_1GAME_PK9 = 0x39; // todo sv
|
||||
internal const int SIZE_1STORED = 0x1EE; // 494
|
||||
public const int SIZE_2CORE = 0xC4; // 196
|
||||
public const int SIZE_2GAME_PB7 = 0x3F; // 63
|
||||
public const int SIZE_2GAME_PK8 = 0x48; // 72
|
||||
public const int SIZE_2GAME_PA8 = 0x40; // 64
|
||||
public const int SIZE_2GAME_PB8 = 0x2F; // 47
|
||||
public const int SIZE_2GAME_PK9 = 0x3D; // 61
|
||||
public const int SIZE_2STORED = 0x23A; // 570
|
||||
|
||||
public const int SIZE_STORED = SIZE_2STORED;
|
||||
public const int SIZE_CORE = SIZE_2CORE;
|
||||
public const int VersionLatest = Version2;
|
||||
|
||||
public static bool IsKnownVersion(ushort version) => version is Version1 or Version2;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void GetFormat1EncryptionKey(Span<byte> key, ulong seed)
|
||||
public static void SetEncryptionKey(Span<byte> key, ulong seed)
|
||||
{
|
||||
WriteUInt64BigEndian(key, seed ^ 0x6B7B5966193DB88B);
|
||||
WriteUInt64BigEndian(key.Slice(8, 8), seed & 0x937EC53BF8856E87);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void GetFormat1EncryptionIv(Span<byte> iv, ulong seed)
|
||||
public static void SetEncryptionIv(Span<byte> iv, ulong seed)
|
||||
{
|
||||
WriteUInt64BigEndian(iv, seed ^ 0x5F4ED4E84975D976);
|
||||
WriteUInt64BigEndian(iv.Slice(8, 8), seed | 0xE3CDA917EA9E489C);
|
||||
|
@ -45,28 +58,28 @@ public static class HomeCrypto
|
|||
/// <param name="decrypt">Encryption or Decryption mode</param>
|
||||
/// <returns>New array with result data.</returns>
|
||||
/// <exception cref="ArgumentException"> if the format is not supported.</exception>
|
||||
public static byte[] Crypt1(ReadOnlySpan<byte> data, bool decrypt = true)
|
||||
public static byte[] Crypt(ReadOnlySpan<byte> data, bool decrypt = true)
|
||||
{
|
||||
var format = ReadUInt16LittleEndian(data);
|
||||
if (format != Version1)
|
||||
if (!IsKnownVersion(format))
|
||||
throw new ArgumentException($"Unrecognized format: {format}");
|
||||
|
||||
ulong seed = ReadUInt64LittleEndian(data.Slice(2, 8));
|
||||
|
||||
var key = new byte[0x10];
|
||||
GetFormat1EncryptionKey(key, seed);
|
||||
SetEncryptionKey(key, seed);
|
||||
var iv = new byte[0x10];
|
||||
GetFormat1EncryptionIv(iv, seed);
|
||||
SetEncryptionIv(iv, seed);
|
||||
|
||||
var dataSize = ReadUInt16LittleEndian(data[0xE..0x10]);
|
||||
var result = new byte[SIZE_1HEADER + dataSize];
|
||||
data[..SIZE_1HEADER].CopyTo(result); // header
|
||||
Crypt1(data, key, iv, result, dataSize, decrypt);
|
||||
Crypt(data, key, iv, result, dataSize, decrypt);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void Crypt1(ReadOnlySpan<byte> data, byte[] key, byte[] iv, byte[] result, ushort dataSize, bool decrypt)
|
||||
private static void Crypt(ReadOnlySpan<byte> data, byte[] key, byte[] iv, byte[] result, ushort dataSize, bool decrypt)
|
||||
{
|
||||
using var aes = Aes.Create();
|
||||
aes.Mode = CipherMode.CBC;
|
||||
|
@ -89,10 +102,10 @@ public static class HomeCrypto
|
|||
{
|
||||
var span = data.AsSpan();
|
||||
var format = ReadUInt16LittleEndian(span);
|
||||
if (format == Version1)
|
||||
if (IsKnownVersion(format))
|
||||
{
|
||||
if (GetIsEncrypted1(span))
|
||||
data = Crypt1(span);
|
||||
if (GetIsEncrypted(span, format))
|
||||
data = Crypt(span);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -105,7 +118,7 @@ public static class HomeCrypto
|
|||
/// </summary>
|
||||
public static byte[] Encrypt(ReadOnlySpan<byte> pk)
|
||||
{
|
||||
var result = Crypt1(pk, false);
|
||||
var result = Crypt(pk, false);
|
||||
RefreshChecksum(result, result);
|
||||
return result;
|
||||
}
|
||||
|
@ -125,17 +138,39 @@ public static class HomeCrypto
|
|||
/// Checks if the format 1 data is encrypted.
|
||||
/// </summary>
|
||||
/// <returns>True if encrypted.</returns>
|
||||
public static bool GetIsEncrypted1(ReadOnlySpan<byte> data)
|
||||
public static bool GetIsEncrypted(ReadOnlySpan<byte> data, ushort format) => format switch
|
||||
{
|
||||
if (ReadUInt16LittleEndian(data[SIZE_1HEADER..]) != SIZE_1CORE)
|
||||
return true; // Core length should be constant if decrypted.
|
||||
Version1 => IsEncryptedCore1(data),
|
||||
Version2 => IsEncryptedCore2(data),
|
||||
_ => throw new ArgumentException($"Unrecognized format: {format}"),
|
||||
};
|
||||
|
||||
private static bool IsEncryptedCore1(ReadOnlySpan<byte> data)
|
||||
{
|
||||
var core = data.Slice(SIZE_1HEADER + 2, SIZE_1CORE);
|
||||
if (ReadUInt16LittleEndian(core[0xB5..]) != 0)
|
||||
|
||||
// Strings should be \0000 terminated if decrypted.
|
||||
// Any non-zero value is a sign of encryption.
|
||||
if (ReadUInt16LittleEndian(core[0xB5..]) != 0) // OT
|
||||
return true; // OT_Name final terminator should be 0 if decrypted.
|
||||
if (ReadUInt16LittleEndian(core[0x60..]) != 0)
|
||||
if (ReadUInt16LittleEndian(core[0x60..]) != 0) // Nick
|
||||
return true; // Nickname final terminator should be 0 if decrypted.
|
||||
if (ReadUInt16LittleEndian(core[0x88..]) != 0)
|
||||
if (ReadUInt16LittleEndian(core[0x88..]) != 0) // HT
|
||||
return true; // HT_Name final terminator should be 0 if decrypted.
|
||||
|
||||
//// Fall back to checksum.
|
||||
//return ReadUInt32LittleEndian(data[0xA..0xE]) == GetChecksum1(data);
|
||||
return false; // 64 bits checked is enough to feel safe about this check.
|
||||
}
|
||||
|
||||
private static bool IsEncryptedCore2(ReadOnlySpan<byte> data)
|
||||
{
|
||||
var core = data.Slice(SIZE_1HEADER + 2, SIZE_2CORE);
|
||||
if (ReadUInt16LittleEndian(core[0xB1..]) != 0)
|
||||
return true; // OT_Name final terminator should be 0 if decrypted.
|
||||
if (ReadUInt16LittleEndian(core[0x5C..]) != 0)
|
||||
return true; // Nickname final terminator should be 0 if decrypted.
|
||||
if (ReadUInt16LittleEndian(core[0x84..]) != 0)
|
||||
return true; // HT_Name final terminator should be 0 if decrypted.
|
||||
|
||||
//// Fall back to checksum.
|
||||
|
|
|
@ -11,6 +11,7 @@ public abstract class HomeOptional1
|
|||
// Internal Attributes set on creation
|
||||
private readonly Memory<byte> Buffer; // Raw Storage
|
||||
protected Span<byte> Data => Buffer.Span;
|
||||
public int SerializedSize => HeaderSize + Buffer.Length;
|
||||
|
||||
public const int HeaderSize = 3; // u8 format, u16 length(data[u8])
|
||||
protected abstract HomeGameDataFormat Format { get; }
|
||||
|
|
|
@ -1,5 +1,41 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Inter-format manipulation API for <see cref="IGameDataSide"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public interface IGameDataSide<T> : IGameDataSide where T : PKM, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Copies the data from the current instance into the input <see cref="PKM"/>.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to copy to</param>
|
||||
/// <param name="pkh">Overall HOME data object</param>
|
||||
void CopyTo(T pk, PKH pkh);
|
||||
|
||||
/// <summary>
|
||||
/// Copies the data from the input <see cref="PKM"/> into the current instance.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to copy from</param>
|
||||
/// <param name="pkh">Overall HOME data object</param>
|
||||
void CopyFrom(T pk, PKH pkh);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the data to a <see cref="PKM"/>.
|
||||
/// </summary>
|
||||
/// <param name="pkh">Overall HOME data object</param>
|
||||
T ConvertToPKM(PKH pkh);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the instance with data from the input <see cref="PKM"/>.
|
||||
/// </summary>
|
||||
/// <param name="other">Other game data to initialize from</param>
|
||||
/// <param name="pkh">Overall HOME data object</param>
|
||||
void InitializeFrom(IGameDataSide other, PKH pkh);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common properties stored by HOME's side game data formats.
|
||||
/// </summary>
|
||||
|
@ -17,12 +53,6 @@ public interface IGameDataSide
|
|||
/// Gets the personal info for the input arguments.
|
||||
/// </summary>
|
||||
PersonalInfo GetPersonalInfo(ushort species, byte form);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the data to a <see cref="PKM"/>.
|
||||
/// </summary>
|
||||
/// <param name="pkh">HOME entity</param>
|
||||
PKM ConvertToPKM(PKH pkh);
|
||||
}
|
||||
|
||||
public static class GameDataSideExtensions
|
||||
|
@ -35,9 +65,9 @@ public static class GameDataSideExtensions
|
|||
public static void CopyTo(this IGameDataSide data, PKM pk)
|
||||
{
|
||||
pk.Move1 = data.Move1; pk.Move1_PP = data.Move1_PP; pk.Move1_PPUps = data.Move1_PPUps; pk.RelearnMove1 = data.RelearnMove1;
|
||||
pk.Move2 = data.Move2; pk.Move2_PP = data.Move1_PP; pk.Move2_PPUps = data.Move2_PPUps; pk.RelearnMove2 = data.RelearnMove2;
|
||||
pk.Move3 = data.Move3; pk.Move3_PP = data.Move1_PP; pk.Move3_PPUps = data.Move3_PPUps; pk.RelearnMove3 = data.RelearnMove3;
|
||||
pk.Move4 = data.Move4; pk.Move4_PP = data.Move1_PP; pk.Move4_PPUps = data.Move4_PPUps; pk.RelearnMove4 = data.RelearnMove4;
|
||||
pk.Move2 = data.Move2; pk.Move2_PP = data.Move2_PP; pk.Move2_PPUps = data.Move2_PPUps; pk.RelearnMove2 = data.RelearnMove2;
|
||||
pk.Move3 = data.Move3; pk.Move3_PP = data.Move3_PP; pk.Move3_PPUps = data.Move3_PPUps; pk.RelearnMove3 = data.RelearnMove3;
|
||||
pk.Move4 = data.Move4; pk.Move4_PP = data.Move4_PP; pk.Move4_PPUps = data.Move4_PPUps; pk.RelearnMove4 = data.RelearnMove4;
|
||||
pk.Ball = data.Ball;
|
||||
pk.Met_Location = data.Met_Location;
|
||||
pk.Egg_Location = data.Egg_Location;
|
||||
|
@ -51,11 +81,45 @@ public static class GameDataSideExtensions
|
|||
public static void CopyTo(this IGameDataSide data, IGameDataSide pk)
|
||||
{
|
||||
pk.Move1 = data.Move1; pk.Move1_PP = data.Move1_PP; pk.Move1_PPUps = data.Move1_PPUps; pk.RelearnMove1 = data.RelearnMove1;
|
||||
pk.Move2 = data.Move2; pk.Move2_PP = data.Move1_PP; pk.Move2_PPUps = data.Move2_PPUps; pk.RelearnMove2 = data.RelearnMove2;
|
||||
pk.Move3 = data.Move3; pk.Move3_PP = data.Move1_PP; pk.Move3_PPUps = data.Move3_PPUps; pk.RelearnMove3 = data.RelearnMove3;
|
||||
pk.Move4 = data.Move4; pk.Move4_PP = data.Move1_PP; pk.Move4_PPUps = data.Move4_PPUps; pk.RelearnMove4 = data.RelearnMove4;
|
||||
pk.Move2 = data.Move2; pk.Move2_PP = data.Move2_PP; pk.Move2_PPUps = data.Move2_PPUps; pk.RelearnMove2 = data.RelearnMove2;
|
||||
pk.Move3 = data.Move3; pk.Move3_PP = data.Move3_PP; pk.Move3_PPUps = data.Move3_PPUps; pk.RelearnMove3 = data.RelearnMove3;
|
||||
pk.Move4 = data.Move4; pk.Move4_PP = data.Move4_PP; pk.Move4_PPUps = data.Move4_PPUps; pk.RelearnMove4 = data.RelearnMove4;
|
||||
pk.Ball = data.Ball;
|
||||
pk.Met_Location = data.Met_Location;
|
||||
pk.Egg_Location = data.Egg_Location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the shared properties into a destination.
|
||||
/// </summary>
|
||||
/// <param name="data">Source side game data</param>
|
||||
/// <param name="pk">Destination entity</param>
|
||||
public static void CopyFrom(this IGameDataSide data, PKM pk)
|
||||
{
|
||||
data.Move1 = pk.Move1; data.Move1_PP = pk.Move1_PP; data.Move1_PPUps = pk.Move1_PPUps; data.RelearnMove1 = pk.RelearnMove1;
|
||||
data.Move2 = pk.Move2; data.Move2_PP = pk.Move2_PP; data.Move2_PPUps = pk.Move2_PPUps; data.RelearnMove2 = pk.RelearnMove2;
|
||||
data.Move3 = pk.Move3; data.Move3_PP = pk.Move3_PP; data.Move3_PPUps = pk.Move3_PPUps; data.RelearnMove3 = pk.RelearnMove3;
|
||||
data.Move4 = pk.Move4; data.Move4_PP = pk.Move4_PP; data.Move4_PPUps = pk.Move4_PPUps; data.RelearnMove4 = pk.RelearnMove4;
|
||||
data.Ball = pk.Ball;
|
||||
data.Met_Location = pk.Met_Location;
|
||||
data.Egg_Location = pk.Egg_Location;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the moves using the <see cref="source"/> for the given level.
|
||||
/// </summary>
|
||||
public static void ResetMoves(this IGameDataSide data, ushort species, byte form, int level, ILearnSource source, EntityContext context)
|
||||
{
|
||||
var learn = source.GetLearnset(species, form);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
learn.SetEncounterMoves(level, moves);
|
||||
data.Move1 = moves[0];
|
||||
data.Move2 = moves[1];
|
||||
data.Move3 = moves[2];
|
||||
data.Move4 = moves[3];
|
||||
data.Move1_PP = MoveInfo.GetPP(context, moves[0]);
|
||||
data.Move2_PP = MoveInfo.GetPP(context, moves[1]);
|
||||
data.Move3_PP = MoveInfo.GetPP(context, moves[2]);
|
||||
data.Move4_PP = MoveInfo.GetPP(context, moves[3]);
|
||||
}
|
||||
}
|
||||
|
|
7
PKHeX.Core/PKM/HOME/IGameDataSplitAbility.cs
Normal file
7
PKHeX.Core/PKM/HOME/IGameDataSplitAbility.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
public interface IGameDataSplitAbility
|
||||
{
|
||||
ushort Ability { get; set; }
|
||||
byte AbilityNumber { get; set; }
|
||||
}
|
13
PKHeX.Core/PKM/HOME/IHomeStorage.cs
Normal file
13
PKHeX.Core/PKM/HOME/IHomeStorage.cs
Normal file
|
@ -0,0 +1,13 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
public interface IHomeStorage
|
||||
{
|
||||
bool Exists(ulong tracker);
|
||||
PKH GetEntity<T>(T pk) where T : PKM;
|
||||
}
|
||||
|
||||
public sealed class HomeStorageFacade : IHomeStorage
|
||||
{
|
||||
public bool Exists(ulong tracker) => false;
|
||||
public PKH GetEntity<T>(T pk) where T : PKM => PKH.ConvertFromPKM(pk);
|
||||
}
|
6
PKHeX.Core/PKM/HOME/IPokerusStatus.cs
Normal file
6
PKHeX.Core/PKM/HOME/IPokerusStatus.cs
Normal file
|
@ -0,0 +1,6 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
public interface IPokerusStatus
|
||||
{
|
||||
byte PKRS { get; set; }
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
using System;
|
||||
using static System.Buffers.Binary.BinaryPrimitives;
|
||||
using static PKHeX.Core.GameVersion;
|
||||
using static PKHeX.Core.Locations;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Pokémon HOME <see cref="PKM"/> format. </summary>
|
||||
public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, IRibbonSetAffixed, IContestStats, IScaledSize, IRibbonSetRibbons, IRibbonSetMarks
|
||||
{
|
||||
public readonly GameDataCore _coreData;
|
||||
public readonly GameDataCore Core;
|
||||
public GameDataPB7? DataPB7 { get; private set; }
|
||||
public GameDataPK8? DataPK8 { get; private set; }
|
||||
public GameDataPA8? DataPA8 { get; private set; }
|
||||
|
@ -23,10 +22,19 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
var core = mem[..CoreDataSize];
|
||||
var side = mem.Slice(core.Length + 2, GameDataSize);
|
||||
|
||||
_coreData = new GameDataCore(core);
|
||||
Core = new GameDataCore(core);
|
||||
ReadGameData1(side);
|
||||
}
|
||||
|
||||
public PKH() : base(HomeCrypto.SIZE_STORED)
|
||||
{
|
||||
CoreDataSize = HomeCrypto.SIZE_CORE;
|
||||
|
||||
var mem = Data.AsMemory(HomeCrypto.SIZE_1HEADER + 2);
|
||||
var core = mem[..CoreDataSize];
|
||||
Core = new GameDataCore(core) { AffixedRibbon = -1 };
|
||||
}
|
||||
|
||||
private void ReadGameData1(Memory<byte> data)
|
||||
{
|
||||
// Can potentially have no side-game data (GO imports)
|
||||
|
@ -39,18 +47,20 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
var chunk = data[..length];
|
||||
data = data[chunk.Length..];
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case HomeGameDataFormat.PB7: DataPB7 = new GameDataPB7(chunk); break;
|
||||
case HomeGameDataFormat.PK8: DataPK8 = new GameDataPK8(chunk); break;
|
||||
case HomeGameDataFormat.PA8: DataPA8 = new GameDataPA8(chunk); break;
|
||||
case HomeGameDataFormat.PB8: DataPB8 = new GameDataPB8(chunk); break;
|
||||
case HomeGameDataFormat.PK9: DataPK9 = new GameDataPK9(chunk); break;
|
||||
default: throw new ArgumentException($"Unknown {nameof(HomeGameDataFormat)} {format}");
|
||||
}
|
||||
_ = ReadGameData1(chunk, format);
|
||||
}
|
||||
}
|
||||
|
||||
private IGameDataSide ReadGameData1(Memory<byte> chunk, HomeGameDataFormat format) => format switch
|
||||
{
|
||||
HomeGameDataFormat.PB7 => DataPB7 = new GameDataPB7(chunk),
|
||||
HomeGameDataFormat.PK8 => DataPK8 = new GameDataPK8(chunk),
|
||||
HomeGameDataFormat.PA8 => DataPA8 = new GameDataPA8(chunk),
|
||||
HomeGameDataFormat.PB8 => DataPB8 = new GameDataPB8(chunk),
|
||||
HomeGameDataFormat.PK9 => DataPK9 = new GameDataPK9(chunk),
|
||||
_ => throw new ArgumentException($"Unknown {nameof(HomeGameDataFormat)} {format}")
|
||||
};
|
||||
|
||||
private static byte[] DecryptHome(byte[] data)
|
||||
{
|
||||
HomeCrypto.DecryptIfEncrypted(ref data);
|
||||
|
@ -65,108 +75,113 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
public ushort CoreDataSize { get => ReadUInt16LittleEndian(Data.AsSpan(0x10)); set => WriteUInt16LittleEndian(Data.AsSpan(0x10), value); }
|
||||
public ushort GameDataSize { get => ReadUInt16LittleEndian(Data.AsSpan(0x12 + CoreDataSize)); set => WriteUInt16LittleEndian(Data.AsSpan(0x12 + CoreDataSize), value); }
|
||||
|
||||
public override Span<byte> Nickname_Trash => _coreData.Nickname_Trash;
|
||||
public override Span<byte> OT_Trash => _coreData.OT_Trash;
|
||||
public override Span<byte> HT_Trash => _coreData.HT_Trash;
|
||||
private const int GameDataStart = HomeCrypto.SIZE_1HEADER + 2 + HomeCrypto.SIZE_CORE + 2;
|
||||
|
||||
public override Span<byte> Nickname_Trash => Core.Nickname_Trash;
|
||||
public override Span<byte> OT_Trash => Core.OT_Trash;
|
||||
public override Span<byte> HT_Trash => Core.HT_Trash;
|
||||
public override bool IsUntraded => ReadUInt16LittleEndian(HT_Trash) == 0; // immediately terminated HT_Name data (\0)
|
||||
|
||||
#region Core
|
||||
|
||||
public ulong Tracker { get => _coreData.Tracker; set => _coreData.Tracker = value; }
|
||||
public override uint EncryptionConstant { get => _coreData.EncryptionConstant; set => _coreData.EncryptionConstant = value; }
|
||||
public bool IsBadEgg { get => _coreData.IsBadEgg; set => _coreData.IsBadEgg = value; }
|
||||
public override ushort Species { get => _coreData.Species; set => _coreData.Species = value; }
|
||||
public override uint ID32 { get => _coreData.ID32; set => _coreData.ID32 = value; }
|
||||
public override ushort TID16 { get => _coreData.TID16; set => _coreData.TID16 = value; }
|
||||
public override ushort SID16 { get => _coreData.SID16; set => _coreData.SID16 = value; }
|
||||
public override uint EXP { get => _coreData.EXP; set => _coreData.EXP = value; }
|
||||
public override int Ability { get => _coreData.Ability; set => _coreData.Ability = value; }
|
||||
public override int AbilityNumber { get => _coreData.AbilityNumber; set => _coreData.AbilityNumber = value; }
|
||||
public bool Favorite { get => _coreData.IsFavorite; set => _coreData.IsFavorite = value; }
|
||||
public override int MarkValue { get => _coreData.MarkValue; set => _coreData.MarkValue = value; }
|
||||
public override uint PID { get => _coreData.PID; set => _coreData.PID = value; }
|
||||
public override int Nature { get => _coreData.Nature; set => _coreData.Nature = value; }
|
||||
public override int StatNature { get => _coreData.StatNature; set => _coreData.StatNature = value; }
|
||||
public override bool FatefulEncounter { get => _coreData.FatefulEncounter; set => _coreData.FatefulEncounter = value; }
|
||||
public override int Gender { get => _coreData.Gender; set => _coreData.Gender = value; }
|
||||
public override byte Form { get => _coreData.Form; set => _coreData.Form = value; }
|
||||
public override int EV_HP { get => _coreData.EV_HP; set => _coreData.EV_HP = value; }
|
||||
public override int EV_ATK { get => _coreData.EV_ATK; set => _coreData.EV_ATK = value; }
|
||||
public override int EV_DEF { get => _coreData.EV_DEF; set => _coreData.EV_DEF = value; }
|
||||
public override int EV_SPE { get => _coreData.EV_SPE; set => _coreData.EV_SPE = value; }
|
||||
public override int EV_SPA { get => _coreData.EV_SPA; set => _coreData.EV_SPA = value; }
|
||||
public override int EV_SPD { get => _coreData.EV_SPD; set => _coreData.EV_SPD = value; }
|
||||
public byte CNT_Cool { get => _coreData.CNT_Cool; set => _coreData.CNT_Cool = value; }
|
||||
public byte CNT_Beauty { get => _coreData.CNT_Beauty; set => _coreData.CNT_Beauty = value; }
|
||||
public byte CNT_Cute { get => _coreData.CNT_Cute; set => _coreData.CNT_Cute = value; }
|
||||
public byte CNT_Smart { get => _coreData.CNT_Smart; set => _coreData.CNT_Smart = value; }
|
||||
public byte CNT_Tough { get => _coreData.CNT_Tough; set => _coreData.CNT_Tough = value; }
|
||||
public byte CNT_Sheen { get => _coreData.CNT_Sheen; set => _coreData.CNT_Sheen = value; }
|
||||
public override int PKRS_Days { get => _coreData.PKRS_Days; set => _coreData.PKRS_Days = value; }
|
||||
public override int PKRS_Strain { get => _coreData.PKRS_Strain; set => _coreData.PKRS_Strain = value; }
|
||||
public byte HeightScalar { get => _coreData.HeightScalar; set => _coreData.HeightScalar = value; }
|
||||
public byte WeightScalar { get => _coreData.WeightScalar; set => _coreData.WeightScalar = value; }
|
||||
public override int Stat_HPCurrent { get => _coreData.Stat_HPCurrent; set => _coreData.Stat_HPCurrent = value; }
|
||||
public override int IV_HP { get => _coreData.IV_HP; set => _coreData.IV_HP = value; }
|
||||
public override int IV_ATK { get => _coreData.IV_ATK; set => _coreData.IV_ATK = value; }
|
||||
public override int IV_DEF { get => _coreData.IV_DEF; set => _coreData.IV_DEF = value; }
|
||||
public override int IV_SPE { get => _coreData.IV_SPE; set => _coreData.IV_SPE = value; }
|
||||
public override int IV_SPA { get => _coreData.IV_SPA; set => _coreData.IV_SPA = value; }
|
||||
public override int IV_SPD { get => _coreData.IV_SPD; set => _coreData.IV_SPD = value; }
|
||||
public override bool IsEgg { get => _coreData.IsEgg; set => _coreData.IsEgg = value; }
|
||||
public override bool IsNicknamed { get => _coreData.IsNicknamed; set => _coreData.IsNicknamed = value; }
|
||||
public override int Status_Condition { get => _coreData.Status_Condition; set => _coreData.Status_Condition = value; }
|
||||
public override int HT_Gender { get => _coreData.HT_Gender; set => _coreData.HT_Gender = value; }
|
||||
public byte HT_Language { get => _coreData.HT_Language; set => _coreData.HT_Language = value; }
|
||||
public override int CurrentHandler { get => _coreData.CurrentHandler; set => _coreData.CurrentHandler = value; }
|
||||
public int HT_TrainerID { get => _coreData.HT_TrainerID; set => _coreData.HT_TrainerID = value; }
|
||||
public override int HT_Friendship { get => _coreData.HT_Friendship; set => _coreData.HT_Friendship = value; }
|
||||
public byte HT_Intensity { get => _coreData.HT_Intensity; set => _coreData.HT_Intensity = value; }
|
||||
public byte HT_Memory { get => _coreData.HT_Memory; set => _coreData.HT_Memory = value; }
|
||||
public byte HT_Feeling { get => _coreData.HT_Feeling; set => _coreData.HT_Feeling = value; }
|
||||
public ushort HT_TextVar { get => _coreData.HT_TextVar; set => _coreData.HT_TextVar = value; }
|
||||
public override int Version { get => _coreData.Version; set => _coreData.Version = value; }
|
||||
public byte BattleVersion { get => _coreData.BattleVersion; set => _coreData.BattleVersion = value; }
|
||||
public override int Language { get => _coreData.Language; set => _coreData.Language = value; }
|
||||
public uint FormArgument { get => _coreData.FormArgument; set => _coreData.FormArgument = value; }
|
||||
public byte FormArgumentRemain { get => _coreData.FormArgumentRemain; set => _coreData.FormArgumentRemain = value; }
|
||||
public byte FormArgumentElapsed { get => _coreData.FormArgumentElapsed; set => _coreData.FormArgumentElapsed = value; }
|
||||
public byte FormArgumentMaximum { get => _coreData.FormArgumentMaximum; set => _coreData.FormArgumentMaximum = value; }
|
||||
public sbyte AffixedRibbon { get => _coreData.AffixedRibbon; set => _coreData.AffixedRibbon = value; }
|
||||
public override int OT_Friendship { get => _coreData.OT_Friendship; set => _coreData.OT_Friendship = value; }
|
||||
public byte OT_Intensity { get => _coreData.OT_Intensity; set => _coreData.OT_Intensity = value; }
|
||||
public byte OT_Memory { get => _coreData.OT_Memory; set => _coreData.OT_Memory = value; }
|
||||
public ushort OT_TextVar { get => _coreData.OT_TextVar; set => _coreData.OT_TextVar = value; }
|
||||
public byte OT_Feeling { get => _coreData.OT_Feeling; set => _coreData.OT_Feeling = value; }
|
||||
public override int Egg_Year { get => _coreData.Egg_Year; set => _coreData.Egg_Year = value; }
|
||||
public override int Egg_Month { get => _coreData.Egg_Month; set => _coreData.Egg_Month = value; }
|
||||
public override int Egg_Day { get => _coreData.Egg_Day; set => _coreData.Egg_Day = value; }
|
||||
public override int Met_Year { get => _coreData.Met_Year; set => _coreData.Met_Year = value; }
|
||||
public override int Met_Month { get => _coreData.Met_Month; set => _coreData.Met_Month = value; }
|
||||
public override int Met_Day { get => _coreData.Met_Day; set => _coreData.Met_Day = value; }
|
||||
public override int Met_Level { get => _coreData.Met_Level; set => _coreData.Met_Level = value; }
|
||||
public override int OT_Gender { get => _coreData.OT_Gender; set => _coreData.OT_Gender = value; }
|
||||
public byte HyperTrainFlags { get => _coreData.HyperTrainFlags; set => _coreData.HyperTrainFlags = value; }
|
||||
public bool HT_HP { get => _coreData.HT_HP; set => _coreData.HT_HP = value; }
|
||||
public bool HT_ATK { get => _coreData.HT_ATK; set => _coreData.HT_ATK = value; }
|
||||
public bool HT_DEF { get => _coreData.HT_DEF; set => _coreData.HT_DEF = value; }
|
||||
public bool HT_SPA { get => _coreData.HT_SPA; set => _coreData.HT_SPA = value; }
|
||||
public bool HT_SPD { get => _coreData.HT_SPD; set => _coreData.HT_SPD = value; }
|
||||
public bool HT_SPE { get => _coreData.HT_SPE; set => _coreData.HT_SPE = value; }
|
||||
public override int HeldItem { get => _coreData.HeldItem; set => _coreData.HeldItem = value; }
|
||||
public ulong Tracker { get => Core.Tracker; set => Core.Tracker = value; }
|
||||
public override uint EncryptionConstant { get => Core.EncryptionConstant; set => Core.EncryptionConstant = value; }
|
||||
public bool IsBadEgg { get => Core.IsBadEgg; set => Core.IsBadEgg = value; }
|
||||
public override ushort Species { get => Core.Species; set => Core.Species = value; }
|
||||
public override uint ID32 { get => Core.ID32; set => Core.ID32 = value; }
|
||||
public override ushort TID16 { get => Core.TID16; set => Core.TID16 = value; }
|
||||
public override ushort SID16 { get => Core.SID16; set => Core.SID16 = value; }
|
||||
public override uint EXP { get => Core.EXP; set => Core.EXP = value; }
|
||||
public bool Favorite { get => Core.IsFavorite; set => Core.IsFavorite = value; }
|
||||
public override int MarkValue { get => Core.MarkValue; set => Core.MarkValue = value; }
|
||||
public override uint PID { get => Core.PID; set => Core.PID = value; }
|
||||
public override int Nature { get => Core.Nature; set => Core.Nature = value; }
|
||||
public override int StatNature { get => Core.StatNature; set => Core.StatNature = value; }
|
||||
public override bool FatefulEncounter { get => Core.FatefulEncounter; set => Core.FatefulEncounter = value; }
|
||||
public override int Gender { get => Core.Gender; set => Core.Gender = value; }
|
||||
public override byte Form { get => Core.Form; set => Core.Form = value; }
|
||||
public override int EV_HP { get => Core.EV_HP; set => Core.EV_HP = value; }
|
||||
public override int EV_ATK { get => Core.EV_ATK; set => Core.EV_ATK = value; }
|
||||
public override int EV_DEF { get => Core.EV_DEF; set => Core.EV_DEF = value; }
|
||||
public override int EV_SPE { get => Core.EV_SPE; set => Core.EV_SPE = value; }
|
||||
public override int EV_SPA { get => Core.EV_SPA; set => Core.EV_SPA = value; }
|
||||
public override int EV_SPD { get => Core.EV_SPD; set => Core.EV_SPD = value; }
|
||||
public byte CNT_Cool { get => Core.CNT_Cool; set => Core.CNT_Cool = value; }
|
||||
public byte CNT_Beauty { get => Core.CNT_Beauty; set => Core.CNT_Beauty = value; }
|
||||
public byte CNT_Cute { get => Core.CNT_Cute; set => Core.CNT_Cute = value; }
|
||||
public byte CNT_Smart { get => Core.CNT_Smart; set => Core.CNT_Smart = value; }
|
||||
public byte CNT_Tough { get => Core.CNT_Tough; set => Core.CNT_Tough = value; }
|
||||
public byte CNT_Sheen { get => Core.CNT_Sheen; set => Core.CNT_Sheen = value; }
|
||||
public byte HeightScalar { get => Core.HeightScalar; set => Core.HeightScalar = value; }
|
||||
public byte WeightScalar { get => Core.WeightScalar; set => Core.WeightScalar = value; }
|
||||
public override int Stat_HPCurrent { get => Core.Stat_HPCurrent; set => Core.Stat_HPCurrent = value; }
|
||||
public override int IV_HP { get => Core.IV_HP; set => Core.IV_HP = value; }
|
||||
public override int IV_ATK { get => Core.IV_ATK; set => Core.IV_ATK = value; }
|
||||
public override int IV_DEF { get => Core.IV_DEF; set => Core.IV_DEF = value; }
|
||||
public override int IV_SPE { get => Core.IV_SPE; set => Core.IV_SPE = value; }
|
||||
public override int IV_SPA { get => Core.IV_SPA; set => Core.IV_SPA = value; }
|
||||
public override int IV_SPD { get => Core.IV_SPD; set => Core.IV_SPD = value; }
|
||||
public override bool IsEgg { get => Core.IsEgg; set => Core.IsEgg = value; }
|
||||
public override bool IsNicknamed { get => Core.IsNicknamed; set => Core.IsNicknamed = value; }
|
||||
public override int Status_Condition { get => Core.Status_Condition; set => Core.Status_Condition = value; }
|
||||
public override int HT_Gender { get => Core.HT_Gender; set => Core.HT_Gender = value; }
|
||||
public byte HT_Language { get => Core.HT_Language; set => Core.HT_Language = value; }
|
||||
public override int CurrentHandler { get => Core.CurrentHandler; set => Core.CurrentHandler = value; }
|
||||
public int HT_TrainerID { get => Core.HT_TrainerID; set => Core.HT_TrainerID = value; }
|
||||
public override int HT_Friendship { get => Core.HT_Friendship; set => Core.HT_Friendship = value; }
|
||||
public byte HT_Intensity { get => Core.HT_Intensity; set => Core.HT_Intensity = value; }
|
||||
public byte HT_Memory { get => Core.HT_Memory; set => Core.HT_Memory = value; }
|
||||
public byte HT_Feeling { get => Core.HT_Feeling; set => Core.HT_Feeling = value; }
|
||||
public ushort HT_TextVar { get => Core.HT_TextVar; set => Core.HT_TextVar = value; }
|
||||
public override int Version { get => Core.Version; set => Core.Version = value; }
|
||||
public byte BattleVersion { get => Core.BattleVersion; set => Core.BattleVersion = value; }
|
||||
public override int Language { get => Core.Language; set => Core.Language = value; }
|
||||
public uint FormArgument { get => Core.FormArgument; set => Core.FormArgument = value; }
|
||||
public byte FormArgumentRemain { get => Core.FormArgumentRemain; set => Core.FormArgumentRemain = value; }
|
||||
public byte FormArgumentElapsed { get => Core.FormArgumentElapsed; set => Core.FormArgumentElapsed = value; }
|
||||
public byte FormArgumentMaximum { get => Core.FormArgumentMaximum; set => Core.FormArgumentMaximum = value; }
|
||||
public sbyte AffixedRibbon { get => Core.AffixedRibbon; set => Core.AffixedRibbon = value; }
|
||||
public override int OT_Friendship { get => Core.OT_Friendship; set => Core.OT_Friendship = value; }
|
||||
public byte OT_Intensity { get => Core.OT_Intensity; set => Core.OT_Intensity = value; }
|
||||
public byte OT_Memory { get => Core.OT_Memory; set => Core.OT_Memory = value; }
|
||||
public ushort OT_TextVar { get => Core.OT_TextVar; set => Core.OT_TextVar = value; }
|
||||
public byte OT_Feeling { get => Core.OT_Feeling; set => Core.OT_Feeling = value; }
|
||||
public override int Egg_Year { get => Core.Egg_Year; set => Core.Egg_Year = value; }
|
||||
public override int Egg_Month { get => Core.Egg_Month; set => Core.Egg_Month = value; }
|
||||
public override int Egg_Day { get => Core.Egg_Day; set => Core.Egg_Day = value; }
|
||||
public override int Met_Year { get => Core.Met_Year; set => Core.Met_Year = value; }
|
||||
public override int Met_Month { get => Core.Met_Month; set => Core.Met_Month = value; }
|
||||
public override int Met_Day { get => Core.Met_Day; set => Core.Met_Day = value; }
|
||||
public override int Met_Level { get => Core.Met_Level; set => Core.Met_Level = value; }
|
||||
public override int OT_Gender { get => Core.OT_Gender; set => Core.OT_Gender = value; }
|
||||
public byte HyperTrainFlags { get => Core.HyperTrainFlags; set => Core.HyperTrainFlags = value; }
|
||||
public bool HT_HP { get => Core.HT_HP; set => Core.HT_HP = value; }
|
||||
public bool HT_ATK { get => Core.HT_ATK; set => Core.HT_ATK = value; }
|
||||
public bool HT_DEF { get => Core.HT_DEF; set => Core.HT_DEF = value; }
|
||||
public bool HT_SPA { get => Core.HT_SPA; set => Core.HT_SPA = value; }
|
||||
public bool HT_SPD { get => Core.HT_SPD; set => Core.HT_SPD = value; }
|
||||
public bool HT_SPE { get => Core.HT_SPE; set => Core.HT_SPE = value; }
|
||||
public override int HeldItem { get => Core.HeldItem; set => Core.HeldItem = value; }
|
||||
|
||||
public override string Nickname { get => _coreData.Nickname; set => _coreData.Nickname = value; }
|
||||
public override string OT_Name { get => _coreData.OT_Name; set => _coreData.OT_Name = value; }
|
||||
public override string HT_Name { get => _coreData.HT_Name; set => _coreData.HT_Name = value; }
|
||||
public override string Nickname { get => Core.Nickname; set => Core.Nickname = value; }
|
||||
public override string OT_Name { get => Core.OT_Name; set => Core.OT_Name = value; }
|
||||
public override string HT_Name { get => Core.HT_Name; set => Core.HT_Name = value; }
|
||||
|
||||
public override int MarkingCount => _coreData.MarkingCount;
|
||||
public int RibbonCount => _coreData.RibbonCount;
|
||||
public int MarkCount => _coreData.MarkCount;
|
||||
public int RibbonMarkCount => _coreData.RibbonMarkCount;
|
||||
public override int GetMarking(int index) => _coreData.GetMarking(index);
|
||||
public override void SetMarking(int index, int value) => _coreData.SetMarking(index, value);
|
||||
public override int MarkingCount => Core.MarkingCount;
|
||||
public int RibbonCount => Core.RibbonCount;
|
||||
public int MarkCount => Core.MarkCount;
|
||||
public int RibbonMarkCount => Core.RibbonMarkCount;
|
||||
public override int GetMarking(int index) => Core.GetMarking(index);
|
||||
public override void SetMarking(int index, int value) => Core.SetMarking(index, value);
|
||||
|
||||
#endregion
|
||||
|
||||
// Used to be in Core, now we just don't bother.
|
||||
public override int PKRS_Days { get => 0; set { } }
|
||||
public override int PKRS_Strain { get => 0; set { } }
|
||||
public override int Ability { get => 0; set { } }
|
||||
public override int AbilityNumber { get => 0; set { } }
|
||||
|
||||
#region Calculated
|
||||
|
||||
public override int CurrentFriendship { get => CurrentHandler == 0 ? OT_Friendship : HT_Friendship; set { if (CurrentHandler == 0) OT_Friendship = value; else HT_Friendship = value; } }
|
||||
|
@ -233,12 +248,12 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
public override int MaxAbilityID => Legal.MaxAbilityID_8a;
|
||||
public override int MaxItemID => Legal.MaxItemID_8a;
|
||||
public override int MaxBallID => Legal.MaxBallID_8a;
|
||||
public override int MaxGameID => Legal.MaxGameID_8a;
|
||||
public override int MaxGameID => Legal.MaxGameID_HOME;
|
||||
|
||||
#endregion
|
||||
|
||||
public override int SIZE_PARTY => HomeCrypto.SIZE_1STORED;
|
||||
public override int SIZE_STORED => HomeCrypto.SIZE_1STORED;
|
||||
public override int SIZE_PARTY => HomeCrypto.SIZE_2STORED;
|
||||
public override int SIZE_STORED => HomeCrypto.SIZE_2STORED;
|
||||
public override bool Valid { get => true; set { } }
|
||||
public override PersonalInfo PersonalInfo => LatestGameData.GetPersonalInfo(Species, Form);
|
||||
public override void RefreshChecksum() => Checksum = 0;
|
||||
|
@ -250,8 +265,6 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
return HomeCrypto.Encrypt(result);
|
||||
}
|
||||
|
||||
private const int GameDataStart = HomeCrypto.SIZE_1HEADER + 2 + HomeCrypto.SIZE_1CORE + 2;
|
||||
|
||||
public byte[] Rebuild()
|
||||
{
|
||||
var length = WriteLength;
|
||||
|
@ -267,7 +280,7 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
// Header and Core are already in the current byte array.
|
||||
// Write each part, starting with header and core.
|
||||
int ctr = HomeCrypto.SIZE_1HEADER + 2;
|
||||
ctr += _coreData.WriteTo(span[ctr..]);
|
||||
ctr += Core.WriteTo(span[ctr..]);
|
||||
var gameDataLengthSpan = span[ctr..];
|
||||
int gameDataStart = (ctr += 2);
|
||||
if (DataPK8 is { } pk8) ctr += pk8.WriteTo(span[ctr..]);
|
||||
|
@ -278,9 +291,9 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
WriteUInt16LittleEndian(gameDataLengthSpan, GameDataSize = (ushort)(ctr - gameDataStart));
|
||||
|
||||
// Update metadata to ensure we're a valid object.
|
||||
DataVersion = HomeCrypto.Version1;
|
||||
DataVersion = HomeCrypto.VersionLatest;
|
||||
EncodedDataSize = (ushort)(result.Length - HomeCrypto.SIZE_1HEADER);
|
||||
CoreDataSize = HomeCrypto.SIZE_1CORE;
|
||||
CoreDataSize = (ushort)Core.SerializedSize;
|
||||
Data.AsSpan(0, HomeCrypto.SIZE_1HEADER + 2).CopyTo(span); // Copy updated header & CoreData length.
|
||||
|
||||
return result;
|
||||
|
@ -291,11 +304,11 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
get
|
||||
{
|
||||
var length = GameDataStart;
|
||||
if (DataPK8 is not null) length += HomeOptional1.HeaderSize + HomeCrypto.SIZE_1GAME_PK8;
|
||||
if (DataPB7 is not null) length += HomeOptional1.HeaderSize + HomeCrypto.SIZE_1GAME_PB7;
|
||||
if (DataPA8 is not null) length += HomeOptional1.HeaderSize + HomeCrypto.SIZE_1GAME_PA8;
|
||||
if (DataPB8 is not null) length += HomeOptional1.HeaderSize + HomeCrypto.SIZE_1GAME_PB8;
|
||||
if (DataPK9 is not null) length += HomeOptional1.HeaderSize + HomeCrypto.SIZE_1GAME_PK9;
|
||||
if (DataPK8 is {} k8) length += k8.SerializedSize;
|
||||
if (DataPB7 is {} b7) length += b7.SerializedSize;
|
||||
if (DataPA8 is {} a8) length += a8.SerializedSize;
|
||||
if (DataPB8 is {} b8) length += b8.SerializedSize;
|
||||
if (DataPK9 is {} k9) length += k9.SerializedSize;
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
@ -327,18 +340,77 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat
|
|||
(int)PLA => DataPA8,
|
||||
(int)SL or (int)VL => DataPK9,
|
||||
|
||||
(int)SW or (int)SH when DataPK8 is { Met_Location: HOME_SWLA } => DataPA8,
|
||||
(int)SW or (int)SH when DataPK8 is { Met_Location: HOME_SWBD or HOME_SHSP } => DataPB8,
|
||||
(int)SW or (int)SH => DataPK8,
|
||||
// SW/SH can be confused with others if we didn't seed with the original transfer data.
|
||||
(int)SW or (int)SH => DataPK8 switch
|
||||
{
|
||||
{ Met_Location: LocationsHOME.SWLA } => DataPA8,
|
||||
{ Met_Location: LocationsHOME.SWBD or LocationsHOME.SHSP } => DataPB8,
|
||||
{ Met_Location: LocationsHOME.SWSL or LocationsHOME.SHVL } => DataPK9,
|
||||
_ => DataPK8,
|
||||
},
|
||||
|
||||
_ => DataPK8,
|
||||
_ => DataPK8, // Gen7 and below.
|
||||
};
|
||||
|
||||
public PKM? ConvertToPB7() => DataPB7 is { } x ? x.ConvertToPB7(this) : (DataPB7 ??= GameDataPB7.TryCreate(this))?.ConvertToPB7(this);
|
||||
public PK8? ConvertToPK8() => DataPK8 is { } x ? x.ConvertToPK8(this) : (DataPK8 ??= GameDataPK8.TryCreate(this))?.ConvertToPK8(this);
|
||||
public PB8? ConvertToPB8() => DataPB8 is { } x ? x.ConvertToPB8(this) : (DataPB8 ??= GameDataPB8.TryCreate(this))?.ConvertToPB8(this);
|
||||
public PA8? ConvertToPA8() => DataPA8 is { } x ? x.ConvertToPA8(this) : (DataPA8 ??= GameDataPA8.TryCreate(this))?.ConvertToPA8(this);
|
||||
public PK9? ConvertToPK9() => DataPK9 is { } x ? x.ConvertToPK9(this) : (DataPK9 ??= GameDataPK9.TryCreate(this))?.ConvertToPK9(this);
|
||||
public PB7? ConvertToPB7() => DataPB7 is { } x ? x.ConvertToPKM(this) : (DataPB7 ??= GameDataPB7.TryCreate(this))?.ConvertToPKM(this);
|
||||
public PK8? ConvertToPK8() => DataPK8 is { } x ? x.ConvertToPKM(this) : (DataPK8 ??= GameDataPK8.TryCreate(this))?.ConvertToPKM(this);
|
||||
public PB8? ConvertToPB8() => DataPB8 is { } x ? x.ConvertToPKM(this) : (DataPB8 ??= GameDataPB8.TryCreate(this))?.ConvertToPKM(this);
|
||||
public PA8? ConvertToPA8() => DataPA8 is { } x ? x.ConvertToPKM(this) : (DataPA8 ??= GameDataPA8.TryCreate(this))?.ConvertToPKM(this);
|
||||
public PK9? ConvertToPK9() => DataPK9 is { } x ? x.ConvertToPKM(this) : (DataPK9 ??= GameDataPK9.TryCreate(this))?.ConvertToPKM(this);
|
||||
|
||||
public void CopyTo(PKM pk) => _coreData.CopyTo(pk);
|
||||
public void CopyTo(PKM pk) => Core.CopyTo(pk);
|
||||
|
||||
public static HomeGameDataFormat GetType(Type type)
|
||||
{
|
||||
if (type == typeof(PB7)) return HomeGameDataFormat.PB7;
|
||||
if (type == typeof(PK8)) return HomeGameDataFormat.PK8;
|
||||
if (type == typeof(PB8)) return HomeGameDataFormat.PB8;
|
||||
if (type == typeof(PA8)) return HomeGameDataFormat.PA8;
|
||||
if (type == typeof(PK9)) return HomeGameDataFormat.PK9;
|
||||
return HomeGameDataFormat.None;
|
||||
}
|
||||
|
||||
public PKM? ConvertToPKM(HomeGameDataFormat type) => type switch
|
||||
{
|
||||
HomeGameDataFormat.PB7 => ConvertToPB7(),
|
||||
HomeGameDataFormat.PK8 => ConvertToPK8(),
|
||||
HomeGameDataFormat.PB8 => ConvertToPB8(),
|
||||
HomeGameDataFormat.PA8 => ConvertToPA8(),
|
||||
HomeGameDataFormat.PK9 => ConvertToPK9(),
|
||||
_ => null,
|
||||
};
|
||||
|
||||
public static PKH ConvertFromPKM(PKM pk)
|
||||
{
|
||||
var blank = new PKH();
|
||||
blank.CopyFrom(pk);
|
||||
blank.EnsureScaleSizeExists();
|
||||
if (blank.Species is (int)PKHeX.Core.Species.Arceus or (int)PKHeX.Core.Species.Silvally)
|
||||
blank.Form = 0;
|
||||
return blank;
|
||||
}
|
||||
|
||||
public void CopyFrom(PKM pk)
|
||||
{
|
||||
Core.CopyFrom(pk);
|
||||
if (pk is PB7 pb7) (DataPB7 ??= new GameDataPB7()).CopyFrom(pb7, this);
|
||||
else if (pk is PK8 pk8) (DataPK8 ??= new GameDataPK8()).CopyFrom(pk8, this);
|
||||
else if (pk is PB8 pb8) (DataPB8 ??= new GameDataPB8()).CopyFrom(pb8, this);
|
||||
else if (pk is PA8 pa8) (DataPA8 ??= new GameDataPA8()).CopyFrom(pa8, this);
|
||||
else if (pk is PK9 pk9) (DataPK9 ??= new GameDataPK9()).CopyFrom(pk9, this);
|
||||
}
|
||||
|
||||
private IGameDataSide? FirstScaleData => DataPK9 ?? DataPA8 as IGameDataSide;
|
||||
|
||||
private void EnsureScaleSizeExists()
|
||||
{
|
||||
if (FirstScaleData is IScaledSize3)
|
||||
return; // data exists for scale, keep values.
|
||||
while (HeightScalar == 0 && WeightScalar == 0)
|
||||
{
|
||||
var rnd = Util.Rand;
|
||||
HeightScalar = PokeSizeUtil.GetRandomScalar(rnd);
|
||||
WeightScalar = PokeSizeUtil.GetRandomScalar(rnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ public static class BattleVersionExtensions
|
|||
public static bool IsBattleVersionValid<T>(this T pk, EvolutionHistory h) where T : PKM, IBattleVersion => pk.BattleVersion switch
|
||||
{
|
||||
0 => true,
|
||||
(int)GameVersion.SW or (int)GameVersion.SH => h.HasVisitedSWSH && !(pk.SWSH || pk.BDSP || pk.LA),
|
||||
(int)GameVersion.SW or (int)GameVersion.SH => h.HasVisitedSWSH && !(pk.SWSH || pk.BDSP || pk.LA || pk.SV),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
|
|
@ -126,8 +126,8 @@ public static class FormArgumentUtil
|
|||
(int)Stantler or (int)Wyrdeer when generation >= 8 => 9999,
|
||||
(int)Basculin when form == 2 => 9999, // 294
|
||||
(int)Basculegion => 9999, // 294
|
||||
(int)Primeape or (int)Annihilape when generation >= 9 => 9999,
|
||||
(int)Bisharp or (int)Kingambit when generation >= 9 => 9999,
|
||||
(int)Primeape or (int)Annihilape when generation >= 8 => 9999,
|
||||
(int)Bisharp or (int)Kingambit when generation >= 8 => 9999,
|
||||
(int)Gimmighoul => 998,
|
||||
(int)Gholdengo => 999,
|
||||
(int)Koraidon or (int)Miraidon => 1,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Interface that exposes a <see cref="Tracker"/> for Pokémon HOME.
|
||||
|
@ -10,4 +10,6 @@ public interface IHomeTrack
|
|||
/// Tracker for the associated <see cref="PKM"/>
|
||||
/// </summary>
|
||||
ulong Tracker { get; set; }
|
||||
|
||||
bool HasTracker => Tracker != 0;
|
||||
}
|
||||
|
|
|
@ -144,7 +144,7 @@ public static partial class Extensions
|
|||
return currentLevel <= min;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GetHyperTrainMinLevel(IHyperTrain,EvolutionHistory)"/>
|
||||
/// <inheritdoc cref="GetHyperTrainMinLevel(IHyperTrain,EvolutionHistory, EntityContext)"/>
|
||||
public static int GetHyperTrainMinLevel(this EntityContext c) => c switch
|
||||
{
|
||||
EntityContext.Gen7 or EntityContext.Gen8 or EntityContext.Gen8b => 100,
|
||||
|
@ -157,9 +157,15 @@ public static partial class Extensions
|
|||
/// </summary>
|
||||
/// <param name="_">Entity to train</param>
|
||||
/// <param name="h">History of evolutions present as</param>
|
||||
/// <param name="current">Current context</param>
|
||||
/// <returns>True if available, otherwise false.</returns>
|
||||
public static int GetHyperTrainMinLevel(this IHyperTrain _, EvolutionHistory h)
|
||||
public static int GetHyperTrainMinLevel(this IHyperTrain _, EvolutionHistory h, EntityContext current)
|
||||
{
|
||||
// HOME 3.0.0+ disallows inbound transfers of Hyper Trained Pokémon below level 100.
|
||||
// PokeDupeChecker in BD/SP will DprIllegal if < 100, even if it was legitimately trained in S/V+.
|
||||
if (current == EntityContext.Gen8b)
|
||||
return 100;
|
||||
|
||||
if (h.HasVisitedGen9)
|
||||
return 50;
|
||||
return 100;
|
||||
|
@ -176,7 +182,7 @@ public static partial class Extensions
|
|||
return false;
|
||||
|
||||
// Gated behind level.
|
||||
var min = t.GetHyperTrainMinLevel(h);
|
||||
var min = t.GetHyperTrainMinLevel(h, pk.Context);
|
||||
return pk.CurrentLevel >= min;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Allows resetting the moveset back to an initial state.
|
||||
/// </summary>
|
||||
public interface IMoveReset
|
||||
{
|
||||
/// <summary>
|
||||
/// Resets the current moves to the current level up set.
|
||||
/// </summary>
|
||||
void ResetMoves();
|
||||
}
|
|
@ -86,4 +86,13 @@ public static class TeraTypeUtil
|
|||
/// <param name="t">Entity to set the value to.</param>
|
||||
/// <param name="type">Value to update with.</param>
|
||||
public static void SetTeraType(this ITeraType t, byte type) => t.SetTeraType((MoveType)type);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the preferred Tera Type to set for the given <see cref="IPersonalType"/>.
|
||||
/// </summary>
|
||||
public static MoveType GetTeraTypeImport(byte type1, byte type2)
|
||||
{
|
||||
var type = (MoveType)type1;
|
||||
return type != (byte)MoveType.Normal ? type : (MoveType)type2;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,9 @@ using static System.Buffers.Binary.BinaryPrimitives;
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Generation 8 <see cref="PKM"/> format. </summary>
|
||||
public sealed class PA8 : PKM, ISanityChecksum, IMoveReset,
|
||||
IGanbaru, IAlpha, INoble, ITechRecord, ISociability, IMoveShop8Mastery, IContestStats, IHyperTrain, IScaledSizeValue, IScaledSize3, IGigantamax, IFavorite, IDynamaxLevel, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories,
|
||||
IRibbonIndex, IRibbonSetAffixed, IRibbonSetRibbons, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMarks, IRibbonSetMark8
|
||||
public sealed class PA8 : PKM, ISanityChecksum,
|
||||
IGanbaru, IAlpha, INoble, ITechRecord, ISociability, IMoveShop8Mastery, IContestStats, IHyperTrain, IScaledSizeValue, IScaledSize3, IGigantamax, IFavorite, IDynamaxLevel, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, IPokerusStatus,
|
||||
IRibbonIndex, IRibbonSetAffixed, IRibbonSetRibbons, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMarks, IRibbonSetMark8, IRibbonSetCommon9, IRibbonSetMark9
|
||||
{
|
||||
public override ReadOnlySpan<ushort> ExtraBytes => new ushort[]
|
||||
{
|
||||
|
@ -175,7 +175,7 @@ public sealed class PA8 : PKM, ISanityChecksum, IMoveReset,
|
|||
public byte CNT_Smart { get => Data[0x2F]; set => Data[0x2F] = value; }
|
||||
public byte CNT_Tough { get => Data[0x30]; set => Data[0x30] = value; }
|
||||
public byte CNT_Sheen { get => Data[0x31]; set => Data[0x31] = value; }
|
||||
private byte PKRS { get => Data[0x32]; set => Data[0x32] = value; }
|
||||
public byte PKRS { get => Data[0x32]; set => Data[0x32] = value; }
|
||||
public override int PKRS_Days { get => PKRS & 0xF; set => PKRS = (byte)((PKRS & ~0xF) | value); }
|
||||
public override int PKRS_Strain { get => PKRS >> 4; set => PKRS = (byte)((PKRS & 0xF) | (value << 4)); }
|
||||
// 0x33 unused padding
|
||||
|
@ -296,21 +296,21 @@ public sealed class PA8 : PKM, ISanityChecksum, IMoveReset,
|
|||
public bool RibbonMarkThorny { get => FlagUtil.GetFlag(Data, 0x43, 7); set => FlagUtil.SetFlag(Data, 0x43, 7, value); }
|
||||
// 0x44 Ribbon 2
|
||||
|
||||
public bool RibbonMarkVigor { get => FlagUtil.GetFlag(Data, 0x44, 0); set => FlagUtil.SetFlag(Data, 0x44, 0, value); }
|
||||
public bool RibbonMarkSlump { get => FlagUtil.GetFlag(Data, 0x44, 1); set => FlagUtil.SetFlag(Data, 0x44, 1, value); }
|
||||
public bool RibbonHisui { get => FlagUtil.GetFlag(Data, 0x44, 2); set => FlagUtil.SetFlag(Data, 0x44, 2, value); }
|
||||
public bool RibbonTwinklingStar { get => FlagUtil.GetFlag(Data, 0x44, 3); set => FlagUtil.SetFlag(Data, 0x44, 3, value); }
|
||||
public bool RIB44_4 { get => FlagUtil.GetFlag(Data, 0x44, 4); set => FlagUtil.SetFlag(Data, 0x44, 4, value); }
|
||||
public bool RIB44_5 { get => FlagUtil.GetFlag(Data, 0x44, 5); set => FlagUtil.SetFlag(Data, 0x44, 5, value); }
|
||||
public bool RIB44_6 { get => FlagUtil.GetFlag(Data, 0x44, 6); set => FlagUtil.SetFlag(Data, 0x44, 6, value); }
|
||||
public bool RIB44_7 { get => FlagUtil.GetFlag(Data, 0x44, 7); set => FlagUtil.SetFlag(Data, 0x44, 7, value); }
|
||||
public bool RibbonMarkVigor { get => FlagUtil.GetFlag(Data, 0x44, 0); set => FlagUtil.SetFlag(Data, 0x44, 0, value); }
|
||||
public bool RibbonMarkSlump { get => FlagUtil.GetFlag(Data, 0x44, 1); set => FlagUtil.SetFlag(Data, 0x44, 1, value); }
|
||||
public bool RibbonHisui { get => FlagUtil.GetFlag(Data, 0x44, 2); set => FlagUtil.SetFlag(Data, 0x44, 2, value); }
|
||||
public bool RibbonTwinklingStar { get => FlagUtil.GetFlag(Data, 0x44, 3); set => FlagUtil.SetFlag(Data, 0x44, 3, value); }
|
||||
public bool RibbonChampionPaldea { get => FlagUtil.GetFlag(Data, 0x44, 4); set => FlagUtil.SetFlag(Data, 0x44, 4, value); }
|
||||
public bool RibbonMarkJumbo { get => FlagUtil.GetFlag(Data, 0x44, 5); set => FlagUtil.SetFlag(Data, 0x44, 5, value); }
|
||||
public bool RibbonMarkMini { get => FlagUtil.GetFlag(Data, 0x44, 6); set => FlagUtil.SetFlag(Data, 0x44, 6, value); }
|
||||
public bool RibbonMarkItemfinder { get => FlagUtil.GetFlag(Data, 0x44, 7); set => FlagUtil.SetFlag(Data, 0x44, 7, value); }
|
||||
|
||||
public bool RIB45_0 { get => FlagUtil.GetFlag(Data, 0x45, 0); set => FlagUtil.SetFlag(Data, 0x45, 0, value); }
|
||||
public bool RIB45_1 { get => FlagUtil.GetFlag(Data, 0x45, 1); set => FlagUtil.SetFlag(Data, 0x45, 1, value); }
|
||||
public bool RIB45_2 { get => FlagUtil.GetFlag(Data, 0x45, 2); set => FlagUtil.SetFlag(Data, 0x45, 2, value); }
|
||||
public bool RIB45_3 { get => FlagUtil.GetFlag(Data, 0x45, 3); set => FlagUtil.SetFlag(Data, 0x45, 3, value); }
|
||||
public bool RIB45_4 { get => FlagUtil.GetFlag(Data, 0x45, 4); set => FlagUtil.SetFlag(Data, 0x45, 4, value); }
|
||||
public bool RIB45_5 { get => FlagUtil.GetFlag(Data, 0x45, 5); set => FlagUtil.SetFlag(Data, 0x45, 5, value); }
|
||||
public bool RibbonMarkPartner { get => FlagUtil.GetFlag(Data, 0x45, 0); set => FlagUtil.SetFlag(Data, 0x45, 0, value); }
|
||||
public bool RibbonMarkGourmand { get => FlagUtil.GetFlag(Data, 0x45, 1); set => FlagUtil.SetFlag(Data, 0x45, 1, value); }
|
||||
public bool RibbonOnceInALifetime { get => FlagUtil.GetFlag(Data, 0x45, 2); set => FlagUtil.SetFlag(Data, 0x45, 2, value); }
|
||||
public bool RibbonMarkAlpha { get => FlagUtil.GetFlag(Data, 0x45, 3); set => FlagUtil.SetFlag(Data, 0x45, 3, value); }
|
||||
public bool RibbonMarkMightiest { get => FlagUtil.GetFlag(Data, 0x45, 4); set => FlagUtil.SetFlag(Data, 0x45, 4, value); }
|
||||
public bool RibbonMarkTitan { get => FlagUtil.GetFlag(Data, 0x45, 5); set => FlagUtil.SetFlag(Data, 0x45, 5, value); }
|
||||
public bool RIB45_6 { get => FlagUtil.GetFlag(Data, 0x45, 6); set => FlagUtil.SetFlag(Data, 0x45, 6, value); }
|
||||
public bool RIB45_7 { get => FlagUtil.GetFlag(Data, 0x45, 7); set => FlagUtil.SetFlag(Data, 0x45, 7, value); }
|
||||
|
||||
|
@ -331,15 +331,17 @@ public sealed class PA8 : PKM, ISanityChecksum, IMoveReset,
|
|||
public bool RIB47_5 { get => FlagUtil.GetFlag(Data, 0x47, 5); set => FlagUtil.SetFlag(Data, 0x47, 5, value); }
|
||||
public bool RIB47_6 { get => FlagUtil.GetFlag(Data, 0x47, 6); set => FlagUtil.SetFlag(Data, 0x47, 6, value); }
|
||||
public bool RIB47_7 { get => FlagUtil.GetFlag(Data, 0x47, 7); set => FlagUtil.SetFlag(Data, 0x47, 7, value); }
|
||||
|
||||
|
||||
public int RibbonCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x34)) & 0b00000000_00011111__11111111_11111111__11111111_11111111__11111111_11111111)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000000_00001100__00000000_00000000__00000000_00000000);
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000100_00011100__00000000_00000000__00000000_00000000);
|
||||
public int MarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x34)) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000000_00000011__11111111_11111111__11111111_11111111);
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00111011_11100011__11111111_11111111__11111111_11111111);
|
||||
public int RibbonMarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x34)) & 0b11111111_11111111__11111111_11111111__11111111_11111111__11111111_11111111)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000000_00001111__11111111_11111111__11111111_11111111);
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00111111_11111111__11111111_11111111__11111111_11111111);
|
||||
|
||||
public bool HasMarkEncounter8 => MarkCount != 0;
|
||||
public bool HasMarkEncounter8 => BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x34)) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000000_00000011__11111111_11111111__11111111_11111111) != 0;
|
||||
public bool HasMarkEncounter9 => (Data[0x45] & 0b00111000) != 0;
|
||||
|
||||
public uint Sociability { get => ReadUInt32LittleEndian(Data.AsSpan(0x48)); set => WriteUInt32LittleEndian(Data.AsSpan(0x48), value); }
|
||||
|
||||
|
@ -699,7 +701,7 @@ public sealed class PA8 : PKM, ISanityChecksum, IMoveReset,
|
|||
public override int MaxAbilityID => Legal.MaxAbilityID_8a;
|
||||
public override int MaxItemID => Legal.MaxItemID_8a;
|
||||
public override int MaxBallID => Legal.MaxBallID_8a;
|
||||
public override int MaxGameID => Legal.MaxGameID_8a;
|
||||
public override int MaxGameID => Legal.MaxGameID_HOME;
|
||||
|
||||
public float HeightRatio => GetHeightRatio(HeightScalar);
|
||||
public float WeightRatio => GetWeightRatio(WeightScalar);
|
||||
|
@ -794,244 +796,4 @@ public sealed class PA8 : PKM, ISanityChecksum, IMoveReset,
|
|||
if (permit.IsRecordPermitted(flagIndex))
|
||||
SetMasteredRecordFlag(flagIndex, true);
|
||||
}
|
||||
|
||||
public PK8 ConvertToPK8()
|
||||
{
|
||||
var pk = ConvertTo<PK8>();
|
||||
pk.SanitizeImport();
|
||||
return pk;
|
||||
}
|
||||
|
||||
public PB8 ConvertToPB8()
|
||||
{
|
||||
var pk = ConvertTo<PB8>();
|
||||
if (pk.Egg_Location == 0)
|
||||
pk.Egg_Location = Locations.Default8bNone;
|
||||
return pk;
|
||||
}
|
||||
|
||||
private T ConvertTo<T>() where T : G8PKM, new()
|
||||
{
|
||||
var pk = new T
|
||||
{
|
||||
EncryptionConstant = EncryptionConstant,
|
||||
PID = PID,
|
||||
Species = Species,
|
||||
Form = Form,
|
||||
FormArgument = FormArgument,
|
||||
Gender = Gender,
|
||||
Nature = Nature,
|
||||
StatNature = StatNature,
|
||||
|
||||
TID16 = TID16,
|
||||
SID16 = SID16,
|
||||
EXP = EXP,
|
||||
Ability = Ability,
|
||||
AbilityNumber = AbilityNumber,
|
||||
Language = Language,
|
||||
Version = Version,
|
||||
|
||||
IV_HP = IV_HP,
|
||||
IV_ATK = IV_ATK,
|
||||
IV_DEF = IV_DEF,
|
||||
IV_SPE = IV_SPE,
|
||||
IV_SPA = IV_SPA,
|
||||
IV_SPD = IV_SPD,
|
||||
IsEgg = IsEgg,
|
||||
EV_HP = EV_HP,
|
||||
EV_ATK = EV_ATK,
|
||||
EV_DEF = EV_DEF,
|
||||
EV_SPE = EV_SPE,
|
||||
EV_SPA = EV_SPA,
|
||||
EV_SPD = EV_SPD,
|
||||
|
||||
OT_Gender = OT_Gender,
|
||||
OT_Friendship = OT_Friendship,
|
||||
OT_Intensity = OT_Intensity,
|
||||
OT_Memory = OT_Memory,
|
||||
OT_TextVar = OT_TextVar,
|
||||
OT_Feeling = OT_Feeling,
|
||||
Egg_Year = Egg_Year,
|
||||
Egg_Month = Egg_Month,
|
||||
Egg_Day = Egg_Day,
|
||||
Met_Year = Met_Year,
|
||||
Met_Month = Met_Month,
|
||||
Met_Day = Met_Day,
|
||||
Ball = Ball,
|
||||
Egg_Location = Egg_Location,
|
||||
Met_Location = Met_Location,
|
||||
Met_Level = Met_Level,
|
||||
Tracker = Tracker,
|
||||
|
||||
IsNicknamed = IsNicknamed,
|
||||
CurrentHandler = CurrentHandler,
|
||||
HT_Gender = HT_Gender,
|
||||
HT_Language = HT_Language,
|
||||
HT_Friendship = HT_Friendship,
|
||||
HT_Intensity = HT_Intensity,
|
||||
HT_Memory = HT_Memory,
|
||||
HT_Feeling = HT_Feeling,
|
||||
HT_TextVar = HT_TextVar,
|
||||
|
||||
FatefulEncounter = FatefulEncounter,
|
||||
CNT_Cool = CNT_Cool,
|
||||
CNT_Beauty = CNT_Beauty,
|
||||
CNT_Cute = CNT_Cute,
|
||||
CNT_Smart = CNT_Smart,
|
||||
CNT_Tough = CNT_Tough,
|
||||
CNT_Sheen = CNT_Sheen,
|
||||
|
||||
RibbonChampionKalos = RibbonChampionKalos,
|
||||
RibbonChampionG3 = RibbonChampionG3,
|
||||
RibbonChampionSinnoh = RibbonChampionSinnoh,
|
||||
RibbonBestFriends = RibbonBestFriends,
|
||||
RibbonTraining = RibbonTraining,
|
||||
RibbonBattlerSkillful = RibbonBattlerSkillful,
|
||||
RibbonBattlerExpert = RibbonBattlerExpert,
|
||||
RibbonEffort = RibbonEffort,
|
||||
RibbonAlert = RibbonAlert,
|
||||
RibbonShock = RibbonShock,
|
||||
RibbonDowncast = RibbonDowncast,
|
||||
RibbonCareless = RibbonCareless,
|
||||
RibbonRelax = RibbonRelax,
|
||||
RibbonSnooze = RibbonSnooze,
|
||||
RibbonSmile = RibbonSmile,
|
||||
RibbonGorgeous = RibbonGorgeous,
|
||||
RibbonRoyal = RibbonRoyal,
|
||||
RibbonGorgeousRoyal = RibbonGorgeousRoyal,
|
||||
RibbonArtist = RibbonArtist,
|
||||
RibbonFootprint = RibbonFootprint,
|
||||
RibbonRecord = RibbonRecord,
|
||||
RibbonLegend = RibbonLegend,
|
||||
RibbonCountry = RibbonCountry,
|
||||
RibbonNational = RibbonNational,
|
||||
RibbonEarth = RibbonEarth,
|
||||
RibbonWorld = RibbonWorld,
|
||||
RibbonClassic = RibbonClassic,
|
||||
RibbonPremier = RibbonPremier,
|
||||
RibbonEvent = RibbonEvent,
|
||||
RibbonBirthday = RibbonBirthday,
|
||||
RibbonSpecial = RibbonSpecial,
|
||||
RibbonSouvenir = RibbonSouvenir,
|
||||
RibbonWishing = RibbonWishing,
|
||||
RibbonChampionBattle = RibbonChampionBattle,
|
||||
RibbonChampionRegional = RibbonChampionRegional,
|
||||
RibbonChampionNational = RibbonChampionNational,
|
||||
RibbonChampionWorld = RibbonChampionWorld,
|
||||
HasContestMemoryRibbon = HasContestMemoryRibbon,
|
||||
HasBattleMemoryRibbon = HasBattleMemoryRibbon,
|
||||
RibbonChampionG6Hoenn = RibbonChampionG6Hoenn,
|
||||
RibbonContestStar = RibbonContestStar,
|
||||
RibbonMasterCoolness = RibbonMasterCoolness,
|
||||
RibbonMasterBeauty = RibbonMasterBeauty,
|
||||
RibbonMasterCuteness = RibbonMasterCuteness,
|
||||
RibbonMasterCleverness = RibbonMasterCleverness,
|
||||
RibbonMasterToughness = RibbonMasterToughness,
|
||||
RibbonChampionAlola = RibbonChampionAlola,
|
||||
RibbonBattleRoyale = RibbonBattleRoyale,
|
||||
RibbonBattleTreeGreat = RibbonBattleTreeGreat,
|
||||
RibbonBattleTreeMaster = RibbonBattleTreeMaster,
|
||||
RibbonChampionGalar = RibbonChampionGalar,
|
||||
RibbonTowerMaster = RibbonTowerMaster,
|
||||
RibbonMasterRank = RibbonMasterRank,
|
||||
|
||||
RibbonMarkLunchtime = RibbonMarkLunchtime,
|
||||
RibbonMarkSleepyTime = RibbonMarkSleepyTime,
|
||||
RibbonMarkDusk = RibbonMarkDusk,
|
||||
RibbonMarkDawn = RibbonMarkDawn,
|
||||
RibbonMarkCloudy = RibbonMarkCloudy,
|
||||
RibbonMarkRainy = RibbonMarkRainy,
|
||||
RibbonMarkStormy = RibbonMarkStormy,
|
||||
RibbonMarkSnowy = RibbonMarkSnowy,
|
||||
RibbonMarkBlizzard = RibbonMarkBlizzard,
|
||||
RibbonMarkDry = RibbonMarkDry,
|
||||
RibbonMarkSandstorm = RibbonMarkSandstorm,
|
||||
RibbonCountMemoryContest = RibbonCountMemoryContest,
|
||||
RibbonCountMemoryBattle = RibbonCountMemoryBattle,
|
||||
RibbonMarkMisty = RibbonMarkMisty,
|
||||
RibbonMarkDestiny = RibbonMarkDestiny,
|
||||
RibbonMarkFishing = RibbonMarkFishing,
|
||||
RibbonMarkCurry = RibbonMarkCurry,
|
||||
RibbonMarkUncommon = RibbonMarkUncommon,
|
||||
RibbonMarkRare = RibbonMarkRare,
|
||||
RibbonMarkRowdy = RibbonMarkRowdy,
|
||||
RibbonMarkAbsentMinded = RibbonMarkAbsentMinded,
|
||||
RibbonMarkJittery = RibbonMarkJittery,
|
||||
RibbonMarkExcited = RibbonMarkExcited,
|
||||
RibbonMarkCharismatic = RibbonMarkCharismatic,
|
||||
RibbonMarkCalmness = RibbonMarkCalmness,
|
||||
RibbonMarkIntense = RibbonMarkIntense,
|
||||
RibbonMarkZonedOut = RibbonMarkZonedOut,
|
||||
RibbonMarkJoyful = RibbonMarkJoyful,
|
||||
RibbonMarkAngry = RibbonMarkAngry,
|
||||
RibbonMarkSmiley = RibbonMarkSmiley,
|
||||
RibbonMarkTeary = RibbonMarkTeary,
|
||||
RibbonMarkUpbeat = RibbonMarkUpbeat,
|
||||
RibbonMarkPeeved = RibbonMarkPeeved,
|
||||
RibbonMarkIntellectual = RibbonMarkIntellectual,
|
||||
RibbonMarkFerocious = RibbonMarkFerocious,
|
||||
RibbonMarkCrafty = RibbonMarkCrafty,
|
||||
RibbonMarkScowling = RibbonMarkScowling,
|
||||
RibbonMarkKindly = RibbonMarkKindly,
|
||||
RibbonMarkFlustered = RibbonMarkFlustered,
|
||||
RibbonMarkPumpedUp = RibbonMarkPumpedUp,
|
||||
RibbonMarkZeroEnergy = RibbonMarkZeroEnergy,
|
||||
RibbonMarkPrideful = RibbonMarkPrideful,
|
||||
RibbonMarkUnsure = RibbonMarkUnsure,
|
||||
RibbonMarkHumble = RibbonMarkHumble,
|
||||
RibbonMarkThorny = RibbonMarkThorny,
|
||||
RibbonMarkVigor = RibbonMarkVigor,
|
||||
RibbonMarkSlump = RibbonMarkSlump,
|
||||
RibbonHisui = RibbonHisui,
|
||||
RibbonTwinklingStar = RibbonTwinklingStar,
|
||||
|
||||
AffixedRibbon = AffixedRibbon,
|
||||
HyperTrainFlags = HyperTrainFlags,
|
||||
|
||||
Sociability = Sociability,
|
||||
Fullness = Fullness,
|
||||
Enjoyment = Enjoyment,
|
||||
BattleVersion = BattleVersion,
|
||||
PKRS_Days = PKRS_Days,
|
||||
PKRS_Strain = PKRS_Strain,
|
||||
HeightScalar = HeightScalar,
|
||||
WeightScalar = WeightScalar,
|
||||
CanGigantamax = CanGigantamax,
|
||||
DynamaxLevel = DynamaxLevel,
|
||||
|
||||
IsFavorite = IsFavorite,
|
||||
MarkValue = MarkValue,
|
||||
};
|
||||
|
||||
Nickname_Trash.CopyTo(pk.Nickname_Trash);
|
||||
OT_Trash.CopyTo(pk.OT_Trash);
|
||||
HT_Trash.CopyTo(pk.HT_Trash);
|
||||
pk.ResetMoves();
|
||||
pk.ResetPartyStats();
|
||||
pk.RefreshChecksum();
|
||||
|
||||
return pk;
|
||||
}
|
||||
|
||||
public void SanitizeImport()
|
||||
{
|
||||
Scale = HeightScalar;
|
||||
ResetHeight();
|
||||
ResetWeight();
|
||||
}
|
||||
|
||||
public void ResetMoves()
|
||||
{
|
||||
var learn = LearnSource8LA.Instance.GetLearnset(Species, Form);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
learn.SetEncounterMoves(CurrentLevel, moves);
|
||||
SetMoves(moves);
|
||||
this.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
||||
public PK9 ConvertToPK9()
|
||||
{
|
||||
// Todo: Transfer to PK9
|
||||
return new PK9();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -609,79 +609,4 @@ public sealed class PB7 : G6PKM, IHyperTrain, IAwakened, IScaledSizeValue, IComb
|
|||
5 => 4,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(characterIndex)), // never happens, characteristic is always 0-29
|
||||
};
|
||||
|
||||
public PK8 ConvertToPK8()
|
||||
{
|
||||
var pk8 = new PK8
|
||||
{
|
||||
EncryptionConstant = EncryptionConstant,
|
||||
Species = Species,
|
||||
TID16 = TID16,
|
||||
SID16 = SID16,
|
||||
EXP = EXP,
|
||||
PID = PID,
|
||||
Ability = Ability,
|
||||
AbilityNumber = AbilityNumber,
|
||||
MarkValue = MarkValue & 0b1111_1111_1111,
|
||||
Language = Language,
|
||||
EV_HP = EV_HP,
|
||||
EV_ATK = EV_ATK,
|
||||
EV_DEF = EV_DEF,
|
||||
EV_SPA = EV_SPA,
|
||||
EV_SPD = EV_SPD,
|
||||
EV_SPE = EV_SPE,
|
||||
Move1 = Move1,
|
||||
Move2 = Move2,
|
||||
Move3 = Move3,
|
||||
Move4 = Move4,
|
||||
Move1_PPUps = Move1_PPUps,
|
||||
Move2_PPUps = Move2_PPUps,
|
||||
Move3_PPUps = Move3_PPUps,
|
||||
Move4_PPUps = Move4_PPUps,
|
||||
RelearnMove1 = RelearnMove1,
|
||||
RelearnMove2 = RelearnMove2,
|
||||
RelearnMove3 = RelearnMove3,
|
||||
RelearnMove4 = RelearnMove4,
|
||||
IV_HP = IV_HP,
|
||||
IV_ATK = IV_ATK,
|
||||
IV_DEF = IV_DEF,
|
||||
IV_SPA = IV_SPA,
|
||||
IV_SPD = IV_SPD,
|
||||
IV_SPE = IV_SPE,
|
||||
IsNicknamed = IsNicknamed,
|
||||
FatefulEncounter = FatefulEncounter,
|
||||
Gender = Gender,
|
||||
Form = Form,
|
||||
Nature = Nature,
|
||||
Nickname = Nickname,
|
||||
Version = Version,
|
||||
OT_Name = OT_Name,
|
||||
MetDate = MetDate,
|
||||
Met_Location = Met_Location,
|
||||
Ball = Ball,
|
||||
Met_Level = Met_Level,
|
||||
OT_Gender = OT_Gender,
|
||||
HyperTrainFlags = HyperTrainFlags,
|
||||
|
||||
// Memories don't exist in LGPE, and no memories are set on transfer.
|
||||
|
||||
OT_Friendship = OT_Friendship,
|
||||
|
||||
// No Ribbons or Markings on transfer.
|
||||
|
||||
StatNature = Nature,
|
||||
HeightScalar = HeightScalar,
|
||||
WeightScalar = WeightScalar,
|
||||
|
||||
IsFavorite = IsFavorite,
|
||||
};
|
||||
|
||||
// Fix PP and Stats
|
||||
pk8.Heal();
|
||||
|
||||
// Fix Checksum
|
||||
pk8.RefreshChecksum();
|
||||
|
||||
return pk8; // Done!
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,39 +124,9 @@ public sealed class PB8 : G8PKM
|
|||
public override int MaxAbilityID => Legal.MaxAbilityID_8b;
|
||||
public override int MaxItemID => Legal.MaxItemID_8b;
|
||||
public override int MaxBallID => Legal.MaxBallID_8b;
|
||||
public override int MaxGameID => Legal.MaxGameID_8b;
|
||||
public override int MaxGameID => Legal.MaxGameID_HOME;
|
||||
|
||||
public override bool WasEgg => IsEgg || Egg_Day != 0;
|
||||
|
||||
public PK8 ConvertToPK8()
|
||||
{
|
||||
var pk = ConvertTo<PK8>();
|
||||
pk.SanitizeImport();
|
||||
return pk;
|
||||
}
|
||||
|
||||
public override PA8 ConvertToPA8()
|
||||
{
|
||||
var pk = base.ConvertToPA8();
|
||||
if (pk.Egg_Location == Locations.Default8bNone)
|
||||
pk.Egg_Location = 0;
|
||||
return pk;
|
||||
}
|
||||
|
||||
public override bool HasOriginalMetLocation => base.HasOriginalMetLocation && !(LA && Met_Location == Locations.HOME_SWLA);
|
||||
|
||||
public override void ResetMoves()
|
||||
{
|
||||
var learn = LearnSource8BDSP.Instance.GetLearnset(Species, Form);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
learn.SetEncounterMoves(CurrentLevel, moves);
|
||||
SetMoves(moves);
|
||||
this.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
||||
public PK9 ConvertToPK9()
|
||||
{
|
||||
// Todo: Transfer to PK9
|
||||
return new PK9();
|
||||
}
|
||||
public override bool HasOriginalMetLocation => base.HasOriginalMetLocation && !(LA && Met_Location == LocationsHOME.SWLA);
|
||||
}
|
||||
|
|
|
@ -105,88 +105,9 @@ public sealed class PK8 : G8PKM
|
|||
public override int MaxItemID => Legal.MaxItemID_8;
|
||||
public override int MaxBallID => Legal.MaxBallID_8;
|
||||
public override int MaxGameID => Legal.MaxGameID_8;
|
||||
|
||||
public PB8 ConvertToPB8()
|
||||
{
|
||||
var pk = ConvertTo<PB8>();
|
||||
if (pk.Egg_Location == 0)
|
||||
pk.Egg_Location = Locations.Default8bNone;
|
||||
UnmapLocation(pk);
|
||||
return pk;
|
||||
}
|
||||
|
||||
public override PA8 ConvertToPA8()
|
||||
{
|
||||
var pk = base.ConvertToPA8();
|
||||
UnmapLocation(pk);
|
||||
return pk;
|
||||
}
|
||||
|
||||
private static void UnmapLocation(PKM pk)
|
||||
{
|
||||
switch (pk.Met_Location)
|
||||
{
|
||||
case Locations.HOME_SWLA:
|
||||
pk.Version = (int)GameVersion.PLA;
|
||||
// Keep location due to bad transfer logic (official) -- server legal.
|
||||
break;
|
||||
case Locations.HOME_SWBD:
|
||||
pk.Version = (int)GameVersion.BD;
|
||||
pk.Met_Location = 0; // Load whatever value from the server. We don't know.
|
||||
break;
|
||||
case Locations.HOME_SHSP:
|
||||
pk.Version = (int)GameVersion.SP;
|
||||
pk.Met_Location = 0; // Load whatever value from the server. We don't know.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void ResetMoves()
|
||||
{
|
||||
var learn = LearnSource8SWSH.Instance.GetLearnset(Species, Form);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
learn.SetEncounterMoves(CurrentLevel, moves);
|
||||
SetMoves(moves);
|
||||
this.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
||||
public bool IsSideTransfer => Met_Location is Locations.HOME_SHSP or Locations.HOME_SWBD or Locations.HOME_SWLA;
|
||||
public override bool BDSP => Met_Location is Locations.HOME_SWBD or Locations.HOME_SHSP;
|
||||
public override bool LA => Met_Location is Locations.HOME_SWLA;
|
||||
public bool IsSideTransfer => LocationsHOME.IsLocationSWSH(Met_Location);
|
||||
public override bool SV => Met_Location is LocationsHOME.SWSL or LocationsHOME.SHVL;
|
||||
public override bool BDSP => Met_Location is LocationsHOME.SWBD or LocationsHOME.SHSP;
|
||||
public override bool LA => Met_Location is LocationsHOME.SWLA;
|
||||
public override bool HasOriginalMetLocation => base.HasOriginalMetLocation && !(BDSP || LA);
|
||||
|
||||
public void SanitizeImport()
|
||||
{
|
||||
// BDSP->SWSH: Set the Met Location to the magic Location, set the Egg Location to 0 if -1, otherwise BDSPEgg (0 is a valid location, but no eggs can be EggMet there -- only hatched.)
|
||||
// PLA->SWSH: Set the Met Location to the magic Location, set the Egg Location to 0 (no eggs in game).
|
||||
var ver = Version;
|
||||
if (ver is (int)GameVersion.SP)
|
||||
{
|
||||
Version = (int)GameVersion.SH;
|
||||
Met_Location = Locations.HOME_SHSP;
|
||||
Egg_Location = Egg_Location == Locations.Default8bNone ? 0 : Locations.HOME_SWSHBDSPEgg;
|
||||
}
|
||||
else if (ver is (int)GameVersion.BD)
|
||||
{
|
||||
Version = (int)GameVersion.SW;
|
||||
Met_Location = Locations.HOME_SWBD;
|
||||
Egg_Location = Egg_Location == Locations.Default8bNone ? 0 : Locations.HOME_SWSHBDSPEgg;
|
||||
}
|
||||
else if (ver is (int)GameVersion.PLA)
|
||||
{
|
||||
const ushort met = Locations.HOME_SWLA;
|
||||
Version = (int)GameVersion.SW;
|
||||
Met_Location = met;
|
||||
Egg_Location = 0; // Everything originating from this game has an Egg Location of 0.
|
||||
}
|
||||
|
||||
if (Ball > (int)Core.Ball.Beast)
|
||||
Ball = (int)Core.Ball.Poke;
|
||||
}
|
||||
|
||||
public PK9 ConvertToPK9()
|
||||
{
|
||||
// Todo: Transfer to PK9
|
||||
return new PK9();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ using static System.Buffers.Binary.BinaryPrimitives;
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Generation 9 <see cref="PKM"/> format. </summary>
|
||||
public sealed class PK9 : PKM, ISanityChecksum, ITeraType, IMoveReset, ITechRecord, IObedienceLevel,
|
||||
public sealed class PK9 : PKM, ISanityChecksum, ITeraType, ITechRecord, IObedienceLevel,
|
||||
IContestStats, IHyperTrain, IScaledSize, IScaledSize3, IFavorite, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories,
|
||||
IRibbonIndex, IRibbonSetAffixed, IRibbonSetRibbons, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetCommon9, IRibbonSetMarks, IRibbonSetMark8, IRibbonSetMark9
|
||||
{
|
||||
|
@ -608,20 +608,11 @@ public sealed class PK9 : PKM, ISanityChecksum, ITeraType, IMoveReset, ITechReco
|
|||
HT_Language = (byte)tr.Language;
|
||||
}
|
||||
|
||||
public void ResetMoves()
|
||||
{
|
||||
var learn = LearnSource9SV.Instance.GetLearnset(Species, Form);
|
||||
Span<ushort> moves = stackalloc ushort[4];
|
||||
learn.SetEncounterMoves(CurrentLevel, moves);
|
||||
SetMoves(moves);
|
||||
this.SetMaximumPPCurrent(moves);
|
||||
}
|
||||
|
||||
// Maximums
|
||||
public override ushort MaxMoveID => Legal.MaxMoveID_9;
|
||||
public override ushort MaxSpeciesID => Legal.MaxSpeciesID_9;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_9;
|
||||
public override int MaxItemID => Legal.MaxItemID_9;
|
||||
public override int MaxBallID => Legal.MaxBallID_9;
|
||||
public override int MaxGameID => Legal.MaxGameID_9;
|
||||
public override int MaxGameID => Legal.MaxGameID_HOME;
|
||||
}
|
||||
|
|
|
@ -282,7 +282,7 @@ public abstract class PKM : ISpeciesForm, ITrainerID32, IGeneration, IShiny, ILa
|
|||
public bool SWSH => Version is (int)SW or (int)SH;
|
||||
public virtual bool BDSP => Version is (int)BD or (int)SP;
|
||||
public virtual bool LA => Version is (int)PLA;
|
||||
public bool SV => Version is (int)SL or (int)VL;
|
||||
public virtual bool SV => Version is (int)SL or (int)VL;
|
||||
|
||||
public bool GO_LGPE => GO && Met_Location == Locations.GO7;
|
||||
public bool GO_HOME => GO && Met_Location == Locations.GO8;
|
||||
|
|
|
@ -5,15 +5,13 @@ using static System.Buffers.Binary.BinaryPrimitives;
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Generation 8 <see cref="PKM"/> format. </summary>
|
||||
public abstract class G8PKM : PKM, ISanityChecksum, IMoveReset,
|
||||
ITechRecord, ISociability, IContestStats, IHyperTrain, IScaledSize, IGigantamax, IFavorite, IDynamaxLevel, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories,
|
||||
IRibbonIndex, IRibbonSetAffixed, IRibbonSetRibbons, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMarks, IRibbonSetMark8
|
||||
public abstract class G8PKM : PKM, ISanityChecksum,
|
||||
ITechRecord, ISociability, IContestStats, IHyperTrain, IScaledSize, IGigantamax, IFavorite, IDynamaxLevel, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, IPokerusStatus,
|
||||
IRibbonIndex, IRibbonSetAffixed, IRibbonSetRibbons, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetCommon9, IRibbonSetMarks, IRibbonSetMark8, IRibbonSetMark9
|
||||
{
|
||||
protected G8PKM() : base(PokeCrypto.SIZE_8PARTY) { }
|
||||
protected G8PKM(byte[] data) : base(DecryptParty(data)) { }
|
||||
|
||||
public abstract void ResetMoves();
|
||||
|
||||
private static byte[] DecryptParty(byte[] data)
|
||||
{
|
||||
PokeCrypto.DecryptIfEncrypted8(ref data);
|
||||
|
@ -151,7 +149,7 @@ public abstract class G8PKM : PKM, ISanityChecksum, IMoveReset,
|
|||
public byte CNT_Smart { get => Data[0x2F]; set => Data[0x2F] = value; }
|
||||
public byte CNT_Tough { get => Data[0x30]; set => Data[0x30] = value; }
|
||||
public byte CNT_Sheen { get => Data[0x31]; set => Data[0x31] = value; }
|
||||
private byte PKRS { get => Data[0x32]; set => Data[0x32] = value; }
|
||||
public byte PKRS { get => Data[0x32]; set => Data[0x32] = value; }
|
||||
public override int PKRS_Days { get => PKRS & 0xF; set => PKRS = (byte)((PKRS & ~0xF) | value); }
|
||||
public override int PKRS_Strain { get => PKRS >> 4; set => PKRS = (byte)((PKRS & 0xF) | (value << 4)); }
|
||||
// 0x33 unused padding
|
||||
|
@ -272,21 +270,21 @@ public abstract class G8PKM : PKM, ISanityChecksum, IMoveReset,
|
|||
public bool RibbonMarkThorny { get => FlagUtil.GetFlag(Data, 0x43, 7); set => FlagUtil.SetFlag(Data, 0x43, 7, value); }
|
||||
// 0x44 Ribbon 2
|
||||
|
||||
public bool RibbonMarkVigor { get => FlagUtil.GetFlag(Data, 0x44, 0); set => FlagUtil.SetFlag(Data, 0x44, 0, value); }
|
||||
public bool RibbonMarkSlump { get => FlagUtil.GetFlag(Data, 0x44, 1); set => FlagUtil.SetFlag(Data, 0x44, 1, value); }
|
||||
public bool RibbonHisui { get => FlagUtil.GetFlag(Data, 0x44, 2); set => FlagUtil.SetFlag(Data, 0x44, 2, value); }
|
||||
public bool RibbonTwinklingStar { get => FlagUtil.GetFlag(Data, 0x44, 3); set => FlagUtil.SetFlag(Data, 0x44, 3, value); }
|
||||
public bool RIB44_4 { get => FlagUtil.GetFlag(Data, 0x44, 4); set => FlagUtil.SetFlag(Data, 0x44, 4, value); }
|
||||
public bool RIB44_5 { get => FlagUtil.GetFlag(Data, 0x44, 5); set => FlagUtil.SetFlag(Data, 0x44, 5, value); }
|
||||
public bool RIB44_6 { get => FlagUtil.GetFlag(Data, 0x44, 6); set => FlagUtil.SetFlag(Data, 0x44, 6, value); }
|
||||
public bool RIB44_7 { get => FlagUtil.GetFlag(Data, 0x44, 7); set => FlagUtil.SetFlag(Data, 0x44, 7, value); }
|
||||
public bool RibbonMarkVigor { get => FlagUtil.GetFlag(Data, 0x44, 0); set => FlagUtil.SetFlag(Data, 0x44, 0, value); }
|
||||
public bool RibbonMarkSlump { get => FlagUtil.GetFlag(Data, 0x44, 1); set => FlagUtil.SetFlag(Data, 0x44, 1, value); }
|
||||
public bool RibbonHisui { get => FlagUtil.GetFlag(Data, 0x44, 2); set => FlagUtil.SetFlag(Data, 0x44, 2, value); }
|
||||
public bool RibbonTwinklingStar { get => FlagUtil.GetFlag(Data, 0x44, 3); set => FlagUtil.SetFlag(Data, 0x44, 3, value); }
|
||||
public bool RibbonChampionPaldea { get => FlagUtil.GetFlag(Data, 0x44, 4); set => FlagUtil.SetFlag(Data, 0x44, 4, value); }
|
||||
public bool RibbonMarkJumbo { get => FlagUtil.GetFlag(Data, 0x44, 5); set => FlagUtil.SetFlag(Data, 0x44, 5, value); }
|
||||
public bool RibbonMarkMini { get => FlagUtil.GetFlag(Data, 0x44, 6); set => FlagUtil.SetFlag(Data, 0x44, 6, value); }
|
||||
public bool RibbonMarkItemfinder { get => FlagUtil.GetFlag(Data, 0x44, 7); set => FlagUtil.SetFlag(Data, 0x44, 7, value); }
|
||||
|
||||
public bool RIB45_0 { get => FlagUtil.GetFlag(Data, 0x45, 0); set => FlagUtil.SetFlag(Data, 0x45, 0, value); }
|
||||
public bool RIB45_1 { get => FlagUtil.GetFlag(Data, 0x45, 1); set => FlagUtil.SetFlag(Data, 0x45, 1, value); }
|
||||
public bool RIB45_2 { get => FlagUtil.GetFlag(Data, 0x45, 2); set => FlagUtil.SetFlag(Data, 0x45, 2, value); }
|
||||
public bool RIB45_3 { get => FlagUtil.GetFlag(Data, 0x45, 3); set => FlagUtil.SetFlag(Data, 0x45, 3, value); }
|
||||
public bool RIB45_4 { get => FlagUtil.GetFlag(Data, 0x45, 4); set => FlagUtil.SetFlag(Data, 0x45, 4, value); }
|
||||
public bool RIB45_5 { get => FlagUtil.GetFlag(Data, 0x45, 5); set => FlagUtil.SetFlag(Data, 0x45, 5, value); }
|
||||
public bool RibbonMarkPartner { get => FlagUtil.GetFlag(Data, 0x45, 0); set => FlagUtil.SetFlag(Data, 0x45, 0, value); }
|
||||
public bool RibbonMarkGourmand { get => FlagUtil.GetFlag(Data, 0x45, 1); set => FlagUtil.SetFlag(Data, 0x45, 1, value); }
|
||||
public bool RibbonOnceInALifetime { get => FlagUtil.GetFlag(Data, 0x45, 2); set => FlagUtil.SetFlag(Data, 0x45, 2, value); }
|
||||
public bool RibbonMarkAlpha { get => FlagUtil.GetFlag(Data, 0x45, 3); set => FlagUtil.SetFlag(Data, 0x45, 3, value); }
|
||||
public bool RibbonMarkMightiest { get => FlagUtil.GetFlag(Data, 0x45, 4); set => FlagUtil.SetFlag(Data, 0x45, 4, value); }
|
||||
public bool RibbonMarkTitan { get => FlagUtil.GetFlag(Data, 0x45, 5); set => FlagUtil.SetFlag(Data, 0x45, 5, value); }
|
||||
public bool RIB45_6 { get => FlagUtil.GetFlag(Data, 0x45, 6); set => FlagUtil.SetFlag(Data, 0x45, 6, value); }
|
||||
public bool RIB45_7 { get => FlagUtil.GetFlag(Data, 0x45, 7); set => FlagUtil.SetFlag(Data, 0x45, 7, value); }
|
||||
|
||||
|
@ -309,13 +307,15 @@ public abstract class G8PKM : PKM, ISanityChecksum, IMoveReset,
|
|||
public bool RIB47_7 { get => FlagUtil.GetFlag(Data, 0x47, 7); set => FlagUtil.SetFlag(Data, 0x47, 7, value); }
|
||||
|
||||
public int RibbonCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x34)) & 0b00000000_00011111__11111111_11111111__11111111_11111111__11111111_11111111)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000000_00001100__00000000_00000000__00000000_00000000);
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000100_00011100__00000000_00000000__00000000_00000000);
|
||||
public int MarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x34)) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000000_00000011__11111111_11111111__11111111_11111111);
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00111011_11100011__11111111_11111111__11111111_11111111);
|
||||
public int RibbonMarkCount => BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x34)) & 0b11111111_11111111__11111111_11111111__11111111_11111111__11111111_11111111)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000000_00001111__11111111_11111111__11111111_11111111);
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00111111_11111111__11111111_11111111__11111111_11111111);
|
||||
|
||||
public bool HasMarkEncounter8 => MarkCount != 0;
|
||||
public bool HasMarkEncounter8 => BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x34)) & 0b11111111_11100000__00000000_00000000__00000000_00000000__00000000_00000000)
|
||||
+ BitOperations.PopCount(ReadUInt64LittleEndian(Data.AsSpan(0x40)) & 0b00000000_00000000__00000000_00000011__11111111_11111111__11111111_11111111) != 0;
|
||||
public bool HasMarkEncounter9 => (Data[0x45] & 0b00111000) != 0;
|
||||
|
||||
public uint Sociability { get => ReadUInt32LittleEndian(Data.AsSpan(0x48)); set => WriteUInt32LittleEndian(Data.AsSpan(0x48), value); }
|
||||
|
||||
|
@ -504,227 +504,4 @@ public abstract class G8PKM : PKM, ISanityChecksum, IMoveReset,
|
|||
index -= 64;
|
||||
return 0x40 + (index >> 3);
|
||||
}
|
||||
|
||||
protected T ConvertTo<T>() where T : G8PKM, new()
|
||||
{
|
||||
var pk = new T();
|
||||
Data.AsSpan().CopyTo(pk.Data);
|
||||
pk.Move1_PPUps = pk.Move2_PPUps = pk.Move3_PPUps = pk.Move4_PPUps = 0;
|
||||
pk.RelearnMove1 = pk.RelearnMove2 = pk.RelearnMove3 = pk.RelearnMove4 = 0;
|
||||
pk.ClearMoveRecordFlags();
|
||||
pk.ClearPokeJobFlags();
|
||||
|
||||
pk.CanGigantamax = false;
|
||||
pk.DynamaxLevel = 0;
|
||||
pk.Sociability = 0;
|
||||
pk.Fullness = 0;
|
||||
pk.Data[0x52] = 0; // BD/SP IsDprIllegal
|
||||
|
||||
pk.ResetMoves();
|
||||
pk.ResetPartyStats();
|
||||
pk.RefreshChecksum();
|
||||
|
||||
return pk;
|
||||
}
|
||||
|
||||
public virtual PA8 ConvertToPA8()
|
||||
{
|
||||
var pk = new PA8
|
||||
{
|
||||
EncryptionConstant = EncryptionConstant,
|
||||
PID = PID,
|
||||
Species = Species,
|
||||
Form = Form,
|
||||
FormArgument = FormArgument,
|
||||
Gender = Gender,
|
||||
Nature = Nature,
|
||||
StatNature = StatNature,
|
||||
|
||||
TID16 = TID16,
|
||||
SID16 = SID16,
|
||||
EXP = EXP,
|
||||
Ability = Ability,
|
||||
AbilityNumber = AbilityNumber,
|
||||
Language = Language,
|
||||
Version = Version,
|
||||
|
||||
IV_HP = IV_HP,
|
||||
IV_ATK = IV_ATK,
|
||||
IV_DEF = IV_DEF,
|
||||
IV_SPE = IV_SPE,
|
||||
IV_SPA = IV_SPA,
|
||||
IV_SPD = IV_SPD,
|
||||
IsEgg = IsEgg,
|
||||
EV_HP = EV_HP,
|
||||
EV_ATK = EV_ATK,
|
||||
EV_DEF = EV_DEF,
|
||||
EV_SPE = EV_SPE,
|
||||
EV_SPA = EV_SPA,
|
||||
EV_SPD = EV_SPD,
|
||||
|
||||
OT_Gender = OT_Gender,
|
||||
OT_Friendship = OT_Friendship,
|
||||
OT_Intensity = OT_Intensity,
|
||||
OT_Memory = OT_Memory,
|
||||
OT_TextVar = OT_TextVar,
|
||||
OT_Feeling = OT_Feeling,
|
||||
Egg_Year = Egg_Year,
|
||||
Egg_Month = Egg_Month,
|
||||
Egg_Day = Egg_Day,
|
||||
Met_Year = Met_Year,
|
||||
Met_Month = Met_Month,
|
||||
Met_Day = Met_Day,
|
||||
Ball = Ball,
|
||||
Egg_Location = Egg_Location,
|
||||
Met_Location = Met_Location,
|
||||
Met_Level = Met_Level,
|
||||
Tracker = Tracker,
|
||||
|
||||
IsNicknamed = IsNicknamed,
|
||||
CurrentHandler = CurrentHandler,
|
||||
HT_Gender = HT_Gender,
|
||||
HT_Language = HT_Language,
|
||||
HT_Friendship = HT_Friendship,
|
||||
HT_Intensity = HT_Intensity,
|
||||
HT_Memory = HT_Memory,
|
||||
HT_Feeling = HT_Feeling,
|
||||
HT_TextVar = HT_TextVar,
|
||||
|
||||
FatefulEncounter = FatefulEncounter,
|
||||
CNT_Cool = CNT_Cool,
|
||||
CNT_Beauty = CNT_Beauty,
|
||||
CNT_Cute = CNT_Cute,
|
||||
CNT_Smart = CNT_Smart,
|
||||
CNT_Tough = CNT_Tough,
|
||||
CNT_Sheen = CNT_Sheen,
|
||||
|
||||
RibbonChampionKalos = RibbonChampionKalos,
|
||||
RibbonChampionG3 = RibbonChampionG3,
|
||||
RibbonChampionSinnoh = RibbonChampionSinnoh,
|
||||
RibbonBestFriends = RibbonBestFriends,
|
||||
RibbonTraining = RibbonTraining,
|
||||
RibbonBattlerSkillful = RibbonBattlerSkillful,
|
||||
RibbonBattlerExpert = RibbonBattlerExpert,
|
||||
RibbonEffort = RibbonEffort,
|
||||
RibbonAlert = RibbonAlert,
|
||||
RibbonShock = RibbonShock,
|
||||
RibbonDowncast = RibbonDowncast,
|
||||
RibbonCareless = RibbonCareless,
|
||||
RibbonRelax = RibbonRelax,
|
||||
RibbonSnooze = RibbonSnooze,
|
||||
RibbonSmile = RibbonSmile,
|
||||
RibbonGorgeous = RibbonGorgeous,
|
||||
RibbonRoyal = RibbonRoyal,
|
||||
RibbonGorgeousRoyal = RibbonGorgeousRoyal,
|
||||
RibbonArtist = RibbonArtist,
|
||||
RibbonFootprint = RibbonFootprint,
|
||||
RibbonRecord = RibbonRecord,
|
||||
RibbonLegend = RibbonLegend,
|
||||
RibbonCountry = RibbonCountry,
|
||||
RibbonNational = RibbonNational,
|
||||
RibbonEarth = RibbonEarth,
|
||||
RibbonWorld = RibbonWorld,
|
||||
RibbonClassic = RibbonClassic,
|
||||
RibbonPremier = RibbonPremier,
|
||||
RibbonEvent = RibbonEvent,
|
||||
RibbonBirthday = RibbonBirthday,
|
||||
RibbonSpecial = RibbonSpecial,
|
||||
RibbonSouvenir = RibbonSouvenir,
|
||||
RibbonWishing = RibbonWishing,
|
||||
RibbonChampionBattle = RibbonChampionBattle,
|
||||
RibbonChampionRegional = RibbonChampionRegional,
|
||||
RibbonChampionNational = RibbonChampionNational,
|
||||
RibbonChampionWorld = RibbonChampionWorld,
|
||||
HasContestMemoryRibbon = HasContestMemoryRibbon,
|
||||
HasBattleMemoryRibbon = HasBattleMemoryRibbon,
|
||||
RibbonChampionG6Hoenn = RibbonChampionG6Hoenn,
|
||||
RibbonContestStar = RibbonContestStar,
|
||||
RibbonMasterCoolness = RibbonMasterCoolness,
|
||||
RibbonMasterBeauty = RibbonMasterBeauty,
|
||||
RibbonMasterCuteness = RibbonMasterCuteness,
|
||||
RibbonMasterCleverness = RibbonMasterCleverness,
|
||||
RibbonMasterToughness = RibbonMasterToughness,
|
||||
RibbonChampionAlola = RibbonChampionAlola,
|
||||
RibbonBattleRoyale = RibbonBattleRoyale,
|
||||
RibbonBattleTreeGreat = RibbonBattleTreeGreat,
|
||||
RibbonBattleTreeMaster = RibbonBattleTreeMaster,
|
||||
RibbonChampionGalar = RibbonChampionGalar,
|
||||
RibbonTowerMaster = RibbonTowerMaster,
|
||||
RibbonMasterRank = RibbonMasterRank,
|
||||
|
||||
RibbonMarkLunchtime = RibbonMarkLunchtime,
|
||||
RibbonMarkSleepyTime = RibbonMarkSleepyTime,
|
||||
RibbonMarkDusk = RibbonMarkDusk,
|
||||
RibbonMarkDawn = RibbonMarkDawn,
|
||||
RibbonMarkCloudy = RibbonMarkCloudy,
|
||||
RibbonMarkRainy = RibbonMarkRainy,
|
||||
RibbonMarkStormy = RibbonMarkStormy,
|
||||
RibbonMarkSnowy = RibbonMarkSnowy,
|
||||
RibbonMarkBlizzard = RibbonMarkBlizzard,
|
||||
RibbonMarkDry = RibbonMarkDry,
|
||||
RibbonMarkSandstorm = RibbonMarkSandstorm,
|
||||
RibbonCountMemoryContest = RibbonCountMemoryContest,
|
||||
RibbonCountMemoryBattle = RibbonCountMemoryBattle,
|
||||
RibbonMarkMisty = RibbonMarkMisty,
|
||||
RibbonMarkDestiny = RibbonMarkDestiny,
|
||||
RibbonMarkFishing = RibbonMarkFishing,
|
||||
RibbonMarkCurry = RibbonMarkCurry,
|
||||
RibbonMarkUncommon = RibbonMarkUncommon,
|
||||
RibbonMarkRare = RibbonMarkRare,
|
||||
RibbonMarkRowdy = RibbonMarkRowdy,
|
||||
RibbonMarkAbsentMinded = RibbonMarkAbsentMinded,
|
||||
RibbonMarkJittery = RibbonMarkJittery,
|
||||
RibbonMarkExcited = RibbonMarkExcited,
|
||||
RibbonMarkCharismatic = RibbonMarkCharismatic,
|
||||
RibbonMarkCalmness = RibbonMarkCalmness,
|
||||
RibbonMarkIntense = RibbonMarkIntense,
|
||||
RibbonMarkZonedOut = RibbonMarkZonedOut,
|
||||
RibbonMarkJoyful = RibbonMarkJoyful,
|
||||
RibbonMarkAngry = RibbonMarkAngry,
|
||||
RibbonMarkSmiley = RibbonMarkSmiley,
|
||||
RibbonMarkTeary = RibbonMarkTeary,
|
||||
RibbonMarkUpbeat = RibbonMarkUpbeat,
|
||||
RibbonMarkPeeved = RibbonMarkPeeved,
|
||||
RibbonMarkIntellectual = RibbonMarkIntellectual,
|
||||
RibbonMarkFerocious = RibbonMarkFerocious,
|
||||
RibbonMarkCrafty = RibbonMarkCrafty,
|
||||
RibbonMarkScowling = RibbonMarkScowling,
|
||||
RibbonMarkKindly = RibbonMarkKindly,
|
||||
RibbonMarkFlustered = RibbonMarkFlustered,
|
||||
RibbonMarkPumpedUp = RibbonMarkPumpedUp,
|
||||
RibbonMarkZeroEnergy = RibbonMarkZeroEnergy,
|
||||
RibbonMarkPrideful = RibbonMarkPrideful,
|
||||
RibbonMarkUnsure = RibbonMarkUnsure,
|
||||
RibbonMarkHumble = RibbonMarkHumble,
|
||||
RibbonMarkThorny = RibbonMarkThorny,
|
||||
RibbonMarkVigor = RibbonMarkVigor,
|
||||
RibbonMarkSlump = RibbonMarkSlump,
|
||||
RibbonHisui = RibbonHisui,
|
||||
RibbonTwinklingStar = RibbonTwinklingStar,
|
||||
|
||||
AffixedRibbon = AffixedRibbon,
|
||||
HyperTrainFlags = HyperTrainFlags,
|
||||
|
||||
BattleVersion = BattleVersion,
|
||||
PKRS_Days = PKRS_Days,
|
||||
PKRS_Strain = PKRS_Strain,
|
||||
HeightScalar = HeightScalar,
|
||||
WeightScalar = WeightScalar,
|
||||
|
||||
IsFavorite = IsFavorite,
|
||||
MarkValue = MarkValue,
|
||||
};
|
||||
|
||||
Nickname_Trash.CopyTo(pk.Nickname_Trash);
|
||||
OT_Trash.CopyTo(pk.OT_Trash);
|
||||
HT_Trash.CopyTo(pk.HT_Trash);
|
||||
|
||||
pk.SanitizeImport();
|
||||
|
||||
pk.ResetMoves();
|
||||
pk.ResetPartyStats();
|
||||
pk.RefreshChecksum();
|
||||
|
||||
return pk;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,11 @@ public static class EntityConverter
|
|||
/// </summary>
|
||||
public static IEntityRejuvenator RejuvenatorHOME { get; set; } = new LegalityRejuvenator();
|
||||
|
||||
/// <summary>
|
||||
/// Responsible for converting a <see cref="PKM"/> to a <see cref="PKH"/> for HOME.
|
||||
/// </summary>
|
||||
public static IHomeStorage HOME { get; set; } = new HomeStorageFacade();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input <see cref="PKM"/> file is capable of being converted to the desired format.
|
||||
/// </summary>
|
||||
|
@ -121,12 +126,6 @@ public static class EntityConverter
|
|||
PK4 pk4 when destType == typeof(BK4) => pk4.ConvertToBK4(),
|
||||
PK4 pk4 when destType == typeof(RK4) => pk4.ConvertToRK4(),
|
||||
|
||||
PB8 pb8 when destType == typeof(PK8) => pb8.ConvertToPK8(),
|
||||
PK8 pk8 when destType == typeof(PB8) => pk8.ConvertToPB8(),
|
||||
G8PKM pk8 when destType == typeof(PA8) => pk8.ConvertToPA8(),
|
||||
PA8 pa8 when destType == typeof(PK8) => pa8.ConvertToPK8(),
|
||||
PA8 pa8 when destType == typeof(PB8) => pa8.ConvertToPB8(),
|
||||
|
||||
// Sequential
|
||||
PK1 pk1 => pk1.ConvertToPK2(),
|
||||
PK2 pk2 => pk2.ConvertToPK1(),
|
||||
|
@ -135,11 +134,6 @@ public static class EntityConverter
|
|||
PK5 pk5 => pk5.ConvertToPK6(),
|
||||
PK6 pk6 => pk6.ConvertToPK7(),
|
||||
PK7 pk7 => pk7.ConvertToPK8(),
|
||||
PB7 pb7 => pb7.ConvertToPK8(),
|
||||
|
||||
PK8 pk8 => pk8.ConvertToPK9(),
|
||||
PB8 pb8 => pb8.ConvertToPK9(),
|
||||
PA8 pa8 => pa8.ConvertToPK9(),
|
||||
|
||||
// Side-Formats back to Mainline
|
||||
SK2 sk2 => sk2.ConvertToPK2(),
|
||||
|
@ -148,12 +142,17 @@ public static class EntityConverter
|
|||
BK4 bk4 => bk4.ConvertToPK4(),
|
||||
RK4 rk4 => rk4.ConvertToPK4(),
|
||||
|
||||
_ => InvalidTransfer(out result, NoTransferRoute),
|
||||
_ => GetFinalResult(pk, destType, ref result),
|
||||
};
|
||||
|
||||
private static PKM? InvalidTransfer(out EntityConverterResult result, EntityConverterResult value)
|
||||
private static PKM? GetFinalResult(PKM pk, Type destType, ref EntityConverterResult result)
|
||||
{
|
||||
result = value;
|
||||
// Every format can eventually feed into HOME. Don't bother checking current type.
|
||||
var type = PKH.GetType(destType);
|
||||
if (type is not HomeGameDataFormat.None)
|
||||
return HOME.GetEntity(pk).ConvertToPKM(type);
|
||||
|
||||
result = NoTransferRoute;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -117,7 +117,7 @@ public sealed class SAV8BS : SaveFile, ISaveFileRevision, ITrainerStatRecord, IE
|
|||
public override ushort MaxSpeciesID => Legal.MaxSpeciesID_8b;
|
||||
public override int MaxItemID => Legal.MaxItemID_8b;
|
||||
public override int MaxBallID => Legal.MaxBallID_8b;
|
||||
public override int MaxGameID => Legal.MaxGameID_8a;
|
||||
public override int MaxGameID => Legal.MaxGameID_HOME;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_8b;
|
||||
|
||||
public bool HasFirstSaveFileExpansion => (Gem8Version)SaveRevision >= Gem8Version.V1_1;
|
||||
|
|
|
@ -101,7 +101,7 @@ public sealed class SAV8LA : SaveFile, ISaveBlock8LA, ISCBlockArray, ISaveFileRe
|
|||
public override ushort MaxSpeciesID => Legal.MaxSpeciesID_8a;
|
||||
public override int MaxItemID => Legal.MaxItemID_8a;
|
||||
public override int MaxBallID => Legal.MaxBallID_8a;
|
||||
public override int MaxGameID => Legal.MaxGameID_8a;
|
||||
public override int MaxGameID => Legal.MaxGameID_HOME;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_8a;
|
||||
|
||||
#region Blocks
|
||||
|
|
|
@ -91,7 +91,7 @@ public sealed class SAV9SV : SaveFile, ISaveBlock9Main, ISCBlockArray, ISaveFile
|
|||
public override ushort MaxSpeciesID => Legal.MaxSpeciesID_9;
|
||||
public override int MaxItemID => Legal.MaxItemID_9;
|
||||
public override int MaxBallID => Legal.MaxBallID_9;
|
||||
public override int MaxGameID => Legal.MaxGameID_9;
|
||||
public override int MaxGameID => Legal.MaxGameID_HOME;
|
||||
public override int MaxAbilityID => Legal.MaxAbilityID_9;
|
||||
|
||||
private void Initialize()
|
||||
|
|
|
@ -13,7 +13,7 @@ public static class HomeTests
|
|||
{
|
||||
var folder = TestUtil.GetRepoPath();
|
||||
var path = Path.Combine(folder, "TestData");
|
||||
return Directory.EnumerateFiles(path, "*.eh1", SearchOption.TopDirectoryOnly);
|
||||
return Directory.EnumerateFiles(path, "*.eh2", SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
@ -28,19 +28,20 @@ public static class HomeTests
|
|||
var chk = HomeCrypto.GetChecksum1(data);
|
||||
oldCHK.Should().Be(chk);
|
||||
|
||||
bool encrypted = HomeCrypto.GetIsEncrypted1(data);
|
||||
var version = ReadUInt16LittleEndian(data);
|
||||
bool encrypted = HomeCrypto.GetIsEncrypted(data, version);
|
||||
encrypted.Should().BeTrue();
|
||||
|
||||
var ph1 = new PKH(data);
|
||||
ph1.DataVersion.Should().Be(1);
|
||||
HomeCrypto.IsKnownVersion(ph1.DataVersion).Should().BeTrue();
|
||||
|
||||
var decrypted = HomeCrypto.Crypt1(data);
|
||||
var decrypted = HomeCrypto.Crypt(data);
|
||||
decrypted.Length.Should().Be(data.Length);
|
||||
decrypted.Length.Should().Be(ph1.Data.Length);
|
||||
for (int i = 0; i < decrypted.Length; i++)
|
||||
decrypted[i].Should().Be(ph1.Data[i]);
|
||||
|
||||
bool check = HomeCrypto.GetIsEncrypted1(decrypted);
|
||||
bool check = HomeCrypto.GetIsEncrypted(decrypted, version);
|
||||
check.Should().BeFalse();
|
||||
|
||||
ph1.Clone().Should().NotBeNull();
|
||||
|
|
BIN
Tests/PKHeX.Core.Tests/TestData/025 - Pikachu - Anubis.eh2
Normal file
BIN
Tests/PKHeX.Core.Tests/TestData/025 - Pikachu - Anubis.eh2
Normal file
Binary file not shown.
Loading…
Reference in a new issue