diff --git a/PKHeX.Core/Editing/Applicators/MarkingApplicator.cs b/PKHeX.Core/Editing/Applicators/MarkingApplicator.cs index cf73b9ffa..b0d52792a 100644 --- a/PKHeX.Core/Editing/Applicators/MarkingApplicator.cs +++ b/PKHeX.Core/Editing/Applicators/MarkingApplicator.cs @@ -1,9 +1,9 @@ -using System; +using System; namespace PKHeX.Core; /// -/// Logic for modifying the . +/// Logic for modifying the . /// public static class MarkingApplicator { @@ -14,21 +14,40 @@ public static class MarkingApplicator public static Func> MarkingMethod { get; set; } = FlagHighLow; /// - /// Sets the to indicate flawless (or near-flawless) . + /// Sets the applied Markings to indicate flawless (or near-flawless) . /// /// Pokémon to modify. public static void SetMarkings(this PKM pk) { - if (pk.MarkingCount < 6) + if (pk is not IAppliedMarkings { MarkingCount: 6 }) return; // insufficient marking indexes + if (pk is IAppliedMarkings c) + SetMarkings(c, pk); + else if (pk is IAppliedMarkings b) + SetMarkings(b, pk); + } + + private static void SetMarkings(this IAppliedMarkings mark, PKM pk) + { var method = MarkingMethod(pk); - pk.SetMarking(0, method(pk.IV_HP , 0)); - pk.SetMarking(1, method(pk.IV_ATK, 1)); - pk.SetMarking(2, method(pk.IV_DEF, 2)); - pk.SetMarking(3, method(pk.IV_SPA, 3)); - pk.SetMarking(4, method(pk.IV_SPD, 4)); - pk.SetMarking(5, method(pk.IV_SPE, 5)); + mark.SetMarking(0, method(pk.IV_HP , 0) == 1); + mark.SetMarking(1, method(pk.IV_ATK, 1) == 1); + mark.SetMarking(2, method(pk.IV_DEF, 2) == 1); + mark.SetMarking(3, method(pk.IV_SPA, 3) == 1); + mark.SetMarking(4, method(pk.IV_SPD, 4) == 1); + mark.SetMarking(5, method(pk.IV_SPE, 5) == 1); + } + + private static void SetMarkings(this IAppliedMarkings mark, PKM pk) + { + var method = MarkingMethod(pk); + mark.SetMarking(0, (MarkingColor)method(pk.IV_HP, 0)); + mark.SetMarking(1, (MarkingColor)method(pk.IV_ATK, 1)); + mark.SetMarking(2, (MarkingColor)method(pk.IV_DEF, 2)); + mark.SetMarking(3, (MarkingColor)method(pk.IV_SPA, 3)); + mark.SetMarking(4, (MarkingColor)method(pk.IV_SPD, 4)); + mark.SetMarking(5, (MarkingColor)method(pk.IV_SPE, 5)); } /// @@ -37,18 +56,19 @@ public static class MarkingApplicator /// Pokémon to modify. /// Marking index to toggle /// Current marking value - public static int ToggleMarking(this PKM pk, int index) + public static void ToggleMarking(this PKM pk, int index) { - var marking = pk.GetMarking(index); - var revised = NextMarking(pk.Format, marking); - pk.SetMarking(index, revised); - return revised; + if (pk is IAppliedMarkings c) + c.SetMarking(index, c.GetMarking(index).Next()); + else if (pk is IAppliedMarkings b) + b.SetMarking(index, !b.GetMarking(index)); } - private static int NextMarking(int format, int marking) => format switch + private static MarkingColor Next(this MarkingColor value) => value switch { - <= 6 => marking ^ 1, // toggle : 0 (off) | 1 (on) - _ => (marking + 1) % 3, // cycle 0->1->2->0... : 0 (none) | 1 (blue) | 2 (pink) + MarkingColor.Blue => MarkingColor.Pink, + MarkingColor.Pink => MarkingColor.None, + _ => MarkingColor.Blue, }; private static Func FlagHighLow(PKM pk) diff --git a/PKHeX.Core/Editing/PKM/EntitySummary.cs b/PKHeX.Core/Editing/PKM/EntitySummary.cs index 37d0d2b19..a1f565716 100644 --- a/PKHeX.Core/Editing/PKM/EntitySummary.cs +++ b/PKHeX.Core/Editing/PKM/EntitySummary.cs @@ -66,7 +66,6 @@ public class EntitySummary : IFatefulEncounterReadOnly // do NOT seal, allow inh public int Smart => pk is IContestStatsReadOnly s ? s.CNT_Smart : 0; public int Tough => pk is IContestStatsReadOnly s ? s.CNT_Tough : 0; public int Sheen => pk is IContestStatsReadOnly s ? s.CNT_Sheen : 0; - public int Markings => pk.MarkValue; public string NotOT => pk.Format > 5 ? pk.HT_Name : "N/A"; diff --git a/PKHeX.Core/Legality/Verifiers/MarkingVerifier.cs b/PKHeX.Core/Legality/Verifiers/MarkingVerifier.cs index 0797d41be..18ad0e701 100644 --- a/PKHeX.Core/Legality/Verifiers/MarkingVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/MarkingVerifier.cs @@ -4,7 +4,7 @@ using static PKHeX.Core.CheckIdentifier; namespace PKHeX.Core; /// -/// Verifies the . +/// Verifies the . /// public sealed class MarkingVerifier : Verifier { @@ -26,26 +26,14 @@ public sealed class MarkingVerifier : Verifier private void VerifyMarkValue(LegalityAnalysis data, PKM pk) { - var mv = pk.MarkValue; - if (mv == 0) - return; - // Eggs can have markings applied. - //if (pk.IsEgg) - //{ - // data.AddLine(GetInvalid(LMarkValueShouldBeZero)); - // return; - //} - - switch (pk.Format) + switch (pk) { - case <= 2: + case IAppliedMarkings3 m4: + VerifyMarkValueSingle(data, m4, m4.MarkingValue); return; - case <= 6: - VerifyMarkValueSingle(data, pk, mv); - return; - default: - VerifyMarkValueDual(data, pk, mv); + case IAppliedMarkings7 m7: + VerifyMarkValueDual(data, m7, m7.MarkingValue); return; } } @@ -54,8 +42,10 @@ public sealed class MarkingVerifier : Verifier private const int Single6 = 0b_111111; private const int Dual6 = 0b_1111_1111_1111; - private void VerifyMarkValueDual(LegalityAnalysis data, PKM pk, int mv) + private void VerifyMarkValueDual(LegalityAnalysis data, IAppliedMarkings7 pk, ushort mv) { + if (mv == 0) + return; if (mv > Dual6) data.AddLine(GetInvalid(LMarkValueUnusedBitsPresent)); @@ -63,20 +53,22 @@ public sealed class MarkingVerifier : Verifier for (int i = 0; i < count; i++) { var value = pk.GetMarking(i); - if (value is not (0 or 1 or 2)) + if (value is not (0 or MarkingColor.Blue or MarkingColor.Pink)) data.AddLine(GetInvalid(string.Format(LMarkValueOutOfRange_0, i))); } } - private void VerifyMarkValueSingle(LegalityAnalysis data, PKM pk, int mv) + private void VerifyMarkValueSingle(LegalityAnalysis data, IAppliedMarkings3 pk, byte mv) { + if (mv == 0) + return; if (!IsMarkValueValid3456(pk, mv)) data.AddLine(GetInvalid(LMarkValueUnusedBitsPresent)); } - private static bool IsMarkValueValid3456(PKM pk, int value) + private static bool IsMarkValueValid3456(IAppliedMarkings3 pk, int value) { - var max = pk.Format is 3 ? Single4 : Single6; + var max = pk is IAppliedMarkings4 ? Single6 : Single4; return value <= max; } } diff --git a/PKHeX.Core/PKM/BK4.cs b/PKHeX.Core/PKM/BK4.cs index 3da2cbf81..2a7d06912 100644 --- a/PKHeX.Core/PKM/BK4.cs +++ b/PKHeX.Core/PKM/BK4.cs @@ -63,7 +63,7 @@ public sealed class BK4 : G4PKM public override int OT_Friendship { get => Data[0x14]; set => Data[0x14] = (byte)value; } public override int Ability { get => Data[0x15]; set => Data[0x15] = (byte)value; } - public override int MarkValue { get => Data[0x16]; set => Data[0x16] = (byte)value; } + public override byte MarkingValue { get => Data[0x16]; set => Data[0x16] = value; } public override int Language { get => Data[0x17]; set => Data[0x17] = (byte)value; } public override int EV_HP { get => Data[0x18]; set => Data[0x18] = (byte)value; } public override int EV_ATK { get => Data[0x19]; set => Data[0x19] = (byte)value; } diff --git a/PKHeX.Core/PKM/CK3.cs b/PKHeX.Core/PKM/CK3.cs index a3f14d054..00d51a401 100644 --- a/PKHeX.Core/PKM/CK3.cs +++ b/PKHeX.Core/PKM/CK3.cs @@ -174,7 +174,7 @@ public sealed class CK3(byte[] Data) : G3PKM(Data), IShadowCapture public override bool AbilityBit { get => Data[0xCC] == 1; set => Data[0xCC] = value ? (byte)1 : (byte)0; } public override bool Valid { get => Data[0xCD] == 0; set => Data[0xCD] = !value ? (byte)1 : (byte)0; } - public override int MarkValue { get => SwapBits(Data[0xCF], 1, 2); set => Data[0xCF] = (byte)SwapBits(value, 1, 2); } + public override byte MarkingValue { get => (byte)SwapBits(Data[0xCF], 1, 2); set => Data[0xCF] = (byte)SwapBits(value, 1, 2); } public override int PKRS_Days { get => Math.Max((sbyte)Data[0xD0], (sbyte)0); set => Data[0xD0] = (byte)(value == 0 ? 0xFF : value & 0xF); } public int PartySlot { get => Data[0xD7]; set => Data[0xD7] = (byte)value; } // or not; only really used while in party? diff --git a/PKHeX.Core/PKM/HOME/GameDataCore.cs b/PKHeX.Core/PKM/HOME/GameDataCore.cs index 55f2a92b5..19362b89b 100644 --- a/PKHeX.Core/PKM/HOME/GameDataCore.cs +++ b/PKHeX.Core/PKM/HOME/GameDataCore.cs @@ -10,7 +10,8 @@ namespace PKHeX.Core; public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature, IFatefulEncounter, IContestStats, IScaledSize, ITrainerMemories, IHandlerLanguage, IBattleVersion, IHyperTrain, IFormArgument, IFavorite, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8, - IRibbonSetCommon9, IRibbonSetMark9 + IRibbonSetCommon9, IRibbonSetMark9, + IAppliedMarkings7 { // Internal Attributes set on creation private readonly Memory Buffer; // Raw Storage @@ -39,7 +40,7 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature 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 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 ushort MarkingValue { get => ReadUInt16LittleEndian(Data[0x18..]); set => WriteUInt16LittleEndian(Data[0x18..], 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; } @@ -296,25 +297,32 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature public int HeldItem { get => ReadUInt16LittleEndian(Data[0xC2..]); set => WriteUInt16LittleEndian(Data[0xC2..], (ushort)value); } - public int MarkingCount => 6; - public TrainerIDFormat TrainerIDDisplayFormat => ((GameVersion)Version).GetGeneration() >= 7 ? TrainerIDFormat.SixDigit : TrainerIDFormat.SixteenBit; - public int GetMarking(int index) + public int MarkingCount => 6; + + public MarkingColor GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> (index * 2)) & 3; + return (MarkingColor)((MarkingValue >> (index * 2)) & 3); } - public void SetMarking(int index, int value) + public void SetMarking(int index, MarkingColor value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); var shift = index * 2; - MarkValue = (MarkValue & ~(0b11 << shift)) | ((value & 3) << shift); + MarkingValue = (ushort)((MarkingValue & ~(0b11 << shift)) | (((byte)value & 3) << shift)); } + public MarkingColor MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public MarkingColor MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public MarkingColor MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public MarkingColor MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public MarkingColor MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public MarkingColor MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } + public void CopyFrom(PKM pk) { EncryptionConstant = pk.EncryptionConstant; @@ -325,7 +333,7 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature TID16 = pk.TID16; SID16 = pk.SID16; EXP = pk.EXP; - MarkValue = pk.MarkValue; + MarkingValue = pk is IAppliedMarkings7 m7 ? m7.MarkingValue : (ushort)0; Nature = pk.Nature; StatNature = pk.StatNature; FatefulEncounter = pk.FatefulEncounter; @@ -382,7 +390,8 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature pk.TID16 = TID16; pk.SID16 = SID16; pk.EXP = EXP; - pk.MarkValue = MarkValue; + if (pk is IAppliedMarkings7 m7) + m7.MarkingValue = MarkingValue; pk.Nature = Nature; pk.StatNature = StatNature; pk.FatefulEncounter = FatefulEncounter; diff --git a/PKHeX.Core/PKM/HOME/GameDataPK8.cs b/PKHeX.Core/PKM/HOME/GameDataPK8.cs index 39ccb8241..6b6cf3602 100644 --- a/PKHeX.Core/PKM/HOME/GameDataPK8.cs +++ b/PKHeX.Core/PKM/HOME/GameDataPK8.cs @@ -112,7 +112,7 @@ public sealed class GameDataPK8 : HomeOptional1, IGameDataSide, IGigantamax AbilityNumber = (byte)pk.AbilityNumber; Ability = (ushort)pk.Ability; - pkh.MarkValue &= 0b1111_1111_1111; + pkh.MarkingValue &= 0b1111_1111_1111; if (!pk.IsNicknamed) pkh.Nickname = SpeciesName.GetSpeciesNameGeneration(pk.Species, pk.Language, 8); if (FormInfo.IsTotemForm(pk.Species, pk.Form)) diff --git a/PKHeX.Core/PKM/HOME/PKH.cs b/PKHeX.Core/PKM/HOME/PKH.cs index e57404002..97756e61f 100644 --- a/PKHeX.Core/PKM/HOME/PKH.cs +++ b/PKHeX.Core/PKM/HOME/PKH.cs @@ -5,7 +5,8 @@ using static PKHeX.Core.GameVersion; namespace PKHeX.Core; /// Pokémon HOME format. -public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, IRibbonSetAffixed, IContestStats, IScaledSize, IRibbonSetRibbons, IRibbonSetMarks +public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, IRibbonSetAffixed, IContestStats, IScaledSize, + IRibbonSetRibbons, IRibbonSetMarks, IAppliedMarkings7 { public readonly GameDataCore Core; public GameDataPB7? DataPB7 { get; private set; } @@ -93,7 +94,7 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat 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 ushort MarkingValue { get => Core.MarkingValue; set => Core.MarkingValue = 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; } @@ -167,12 +168,19 @@ public sealed class PKH : PKM, IHandlerLanguage, IFormArgument, IHomeTrack, IBat 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 => Core.MarkingCount; + public 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); + public MarkingColor GetMarking(int index) => Core.GetMarking(index); + public void SetMarking(int index, MarkingColor value) => Core.SetMarking(index, value); + + public MarkingColor MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public MarkingColor MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public MarkingColor MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public MarkingColor MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public MarkingColor MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public MarkingColor MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } #endregion diff --git a/PKHeX.Core/PKM/Interfaces/IAppliedMarkings.cs b/PKHeX.Core/PKM/Interfaces/IAppliedMarkings.cs new file mode 100644 index 000000000..994c65c38 --- /dev/null +++ b/PKHeX.Core/PKM/Interfaces/IAppliedMarkings.cs @@ -0,0 +1,90 @@ +namespace PKHeX.Core; + +/// +/// Indicates if the object is capable of being marked by the player with simple shapes. +/// +public interface IAppliedMarkings +{ + /// + /// Count of unique markings that can be applied to the object. + /// + int MarkingCount { get; } +} + +public interface IAppliedMarkings : IAppliedMarkings where T : unmanaged +{ + /// + /// Gets the marking value at the given index. + /// + /// Index of the marking to get. + /// Marking value at the given index. + T GetMarking(int index); + + /// + /// Sets the marking value at the given index. + /// + /// Index of the marking to set. + /// Value to set the marking to. + void SetMarking(int index, T value); +} + +/// +/// Generation 3 Markings +/// +public interface IAppliedMarkings3 : IAppliedMarkings +{ + /// + /// Backing value for the packed bits. + /// + byte MarkingValue { get; set; } + + bool MarkingCircle { get; set; } + bool MarkingTriangle { get; set; } // In generation 3, this is marking index 2 + bool MarkingSquare { get; set; } // In generation 3, this is marking index 1 + bool MarkingHeart { get; set; } +} + +/// +/// Generation 4-6 Markings +/// +public interface IAppliedMarkings4 : IAppliedMarkings3 +{ + bool MarkingStar { get; set; } + bool MarkingDiamond { get; set; } +} + +/// +/// Generation 7+ Markings +/// +public interface IAppliedMarkings7 : IAppliedMarkings +{ + /// + /// Backing value for the packed bits. + /// + ushort MarkingValue { get; set; } + + MarkingColor MarkingCircle { get; set; } + MarkingColor MarkingTriangle { get; set; } + MarkingColor MarkingSquare { get; set; } + MarkingColor MarkingHeart { get; set; } + MarkingColor MarkingStar { get; set; } + MarkingColor MarkingDiamond { get; set; } +} + +public enum MarkingColor : byte +{ + /// + /// Not marked. + /// + None = 0, + + /// + /// Blue marking. + /// + Blue = 1, + + /// + /// Pink marking. + /// + Pink = 2, +} diff --git a/PKHeX.Core/PKM/PA8.cs b/PKHeX.Core/PKM/PA8.cs index 09a6c1fd3..c9f9462a4 100644 --- a/PKHeX.Core/PKM/PA8.cs +++ b/PKHeX.Core/PKM/PA8.cs @@ -130,7 +130,7 @@ public sealed class PA8 : PKM, ISanityChecksum, public bool IsAlpha { get => (Data[0x16] & 32) != 0; set => Data[0x16] = (byte)((Data[0x16] & ~32) | ((value ? 1 : 0) << 5)); } public bool IsNoble { get => (Data[0x16] & 64) != 0; set => Data[0x16] = (byte)((Data[0x16] & ~64) | ((value ? 1 : 0) << 6)); } // 0x17 alignment unused - public override int MarkValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x18)); set => WriteUInt16LittleEndian(Data.AsSpan(0x18), (ushort)value); } + public ushort MarkValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x18)); set => WriteUInt16LittleEndian(Data.AsSpan(0x18), value); } // 0x1A alignment unused // 0x1B alignment unused public override uint PID { get => ReadUInt32LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt32LittleEndian(Data.AsSpan(0x1C), value); } @@ -540,21 +540,21 @@ public sealed class PA8 : PKM, ISanityChecksum, return NatureAmp.AmplifyStat(nature, statIndex, initial); } - public override int MarkingCount => 6; + public int MarkingCount => 6; - public override int GetMarking(int index) + public MarkingColor GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> (index * 2)) & 3; + return (MarkingColor)((MarkValue >> (index * 2)) & 3); } - public override void SetMarking(int index, int value) + public void SetMarking(int index, MarkingColor value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); var shift = index * 2; - MarkValue = (MarkValue & ~(0b11 << shift)) | ((value & 3) << shift); + MarkValue = (ushort)((MarkValue & ~(0b11 << shift)) | (((byte)value & 3) << shift)); } public bool GetRibbon(int index) => FlagUtil.GetFlag(Data, GetRibbonByte(index), index & 7); diff --git a/PKHeX.Core/PKM/PB7.cs b/PKHeX.Core/PKM/PB7.cs index 9c245471c..44ecec93d 100644 --- a/PKHeX.Core/PKM/PB7.cs +++ b/PKHeX.Core/PKM/PB7.cs @@ -5,7 +5,7 @@ using static System.Buffers.Binary.BinaryPrimitives; namespace PKHeX.Core; /// Generation 7 format used for . -public sealed class PB7 : G6PKM, IHyperTrain, IAwakened, IScaledSizeValue, ICombatPower, IFavorite, IFormArgument +public sealed class PB7 : G6PKM, IHyperTrain, IAwakened, IScaledSizeValue, ICombatPower, IFavorite, IFormArgument, IAppliedMarkings7 { public override ReadOnlySpan ExtraBytes => [ @@ -98,7 +98,7 @@ public sealed class PB7 : G6PKM, IHyperTrain, IAwakened, IScaledSizeValue, IComb public override int Ability { get => Data[0x14]; set => Data[0x14] = (byte)value; } public override int AbilityNumber { get => Data[0x15] & 7; set => Data[0x15] = (byte)((Data[0x15] & ~7) | (value & 7)); } public bool IsFavorite { get => (Data[0x15] & 8) != 0; set => Data[0x15] = (byte)((Data[0x15] & ~8) | ((value ? 1 : 0) << 3)); } - public override int MarkValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x16)); set => WriteUInt16LittleEndian(Data.AsSpan(0x16), (ushort)value); } + public ushort MarkingValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x16)); set => WriteUInt16LittleEndian(Data.AsSpan(0x16), value); } public override uint PID { @@ -309,23 +309,30 @@ public sealed class PB7 : G6PKM, IHyperTrain, IAwakened, IScaledSizeValue, IComb // 102/103 unused #endregion - public override int MarkingCount => 6; + public int MarkingCount => 6; - public override int GetMarking(int index) + public MarkingColor GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> (index * 2)) & 3; + return (MarkingColor)((MarkingValue >> (index * 2)) & 3); } - public override void SetMarking(int index, int value) + public void SetMarking(int index, MarkingColor value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); var shift = index * 2; - MarkValue = (MarkValue & ~(0b11 << shift)) | ((value & 3) << shift); + MarkingValue = (ushort)((MarkingValue & ~(0b11 << shift)) | (((byte)value & 3) << shift)); } + public MarkingColor MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public MarkingColor MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public MarkingColor MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public MarkingColor MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public MarkingColor MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public MarkingColor MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } + protected override bool TradeOT(ITrainerInfo tr) { // Check to see if the OT matches the SAV's OT info. diff --git a/PKHeX.Core/PKM/PK3.cs b/PKHeX.Core/PKM/PK3.cs index 1ac02b9b1..6edcf4244 100644 --- a/PKHeX.Core/PKM/PK3.cs +++ b/PKHeX.Core/PKM/PK3.cs @@ -60,7 +60,7 @@ public sealed class PK3 : G3PKM, ISanityChecksum get => StringConverter3.GetString(OT_Trash, Japanese); set => StringConverter3.SetString(OT_Trash, value, 7, Japanese, StringConverterOption.None); } - public override int MarkValue { get => SwapBits(Data[0x1B], 1, 2); set => Data[0x1B] = (byte)SwapBits(value, 1, 2); } + public override byte MarkingValue { get => (byte)SwapBits(Data[0x1B], 1, 2); set => Data[0x1B] = (byte)SwapBits(value, 1, 2); } public ushort Checksum { get => ReadUInt16LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1C), value); } public ushort Sanity { get => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1E), value); } @@ -222,7 +222,7 @@ public sealed class PK3 : G3PKM, ISanityChecksum Form = Form, // IsEgg = false, -- already false OT_Friendship = 70, - MarkValue = MarkValue & 0b1111, + MarkingValue = (byte)(MarkingValue & 0b1111), Language = Language, EV_HP = EV_HP, EV_ATK = EV_ATK, diff --git a/PKHeX.Core/PKM/PK4.cs b/PKHeX.Core/PKM/PK4.cs index a04730d70..292b21921 100644 --- a/PKHeX.Core/PKM/PK4.cs +++ b/PKHeX.Core/PKM/PK4.cs @@ -43,7 +43,7 @@ public sealed class PK4 : G4PKM public override uint EXP { get => ReadUInt32LittleEndian(Data.AsSpan(0x10)); set => WriteUInt32LittleEndian(Data.AsSpan(0x10), value); } public override int OT_Friendship { get => Data[0x14]; set => Data[0x14] = (byte)value; } public override int Ability { get => Data[0x15]; set => Data[0x15] = (byte)value; } - public override int MarkValue { get => Data[0x16]; set => Data[0x16] = (byte)value; } + public override byte MarkingValue { get => Data[0x16]; set => Data[0x16] = value; } public override int Language { get => Data[0x17]; set => Data[0x17] = (byte)value; } public override int EV_HP { get => Data[0x18]; set => Data[0x18] = (byte)value; } public override int EV_ATK { get => Data[0x19]; set => Data[0x19] = (byte)value; } diff --git a/PKHeX.Core/PKM/PK5.cs b/PKHeX.Core/PKM/PK5.cs index 83cbd14cc..a203ae1b3 100644 --- a/PKHeX.Core/PKM/PK5.cs +++ b/PKHeX.Core/PKM/PK5.cs @@ -7,7 +7,7 @@ namespace PKHeX.Core; /// Generation 5 format. public sealed class PK5 : PKM, ISanityChecksum, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetRibbons, - IContestStats, IGroundTile + IContestStats, IGroundTile, IAppliedMarkings4 { public override ReadOnlySpan ExtraBytes => [ @@ -64,7 +64,7 @@ public sealed class PK5 : PKM, ISanityChecksum, public override uint EXP { get => ReadUInt32LittleEndian(Data.AsSpan(0x10)); set => WriteUInt32LittleEndian(Data.AsSpan(0x10), value); } public override int OT_Friendship { get => Data[0x14]; set => Data[0x14] = (byte)value; } public override int Ability { get => Data[0x15]; set => Data[0x15] = (byte)value; } - public override int MarkValue { get => Data[0x16]; set => Data[0x16] = (byte)value; } + public byte MarkingValue { get => Data[0x16]; set => Data[0x16] = value; } public override int Language { get => Data[0x17]; set => Data[0x17] = (byte)value; } public override int EV_HP { get => Data[0x18]; set => Data[0x18] = (byte)value; } public override int EV_ATK { get => Data[0x19]; set => Data[0x19] = (byte)value; } @@ -307,22 +307,29 @@ public sealed class PK5 : PKM, ISanityChecksum, return false; } - public override int MarkingCount => 6; + public int MarkingCount => 6; - public override int GetMarking(int index) + public bool GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> index) & 1; + return ((MarkingValue >> index) & 1) != 0; } - public override void SetMarking(int index, int value) + public void SetMarking(int index, bool value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - MarkValue = (MarkValue & ~(1 << index)) | ((value & 1) << index); + MarkingValue = (byte)((MarkingValue & ~(1 << index)) | ((value ? 1 : 0) << index)); } + public bool MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public bool MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public bool MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public bool MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public bool MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public bool MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } + public override void RefreshAbility(int n) { base.RefreshAbility(n); @@ -341,7 +348,7 @@ public sealed class PK5 : PKM, ISanityChecksum, PID = PID, Ability = Ability, AbilityNumber = 1 << CalculateAbilityIndex(), - MarkValue = MarkValue & 0b_11_1111, + MarkingValue = MarkingValue, Language = Math.Max((int)LanguageID.Japanese, Language), // Hacked or Bad IngameTrade (Japanese B/W) CNT_Cool = CNT_Cool, diff --git a/PKHeX.Core/PKM/PK6.cs b/PKHeX.Core/PKM/PK6.cs index 7212a36bf..0d30c3d3e 100644 --- a/PKHeX.Core/PKM/PK6.cs +++ b/PKHeX.Core/PKM/PK6.cs @@ -6,7 +6,7 @@ namespace PKHeX.Core; /// Generation 6 format. public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetRibbons, - IContestStats, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection, IGroundTile + IContestStats, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection, IGroundTile, IAppliedMarkings4 { public override ReadOnlySpan ExtraBytes => [ @@ -112,7 +112,7 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC public byte CNT_Smart { get => Data[0x27]; set => Data[0x27] = value; } public byte CNT_Tough { get => Data[0x28]; set => Data[0x28] = value; } public byte CNT_Sheen { get => Data[0x29]; set => Data[0x29] = value; } - public override int MarkValue { get => Data[0x2A]; set => Data[0x2A] = (byte)value; } + public byte MarkingValue { get => Data[0x2A]; set => Data[0x2A] = value; } private byte PKRS { get => Data[0x2B]; set => Data[0x2B] = 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)); } @@ -455,28 +455,35 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC public override int MaxItemID => Legal.MaxItemID_6_AO; public override int MaxBallID => Legal.MaxBallID_6; public override int MaxGameID => Legal.MaxGameID_6; // OR - public override int MarkingCount => 6; + public int MarkingCount => 6; - public override int GetMarking(int index) + public bool GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> index) & 1; + return ((MarkingValue >> index) & 1) != 0; } - public override void SetMarking(int index, int value) + public void SetMarking(int index, bool value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - MarkValue = (MarkValue & ~(1 << index)) | ((value & 1) << index); + MarkingValue = (byte)((MarkingValue & ~(1 << index)) | ((value ? 1 : 0) << index)); } + public bool MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public bool MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public bool MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public bool MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public bool MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public bool MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } + public PK7 ConvertToPK7() { PK7 pk7 = new((byte[])Data.Clone()) { ResortEventStatus = 0, // Clears old Marking Value - MarkValue = 0, // Clears old Super Training Bag & Hits Remaining + MarkingValue = 0, // Clears old Super Training Bag & Hits Remaining FormArgument = 0, // Clears old style Form Argument DirtType = 0, // Clears old Form Argument byte DirtLocation = 0, // Clears old Form Argument byte @@ -484,7 +491,7 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC // Remap boolean markings to the dual-bit format -- set 1 if marked. for (int i = 0; i < 6; i++) - pk7.SetMarking(i, GetMarking(i)); + pk7.SetMarking(i, GetMarking(i) ? MarkingColor.Blue : MarkingColor.None); var an = AbilityNumber; if (an is 1 or 2 or 4) // Valid Ability Numbers diff --git a/PKHeX.Core/PKM/PK7.cs b/PKHeX.Core/PKM/PK7.cs index 2415fe9d1..ca34176fb 100644 --- a/PKHeX.Core/PKM/PK7.cs +++ b/PKHeX.Core/PKM/PK7.cs @@ -6,7 +6,7 @@ namespace PKHeX.Core; /// Generation 7 format. public sealed class PK7 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetRibbons, - IContestStats, IHyperTrain, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection, IPokerusStatus + IContestStats, IHyperTrain, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection, IPokerusStatus, IAppliedMarkings7 { public override ReadOnlySpan ExtraBytes => [ @@ -88,7 +88,7 @@ public sealed class PK7 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC public override int Ability { get => Data[0x14]; set => Data[0x14] = (byte)value; } public override int AbilityNumber { get => Data[0x15] & 7; set => Data[0x15] = (byte)((Data[0x15] & ~7) | (value & 7)); } - public override int MarkValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x16)); set => WriteUInt16LittleEndian(Data.AsSpan(0x16), (ushort)value); } + public ushort MarkingValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x16)); set => WriteUInt16LittleEndian(Data.AsSpan(0x16), value); } public override uint PID { @@ -423,23 +423,30 @@ public sealed class PK7 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC public bool IsUntradedEvent6 => Geo1_Country == 0 && Geo1_Region == 0 && Met_Location / 10000 == 4 && Gen6; - public override int MarkingCount => 6; + public int MarkingCount => 6; - public override int GetMarking(int index) + public MarkingColor GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> (index * 2)) & 3; + return (MarkingColor)((MarkingValue >> (index * 2)) & 3); } - public override void SetMarking(int index, int value) + public void SetMarking(int index, MarkingColor value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); var shift = index * 2; - MarkValue = (MarkValue & ~(0b11 << shift)) | ((value & 3) << shift); + MarkingValue = (ushort)((MarkingValue & ~(0b11 << shift)) | (((byte)value & 3) << shift)); } + public MarkingColor MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public MarkingColor MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public MarkingColor MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public MarkingColor MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public MarkingColor MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public MarkingColor MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } + public void FixMemories() { if (IsEgg) // No memories if is egg. diff --git a/PKHeX.Core/PKM/PK9.cs b/PKHeX.Core/PKM/PK9.cs index 0b908d3d4..78794be86 100644 --- a/PKHeX.Core/PKM/PK9.cs +++ b/PKHeX.Core/PKM/PK9.cs @@ -6,7 +6,7 @@ namespace PKHeX.Core; /// Generation 9 format. public sealed class PK9 : PKM, ISanityChecksum, ITeraType, ITechRecord, IObedienceLevel, - IContestStats, IHyperTrain, IScaledSize, IScaledSize3, IFavorite, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, + IContestStats, IHyperTrain, IScaledSize, IScaledSize3, IFavorite, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, IAppliedMarkings7, IRibbonIndex, IRibbonSetAffixed, IRibbonSetRibbons, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetCommon9, IRibbonSetMarks, IRibbonSetMark8, IRibbonSetMark9 { public override ReadOnlySpan ExtraBytes => @@ -130,7 +130,7 @@ public sealed class PK9 : PKM, ISanityChecksum, ITeraType, ITechRecord, IObedien public override int AbilityNumber { get => Data[0x16] & 7; set => Data[0x16] = (byte)((Data[0x16] & ~7) | (value & 7)); } public bool IsFavorite { get => (Data[0x16] & 8) != 0; set => Data[0x16] = (byte)((Data[0x16] & ~8) | ((value ? 1 : 0) << 3)); } // unused, was in LGPE but not in SWSH // 0x17 alignment unused - public override int MarkValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x18)); set => WriteUInt16LittleEndian(Data.AsSpan(0x18), (ushort)value); } + public ushort MarkingValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x18)); set => WriteUInt16LittleEndian(Data.AsSpan(0x18), value); } // 0x1A alignment unused // 0x1B alignment unused public override uint PID { get => ReadUInt32LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt32LittleEndian(Data.AsSpan(0x1C), value); } @@ -512,23 +512,30 @@ public sealed class PK9 : PKM, ISanityChecksum, ITeraType, ITechRecord, IObedien public override int Stat_SPD { get => ReadUInt16LittleEndian(Data.AsSpan(0x154)); set => WriteUInt16LittleEndian(Data.AsSpan(0x154), (ushort)value); } #endregion - public override int MarkingCount => 6; + public int MarkingCount => 6; - public override int GetMarking(int index) + public MarkingColor GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> (index * 2)) & 3; + return (MarkingColor)((MarkingValue >> (index * 2)) & 3); } - public override void SetMarking(int index, int value) + public void SetMarking(int index, MarkingColor value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); var shift = index * 2; - MarkValue = (MarkValue & ~(0b11 << shift)) | ((value & 3) << shift); + MarkingValue = (ushort)((MarkingValue & ~(0b11 << shift)) | (((byte)value & 3) << shift)); } + public MarkingColor MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public MarkingColor MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public MarkingColor MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public MarkingColor MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public MarkingColor MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public MarkingColor MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } + public bool GetRibbon(int index) => FlagUtil.GetFlag(Data, GetRibbonByte(index), index & 7); public void SetRibbon(int index, bool value = true) => FlagUtil.SetFlag(Data, GetRibbonByte(index), index & 7, value); diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index 9c0a2359a..094120932 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -131,7 +131,6 @@ public abstract class PKM : ISpeciesForm, ITrainerID32, IGeneration, IShiny, ILa public abstract uint TSV { get; } public abstract uint PSV { get; } public abstract int Characteristic { get; } - public abstract int MarkValue { get; set; } public abstract int Met_Location { get; set; } public abstract int Egg_Location { get; set; } public abstract int OT_Friendship { get; set; } @@ -523,10 +522,6 @@ public abstract class PKM : ISpeciesForm, ITrainerID32, IGeneration, IShiny, ILa } } - public abstract int MarkingCount { get; } - public abstract int GetMarking(int index); - public abstract void SetMarking(int index, int value); - private int HPBitValPower => ((IV_HP & 2) >> 1) | ((IV_ATK & 2) >> 0) | ((IV_DEF & 2) << 1) | ((IV_SPE & 2) << 2) | ((IV_SPA & 2) << 3) | ((IV_SPD & 2) << 4); public virtual int HPPower => Format < 6 ? ((40 * HPBitValPower) / 63) + 30 : 60; diff --git a/PKHeX.Core/PKM/RK4.cs b/PKHeX.Core/PKM/RK4.cs index 3d53b8dfc..af156ecd3 100644 --- a/PKHeX.Core/PKM/RK4.cs +++ b/PKHeX.Core/PKM/RK4.cs @@ -46,7 +46,7 @@ public sealed class RK4 : G4PKM public override uint EXP { get => ReadUInt32LittleEndian(Data.AsSpan(0x10)); set => WriteUInt32LittleEndian(Data.AsSpan(0x10), value); } public override int OT_Friendship { get => Data[0x14]; set => Data[0x14] = (byte)value; } public override int Ability { get => Data[0x15]; set => Data[0x15] = (byte)value; } - public override int MarkValue { get => Data[0x16]; set => Data[0x16] = (byte)value; } + public override byte MarkingValue { get => Data[0x16]; set => Data[0x16] = value; } public override int Language { get => Data[0x17]; set => Data[0x17] = (byte)value; } public override int EV_HP { get => Data[0x18]; set => Data[0x18] = (byte)value; } public override int EV_ATK { get => Data[0x19]; set => Data[0x19] = (byte)value; } diff --git a/PKHeX.Core/PKM/Shared/G3PKM.cs b/PKHeX.Core/PKM/Shared/G3PKM.cs index b932c58e0..17b12194b 100644 --- a/PKHeX.Core/PKM/Shared/G3PKM.cs +++ b/PKHeX.Core/PKM/Shared/G3PKM.cs @@ -6,7 +6,7 @@ namespace PKHeX.Core; /// /// Generation 3 Base Class /// -public abstract class G3PKM : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonSetUnique3, IRibbonSetOnly3, IRibbonSetRibbons, IContestStats +public abstract class G3PKM : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonSetUnique3, IRibbonSetOnly3, IRibbonSetRibbons, IContestStats, IAppliedMarkings3 { protected G3PKM(byte[] data) : base(data) { } protected G3PKM([ConstantExpected] int size) : base(size) { } @@ -39,22 +39,28 @@ public abstract class G3PKM : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonS public sealed override int CurrentFriendship { get => OT_Friendship; set => OT_Friendship = value; } public sealed override int CurrentHandler { get => 0; set { } } public sealed override int Egg_Location { get => 0; set { } } - public override int MarkingCount => 4; + public int MarkingCount => 4; + public abstract byte MarkingValue { get; set; } - public override int GetMarking(int index) + public bool GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> index) & 1; + return ((MarkingValue >> index) & 1) != 0; } - public override void SetMarking(int index, int value) + public void SetMarking(int index, bool value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - MarkValue = (MarkValue & ~(1 << index)) | ((value & 1) << index); + MarkingValue = (byte)((MarkingValue & ~(1 << index)) | ((value ? 1 : 0) << index)); } + public bool MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public bool MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } // Purposefully reverse because we swap bits already and want to match Gen4+ + public bool MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public bool MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public abstract ushort SpeciesInternal { get; set; } // raw access public sealed override byte Form diff --git a/PKHeX.Core/PKM/Shared/G4PKM.cs b/PKHeX.Core/PKM/Shared/G4PKM.cs index 0fe354a08..e9ebc7ff5 100644 --- a/PKHeX.Core/PKM/Shared/G4PKM.cs +++ b/PKHeX.Core/PKM/Shared/G4PKM.cs @@ -5,7 +5,7 @@ namespace PKHeX.Core; /// Generation 4 format. public abstract class G4PKM : PKM, - IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetRibbons, IContestStats, IGroundTile + IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetRibbons, IContestStats, IGroundTile, IAppliedMarkings4 { protected G4PKM(byte[] data) : base(data) { } protected G4PKM([ConstantExpected] int size) : base(size) { } @@ -162,22 +162,30 @@ public abstract class G4PKM : PKM, public abstract byte BallDPPt { get; set; } public abstract byte BallHGSS { get; set; } public abstract byte PokeathlonStat { get; set; } - public override int MarkingCount => 6; + public int MarkingCount => 6; + public abstract byte MarkingValue { get; set; } - public override int GetMarking(int index) + public bool GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> index) & 1; + return ((MarkingValue >> index) & 1) != 0; } - public override void SetMarking(int index, int value) + public void SetMarking(int index, bool value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - MarkValue = (MarkValue & ~(1 << index)) | ((value & 1) << index); + MarkingValue = (byte)((MarkingValue & ~(1 << index)) | ((value ? 1 : 0) << index)); } + public bool MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public bool MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public bool MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public bool MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public bool MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public bool MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } + public abstract ushort Egg_LocationDP { get; set; } public abstract ushort Egg_LocationExtended { get; set; } public abstract ushort Met_LocationDP { get; set; } diff --git a/PKHeX.Core/PKM/Shared/G8PKM.cs b/PKHeX.Core/PKM/Shared/G8PKM.cs index 429e9c72c..774ee2b09 100644 --- a/PKHeX.Core/PKM/Shared/G8PKM.cs +++ b/PKHeX.Core/PKM/Shared/G8PKM.cs @@ -6,7 +6,7 @@ namespace PKHeX.Core; /// Generation 8 format. public abstract class G8PKM : PKM, ISanityChecksum, - ITechRecord, ISociability, IContestStats, IHyperTrain, IScaledSize, IGigantamax, IFavorite, IDynamaxLevel, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, IPokerusStatus, + ITechRecord, ISociability, IContestStats, IHyperTrain, IScaledSize, IGigantamax, IFavorite, IDynamaxLevel, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories, IPokerusStatus, IAppliedMarkings7, IRibbonIndex, IRibbonSetAffixed, IRibbonSetRibbons, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetCommon9, IRibbonSetMarks, IRibbonSetMark8, IRibbonSetMark9 { protected G8PKM() : base(PokeCrypto.SIZE_8PARTY) { } @@ -104,7 +104,7 @@ public abstract class G8PKM : PKM, ISanityChecksum, public bool IsFavorite { get => (Data[0x16] & 8) != 0; set => Data[0x16] = (byte)((Data[0x16] & ~8) | ((value ? 1 : 0) << 3)); } // unused, was in LGP/E but not in SW/SH public bool CanGigantamax { get => (Data[0x16] & 16) != 0; set => Data[0x16] = (byte)((Data[0x16] & ~16) | (value ? 16 : 0)); } // 0x17 alignment unused - public override int MarkValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x18)); set => WriteUInt16LittleEndian(Data.AsSpan(0x18), (ushort)value); } + public ushort MarkingValue { get => ReadUInt16LittleEndian(Data.AsSpan(0x18)); set => WriteUInt16LittleEndian(Data.AsSpan(0x18), value); } // 0x1A alignment unused // 0x1B alignment unused public override uint PID { get => ReadUInt32LittleEndian(Data.AsSpan(0x1C)); set => WriteUInt32LittleEndian(Data.AsSpan(0x1C), value); } @@ -454,23 +454,30 @@ public abstract class G8PKM : PKM, ISanityChecksum, public override int Stat_SPD { get => ReadUInt16LittleEndian(Data.AsSpan(0x154)); set => WriteUInt16LittleEndian(Data.AsSpan(0x154), (ushort)value); } #endregion - public override int MarkingCount => 6; + public int MarkingCount => 6; - public override int GetMarking(int index) + public MarkingColor GetMarking(int index) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); - return (MarkValue >> (index * 2)) & 3; + return (MarkingColor)((MarkingValue >> (index * 2)) & 3); } - public override void SetMarking(int index, int value) + public void SetMarking(int index, MarkingColor value) { if ((uint)index >= MarkingCount) throw new ArgumentOutOfRangeException(nameof(index)); var shift = index * 2; - MarkValue = (MarkValue & ~(0b11 << shift)) | ((value & 3) << shift); + MarkingValue = (ushort)((MarkingValue & ~(0b11 << shift)) | (((byte)value & 3) << shift)); } + public MarkingColor MarkingCircle { get => GetMarking(0); set => SetMarking(0, value); } + public MarkingColor MarkingTriangle { get => GetMarking(1); set => SetMarking(1, value); } + public MarkingColor MarkingSquare { get => GetMarking(2); set => SetMarking(2, value); } + public MarkingColor MarkingHeart { get => GetMarking(3); set => SetMarking(3, value); } + public MarkingColor MarkingStar { get => GetMarking(4); set => SetMarking(4, value); } + public MarkingColor MarkingDiamond { get => GetMarking(5); set => SetMarking(5, value); } + public bool GetRibbon(int index) => FlagUtil.GetFlag(Data, GetRibbonByte(index), index & 7); public void SetRibbon(int index, bool value = true) => FlagUtil.SetFlag(Data, GetRibbonByte(index), index & 7, value); diff --git a/PKHeX.Core/PKM/Shared/GBPKM.cs b/PKHeX.Core/PKM/Shared/GBPKM.cs index 0744392f0..c14f77b0c 100644 --- a/PKHeX.Core/PKM/Shared/GBPKM.cs +++ b/PKHeX.Core/PKM/Shared/GBPKM.cs @@ -120,7 +120,6 @@ public abstract class GBPKM : PKM public sealed override uint TSV => 0x0000; public sealed override uint PSV => 0xFFFF; public sealed override int Characteristic => -1; - public sealed override int MarkValue { get => 0; set { } } public sealed override int Ability { get => -1; set { } } public sealed override int CurrentHandler { get => 0; set { } } public sealed override int Egg_Location { get => 0; set { } } @@ -181,9 +180,6 @@ public abstract class GBPKM : PKM public int IV_SPC { get => (DV16 >> 0) & 0xF; set => DV16 = (ushort)((DV16 & ~(0xF << 0)) | (ushort)((value > 0xF ? 0xF : value) << 0)); } public sealed override int IV_SPA { get => IV_SPC; set => IV_SPC = value; } public sealed override int IV_SPD { get => IV_SPC; set { } } - public override int MarkingCount => 0; - public override int GetMarking(int index) => 0; - public override void SetMarking(int index, int value) { } public void SetNotNicknamed() => SetNotNicknamed(GuessedLanguage()); public abstract void SetNotNicknamed(int language); diff --git a/PKHeX.Core/PKM/XK3.cs b/PKHeX.Core/PKM/XK3.cs index 2884b6adb..e4251ace6 100644 --- a/PKHeX.Core/PKM/XK3.cs +++ b/PKHeX.Core/PKM/XK3.cs @@ -44,7 +44,7 @@ public sealed class XK3 : G3PKM, IShadowCapture public override int Stat_Level { get => Data[0x11]; set => Data[0x11] = (byte)value; } public override byte CNT_Sheen { get => Data[0x12]; set => Data[0x12] = value; } public override int PKRS_Strain { get => Data[0x13] & 0xF; set => Data[0x13] = (byte)(value & 0xF); } - public override int MarkValue { get => SwapBits(Data[0x14], 1, 2); set => Data[0x14] = (byte)SwapBits(value, 1, 2); } + public override byte MarkingValue { get => (byte)SwapBits(Data[0x14], 1, 2); set => Data[0x14] = (byte)SwapBits(value, 1, 2); } public override int PKRS_Days { get => Math.Max((sbyte)Data[0x15], (sbyte)0); set => Data[0x15] = (byte)(value == 0 ? 0xFF : value & 0xF); } // 0x16-0x1C Battle Related private int XDPKMFLAGS { get => Data[0x1D]; set => Data[0x1D] = (byte)value; } diff --git a/PKHeX.WinForms/Controls/PKM Editor/DrawConfig.cs b/PKHeX.WinForms/Controls/PKM Editor/DrawConfig.cs index 21a8422bf..a92c28dd6 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/DrawConfig.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/DrawConfig.cs @@ -80,12 +80,12 @@ public sealed class DrawConfig : IDisposable _ => TextColor, }; - public bool GetMarkingColor(int markval, out Color c) + public bool GetMarkingColor(MarkingColor markval, out Color c) { switch (markval) { - case 1: c = MarkBlue; return true; - case 2: c = MarkPink; return true; + case MarkingColor.Blue: c = MarkBlue; return true; + case MarkingColor.Pink: c = MarkPink; return true; default: c = MarkDefault; return false; // recolor not required } } diff --git a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs index 8121178b2..516545ae9 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs @@ -496,27 +496,30 @@ public sealed partial class PKMEditor : UserControl, IMainEditor private void SetMarkings() { - var pba = Markings; - var count = Entity.MarkingCount; - for (int i = 0; i < pba.Length; i++) - pba[i].Image = GetMarkSprite(pba[i], i < count && Entity.GetMarking(i) != 0); - PB_MarkShiny.Image = GetMarkSprite(PB_MarkShiny, !BTN_Shinytize.Enabled); PB_MarkCured.Image = GetMarkSprite(PB_MarkCured, CHK_Cured.Checked); PB_Favorite.Image = GetMarkSprite(PB_Favorite, Entity is IFavorite { IsFavorite: true }); PB_Origin.Image = GetOriginSprite(Entity); - // Colored Markings - if (Entity.Format < 7) - return; - - for (int i = 0; i < count; i++) + var pba = Markings; + if (Entity is IAppliedMarkings b) { - if (!Draw.GetMarkingColor(Entity.GetMarking(i), out Color c)) - continue; - var pb = pba[i]; - pb.Image = ImageUtil.ChangeAllColorTo(pb.Image, c); + for (int i = 0; i < b.MarkingCount; i++) + pba[i].Image = GetMarkSprite(pba[i], b.GetMarking(i)); + } + else if (Entity is IAppliedMarkings c) + { + for (int i = 0; i < pba.Length; i++) + { + var pb = pba[i]; + var state = c.GetMarking(i); + var opaque = Draw.GetMarkingColor(state, out var color); + var img = GetMarkSprite(pb, opaque); + if (opaque) + img = ImageUtil.ChangeAllColorTo(img, color); + pb.Image = img; + } } }