simplify mysterygift clone

move declaration to derived class, can return specific type now
don't use AbilityType directly, use the ability permission computed property for legality checks. probably can remove this explicit MG method in the future.
This commit is contained in:
Kurt 2025-06-19 23:36:59 -05:00
parent 870dbb1ce3
commit 8c85a03d78
16 changed files with 40 additions and 45 deletions

View File

@ -46,7 +46,7 @@ public static IReadOnlyList<string> GetTextLines(this IEncounterInfo enc, GameSt
return lines;
// Record types! Can get a nice summary.
// Won't work neatly for Mystery Gift types since those aren't record types.
// Won't work neatly for Mystery Gift types since those aren't record types, plus they have way too many properties.
if (enc is not MysteryGift)
{
// ReSharper disable once ConstantNullCoalescingCondition

View File

@ -262,21 +262,21 @@ private CheckResult VerifyAbilityMG(LegalityAnalysis data, MysteryGift g, IPerso
if (g is PGT) // Ranger Manaphy
return (pk.Format >= 6 ? (pk.AbilityNumber == 1) : (pk.AbilityNumber < 4)) ? VALID : GetInvalid(LAbilityMismatchGift);
var cardType = g.AbilityType;
if (cardType == 4) // 1/2/H
var permit = g.Ability;
if (permit == AbilityPermission.Any12H)
return VALID;
int abilNumber = pk.AbilityNumber;
if (cardType == 3) // 1/2
if (permit == AbilityPermission.Any12)
return abilNumber == 4 ? GetInvalid(LAbilityMismatchGift) : VALID;
// Only remaining matches are fixed index abilities
int cardAbilIndex = 1 << cardType;
int cardAbilIndex = (int)permit;
if (abilNumber == cardAbilIndex)
return VALID;
// Can still match if the ability was changed via ability capsule...
// However, it can't change to/from Hidden Abilities.
if (abilNumber == 4 || cardType == 2)
if (abilNumber == 4 || permit == AbilityPermission.OnlyHidden)
return GetInvalid(LAbilityHiddenFail);
// Ability can be flipped 0/1 if Ability Capsule is available, is not Hidden Ability, and Abilities are different.
@ -319,7 +319,7 @@ private CheckResult VerifyAbility5(LegalityAnalysis data, IEncounterTemplate enc
{
var pk = data.Entity;
// Eggs and Encounter Slots are not yet checked for Hidden Ability potential.
// Eggs and Encounter Slots have not yet checked for Hidden Ability potential.
return enc switch
{
EncounterEgg5 egg when pk.AbilityNumber == 4 && !egg.Ability.CanBeHidden() => GetInvalid(LAbilityHiddenUnavailable),

View File

@ -14,7 +14,7 @@ public abstract class DataMysteryGift(Memory<byte> Raw) : MysteryGift
/// </summary>
public virtual ReadOnlySpan<byte> Write() => Data;
public override int GetHashCode()
public sealed override int GetHashCode()
{
int hash = 17;
foreach (var b in Data)
@ -22,18 +22,12 @@ public override int GetHashCode()
return hash;
}
public sealed override bool IsEmpty => !Data.ContainsAnyExcept<byte>(0);
public void Clear() => Data.Clear();
/// <summary>
/// Creates a deep copy of the <see cref="MysteryGift"/> object data.
/// </summary>
public override MysteryGift Clone()
{
var data = Data.ToArray();
var result = GetMysteryGift(data);
ArgumentNullException.ThrowIfNull(result);
return result;
}
public sealed override bool Empty => !Data.ContainsAnyExcept<byte>(0);
public void Clear() => Data.Clear();
public abstract DataMysteryGift Clone();
}

View File

@ -100,11 +100,6 @@ public EncounterMatchRating GetMatchRating(PKM pk)
return EncounterMatchRating.Match;
}
/// <summary>
/// Creates a deep copy of the <see cref="MysteryGift"/> object data.
/// </summary>
public abstract MysteryGift Clone();
/// <summary>
/// Gets a friendly name for the underlying <see cref="MysteryGift"/> type.
/// </summary>
@ -134,23 +129,16 @@ public EncounterMatchRating GetMatchRating(PKM pk)
public virtual int Quantity { get => 1; set { } }
public virtual bool IsEmpty => false;
public virtual string CardHeader => (CardID > 0 ? $"Card #: {CardID:0000}" : "N/A") + $" - {CardTitle.Replace('\u3000',' ').Trim()}";
public string CardHeader => (CardID > 0 ? $"Card #: {CardID:0000}" : "N/A") + $" - {CardTitle.Replace('\u3000',' ').Trim()}";
// Search Properties
public virtual Moveset Moves { get => default; set { } }
public virtual bool HasFixedIVs => true;
public virtual void GetIVs(Span<int> value) { }
public virtual bool IsShiny => false;
public virtual Shiny Shiny
{
get => Shiny.Never;
init => throw new InvalidOperationException();
}
public virtual bool IsEgg { get => false; set { } }
public virtual int HeldItem { get => -1; set { } }
public virtual int AbilityType { get => -1; set { } }
public abstract Shiny Shiny { get; }
public abstract bool IsEgg { get; set; }
public abstract int HeldItem { get; set; }
public abstract byte Gender { get; set; }
public abstract byte Form { get; set; }
public abstract uint ID32 { get; set; }

View File

@ -17,6 +17,7 @@ public sealed class PCD(Memory<byte> raw)
{
public PCD() : this(new byte[Size]) { }
private readonly Memory<byte> _raw = raw;
public override PCD Clone() => new(Data.ToArray());
public const int Size = 0x358; // 856
public override byte Generation => 4;

View File

@ -11,6 +11,7 @@ public sealed class PGF : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
{
public PGF() : this(new byte[Size]) { }
public PGF(Memory<byte> raw) : base(raw) { }
public override PGF Clone() => new(Data.ToArray());
public int RestrictLanguage { get; set; } // None
public byte RestrictVersion { get; set; } // Permit All
@ -75,7 +76,7 @@ public string Nickname
public Nature Nature { get => (Nature)Data[0x34]; set => Data[0x34] = (byte)value; }
public override byte Gender { get => Data[0x35]; set => Data[0x35] = value; }
public override int AbilityType { get => Data[0x36]; set => Data[0x36] = (byte)value; }
public int AbilityType { get => Data[0x36]; set => Data[0x36] = (byte)value; }
public int PIDType { get => Data[0x37]; set => Data[0x37] = (byte)value; }
public override ushort EggLocation { get => ReadUInt16LittleEndian(Data[0x38..]); set => WriteUInt16LittleEndian(Data[0x38..], value); }
public override ushort Location { get => ReadUInt16LittleEndian(Data[0x3A..]); set => WriteUInt16LittleEndian(Data[0x3A..], value); }

View File

@ -12,6 +12,7 @@ public sealed class PGT : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
{
public PGT() : this(new byte[Size]) { }
public PGT(Memory<byte> raw) : base(raw) { }
public override PGT Clone() => new(Data.ToArray());
public const int Size = 0x104; // 260
public override byte Generation => 4;

View File

@ -15,6 +15,7 @@ public sealed class WA8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
{
public WA8() : this(new byte[Size]) { }
public WA8(Memory<byte> raw) : base(raw) { }
public override WA8 Clone() => new(Data.ToArray());
public const int Size = 0x2C8;
@ -176,7 +177,7 @@ public override int HeldItem
public override byte Level { get => Data[0x23C]; set => Data[0x23C] = value; }
public override bool IsEgg { get => Data[0x23D] == 1; set => Data[0x23D] = value ? (byte)1 : (byte)0; }
public Nature Nature { get => (Nature)Data[0x23E]; set => Data[0x23E] = (byte)value; }
public override int AbilityType { get => Data[0x23F]; set => Data[0x23F] = (byte)value; }
public int AbilityType { get => Data[0x23F]; set => Data[0x23F] = (byte)value; }
private byte PIDTypeValue => Data[0x240];

View File

@ -11,6 +11,7 @@ public sealed class WB7 : DataMysteryGift, ILangNick, IAwakened, IRelearn, IEnco
{
public WB7() : this(new byte[Size]) { }
public WB7(Memory<byte> raw) : base(raw) { }
public override WB7 Clone() => new(Data.ToArray());
public const int Size = 0x310;
private const int CardStart = 0x208;
@ -183,7 +184,7 @@ private uint GetShinyXor()
public Nature Nature { get => (Nature)Card[0xA0]; set => Card[0xA0] = (byte)value; }
public override byte Gender { get => Card[0xA1]; set => Card[0xA1] = value; }
public override int AbilityType { get => IsHOMEGift ? Card[0xA2] : 3; set => Card[0xA2] = (byte)value; } // no references, always ability 0/1
public int AbilityType { get => IsHOMEGift ? Card[0xA2] : 3; set => Card[0xA2] = (byte)value; } // no references, always ability 0/1
public ShinyType6 PIDType { get => (ShinyType6)Card[0xA3]; set => Card[0xA3] = (byte)value; }
public override ushort EggLocation { get => ReadUInt16LittleEndian(Card[0xA4..]); set => WriteUInt16LittleEndian(Card[0xA4..], value); }
public override ushort Location { get => ReadUInt16LittleEndian(Card[0xA6..]); set => WriteUInt16LittleEndian(Card[0xA6..], value); }

View File

@ -15,6 +15,7 @@ public sealed class WB8 : DataMysteryGift,
{
public WB8() : this(new byte[Size]) { }
public WB8(Memory<byte> raw) : base(raw) { }
public override WB8 Clone() => new(Data.ToArray());
public const int Size = 0x2DC;
public const int CardStart = 0x0;
@ -187,7 +188,7 @@ public override int HeldItem
public override byte Level { get => Data[CardStart + 0x28C]; set => Data[CardStart + 0x28C] = value; }
public override bool IsEgg { get => Data[CardStart + 0x28D] == 1; set => Data[CardStart + 0x28D] = value ? (byte)1 : (byte)0; }
public Nature Nature { get => (Nature)Data[CardStart + 0x28E]; set => Data[CardStart + 0x28E] = (byte)value; }
public override int AbilityType { get => Data[CardStart + 0x28F]; set => Data[CardStart + 0x28F] = (byte)value; }
public int AbilityType { get => Data[CardStart + 0x28F]; set => Data[CardStart + 0x28F] = (byte)value; }
private byte PIDTypeValue => Data[CardStart + 0x290];

View File

@ -11,6 +11,7 @@ public sealed class WC6 : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4,
{
public WC6() : this(new byte[Size]) { }
public WC6(Memory<byte> raw) : base(raw) { }
public override WC6 Clone() => new(Data.ToArray());
public const int Size = 0x108;
public const uint EonTicketConst = 0x225D73C2;
@ -176,7 +177,7 @@ public string Nickname
public Nature Nature { get => (Nature)Data[0xA0]; set => Data[0xA0] = (byte)value; }
public override byte Gender { get => Data[0xA1]; set => Data[0xA1] = value; }
public override int AbilityType { get => Data[0xA2]; set => Data[0xA2] = (byte)value; }
public int AbilityType { get => Data[0xA2]; set => Data[0xA2] = (byte)value; }
public ShinyType6 PIDType { get => (ShinyType6)Data[0xA3]; set => Data[0xA3] = (byte)value; }
public override ushort EggLocation { get => ReadUInt16LittleEndian(Data[0xA4..]); set => WriteUInt16LittleEndian(Data[0xA4..], value); }
public override ushort Location { get => ReadUInt16LittleEndian(Data[0xA6..]); set => WriteUInt16LittleEndian(Data[0xA6..], value); }

View File

@ -11,6 +11,7 @@ public sealed class WC7 : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, I
{
public WC7() : this(new byte[Size]) { }
public WC7(Memory<byte> raw) : base(raw) { }
public override WC7 Clone() => new(Data.ToArray());
public const int Size = 0x108;
public override byte Generation => 7;
@ -223,7 +224,7 @@ public string Nickname
public Nature Nature { get => (Nature)Data[0xA0]; set => Data[0xA0] = (byte)value; }
public override byte Gender { get => Data[0xA1]; set => Data[0xA1] = value; }
public override int AbilityType { get => Data[0xA2]; set => Data[0xA2] = (byte)value; }
public int AbilityType { get => Data[0xA2]; set => Data[0xA2] = (byte)value; }
public ShinyType6 PIDType { get => (ShinyType6)Data[0xA3]; set => Data[0xA3] = (byte)value; }
public override ushort EggLocation { get => ReadUInt16LittleEndian(Data[0xA4..]); set => WriteUInt16LittleEndian(Data[0xA4..], value); }
public override ushort Location { get => ReadUInt16LittleEndian(Data[0xA6..]); set => WriteUInt16LittleEndian(Data[0xA6..], value); }

View File

@ -13,6 +13,7 @@ public sealed class WC8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
{
public WC8() : this(new byte[Size]) { }
public WC8(Memory<byte> raw) : base(raw) { }
public override WC8 Clone() => new(Data.ToArray());
public const int Size = 0x2D0;
public const int CardStart = 0x0;
@ -184,7 +185,7 @@ public override int HeldItem
public override byte Level { get => Data[CardStart + 0x244]; set => Data[CardStart + 0x244] = value; }
public override bool IsEgg { get => Data[CardStart + 0x245] == 1; set => Data[CardStart + 0x245] = value ? (byte)1 : (byte)0; }
public Nature Nature { get => (Nature)Data[CardStart + 0x246]; set => Data[CardStart + 0x246] = (byte)value; }
public override int AbilityType { get => Data[CardStart + 0x247]; set => Data[CardStart + 0x247] = (byte)value; }
public int AbilityType { get => Data[CardStart + 0x247]; set => Data[CardStart + 0x247] = (byte)value; }
public ShinyType8 PIDType { get => (ShinyType8)Data[CardStart + 0x248]; set => Data[CardStart + 0x248] = (byte)value; }

View File

@ -14,6 +14,7 @@ public sealed class WC9 : DataMysteryGift, ILangNick, INature, ITeraType, IRibbo
{
public WC9() : this(new byte[Size]) { }
public WC9(Memory<byte> raw) : base(raw) { }
public override WC9 Clone() => new(Data.ToArray());
public const int Size = 0x2C8;
public const int CardStart = 0x0;
@ -199,7 +200,7 @@ public override int HeldItem
public override byte Level { get => Data[CardStart + 0x23C]; set => Data[CardStart + 0x23C] = value; }
public override bool IsEgg { get => Data[CardStart + 0x23D] == 1; set => Data[CardStart + 0x23D] = value ? (byte)1 : (byte)0; }
public Nature Nature { get => (Nature)Data[CardStart + 0x23E]; set => Data[CardStart + 0x23E] = (byte)value; }
public override int AbilityType { get => Data[CardStart + 0x23F]; set => Data[CardStart + 0x23F] = (byte)value; }
public int AbilityType { get => Data[CardStart + 0x23F]; set => Data[CardStart + 0x23F] = (byte)value; }
public ShinyType8 PIDType { get => (ShinyType8)Data[CardStart + 0x240]; set => Data[CardStart + 0x240] = (byte)value; }

View File

@ -14,6 +14,7 @@ public sealed class WR7 : DataMysteryGift
{
public WR7() : this(new byte[Size]) { }
public WR7(Memory<byte> raw) : base(raw) { }
public override WR7 Clone() => new(Data.ToArray());
public const int Size = 0x140;
public override byte Generation => 7;
@ -90,6 +91,8 @@ public override ushort Species
public override uint ID32 { get; set; }
public override ushort TID16 { get; set; }
public override ushort SID16 { get; set; }
public override bool IsEgg { get => false; set { } }
public override int HeldItem { get => -1; set { } }
public override string OriginalTrainerName
{

View File

@ -257,7 +257,7 @@ private void ClickSet(object sender, EventArgs e)
WinFormsUtil.Alert(MsgMysteryGiftSlotFail, $"{GameInfo.Strings.Item[533]} slot not valid.");
return;
}
gifts[index] = (DataMysteryGift)gift.Clone();
gifts[index] = gift.Clone();
SetBackground(index, Drawing.PokeSprite.Properties.Resources.slotSet);
SetGiftBoxes();
SetCardID(gift.CardID);
@ -556,7 +556,7 @@ private void BoxSlot_DragDrop(object? sender, DragEventArgs? e)
return;
}
SetBackground(index, Drawing.PokeSprite.Properties.Resources.slotSet);
dest = (DataMysteryGift)gift.Clone();
dest = gift.Clone();
SetCardID(dest.CardID);
ViewGiftData(dest);