Reimplement applied Markings individual get/set

Closes #4156
Extracts to an interface, varied implementations in the appropriate PKM classes. No longer an abstract property inherited from the base `PKM` class.
This commit is contained in:
Kurt 2024-01-09 20:50:29 -08:00
parent c66fc2f3bf
commit 0ca20ff096
26 changed files with 322 additions and 154 deletions

View file

@ -1,9 +1,9 @@
using System;
using System;
namespace PKHeX.Core;
/// <summary>
/// Logic for modifying the <see cref="PKM.MarkValue"/>.
/// Logic for modifying the <see cref="IAppliedMarkings"/>.
/// </summary>
public static class MarkingApplicator
{
@ -14,21 +14,40 @@ public static class MarkingApplicator
public static Func<PKM, Func<int, int, int>> MarkingMethod { get; set; } = FlagHighLow;
/// <summary>
/// Sets the <see cref="PKM.MarkValue"/> to indicate flawless (or near-flawless) <see cref="PKM.IVs"/>.
/// Sets the applied Markings to indicate flawless (or near-flawless) <see cref="PKM.IVs"/>.
/// </summary>
/// <param name="pk">Pokémon to modify.</param>
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<MarkingColor> c)
SetMarkings(c, pk);
else if (pk is IAppliedMarkings<bool> b)
SetMarkings(b, pk);
}
private static void SetMarkings(this IAppliedMarkings<bool> 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<MarkingColor> 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));
}
/// <summary>
@ -37,18 +56,19 @@ public static class MarkingApplicator
/// <param name="pk">Pokémon to modify.</param>
/// <param name="index">Marking index to toggle</param>
/// <returns>Current marking value</returns>
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<MarkingColor> c)
c.SetMarking(index, c.GetMarking(index).Next());
else if (pk is IAppliedMarkings<bool> 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<int, int, int> FlagHighLow(PKM pk)

View file

@ -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";

View file

@ -4,7 +4,7 @@ using static PKHeX.Core.CheckIdentifier;
namespace PKHeX.Core;
/// <summary>
/// Verifies the <see cref="PKM.MarkValue"/>.
/// Verifies the <see cref="IAppliedMarkings"/>.
/// </summary>
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;
}
}

View file

@ -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; }

View file

@ -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?

View file

@ -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<byte> 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;

View file

@ -112,7 +112,7 @@ public sealed class GameDataPK8 : HomeOptional1, IGameDataSide<PK8>, 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))

View file

@ -5,7 +5,8 @@ using static PKHeX.Core.GameVersion;
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 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

View file

@ -0,0 +1,90 @@
namespace PKHeX.Core;
/// <summary>
/// Indicates if the object is capable of being marked by the player with simple shapes.
/// </summary>
public interface IAppliedMarkings
{
/// <summary>
/// Count of unique markings that can be applied to the object.
/// </summary>
int MarkingCount { get; }
}
public interface IAppliedMarkings<T> : IAppliedMarkings where T : unmanaged
{
/// <summary>
/// Gets the marking value at the given index.
/// </summary>
/// <param name="index">Index of the marking to get.</param>
/// <returns>Marking value at the given index.</returns>
T GetMarking(int index);
/// <summary>
/// Sets the marking value at the given index.
/// </summary>
/// <param name="index">Index of the marking to set.</param>
/// <param name="value">Value to set the marking to.</param>
void SetMarking(int index, T value);
}
/// <summary>
/// Generation 3 Markings
/// </summary>
public interface IAppliedMarkings3 : IAppliedMarkings<bool>
{
/// <summary>
/// Backing value for the packed bits.
/// </summary>
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; }
}
/// <summary>
/// Generation 4-6 Markings
/// </summary>
public interface IAppliedMarkings4 : IAppliedMarkings3
{
bool MarkingStar { get; set; }
bool MarkingDiamond { get; set; }
}
/// <summary>
/// Generation 7+ Markings
/// </summary>
public interface IAppliedMarkings7 : IAppliedMarkings<MarkingColor>
{
/// <summary>
/// Backing value for the packed bits.
/// </summary>
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
{
/// <summary>
/// Not marked.
/// </summary>
None = 0,
/// <summary>
/// Blue marking.
/// </summary>
Blue = 1,
/// <summary>
/// Pink marking.
/// </summary>
Pink = 2,
}

View file

@ -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);

View file

@ -5,7 +5,7 @@ using static System.Buffers.Binary.BinaryPrimitives;
namespace PKHeX.Core;
/// <summary> Generation 7 <see cref="PKM"/> format used for <see cref="GameVersion.GG"/>. </summary>
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<ushort> 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.

View file

@ -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,

View file

@ -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; }

View file

@ -7,7 +7,7 @@ namespace PKHeX.Core;
/// <summary> Generation 5 <see cref="PKM"/> format. </summary>
public sealed class PK5 : PKM, ISanityChecksum,
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetRibbons,
IContestStats, IGroundTile
IContestStats, IGroundTile, IAppliedMarkings4
{
public override ReadOnlySpan<ushort> 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,

View file

@ -6,7 +6,7 @@ namespace PKHeX.Core;
/// <summary> Generation 6 <see cref="PKM"/> format. </summary>
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<ushort> 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

View file

@ -6,7 +6,7 @@ namespace PKHeX.Core;
/// <summary> Generation 7 <see cref="PKM"/> format. </summary>
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<ushort> 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.

View file

@ -6,7 +6,7 @@ namespace PKHeX.Core;
/// <summary> Generation 9 <see cref="PKM"/> format. </summary>
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<ushort> 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);

View file

@ -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;

View file

@ -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; }

View file

@ -6,7 +6,7 @@ namespace PKHeX.Core;
/// <summary>
/// Generation 3 Base <see cref="PKM"/> Class
/// </summary>
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

View file

@ -5,7 +5,7 @@ namespace PKHeX.Core;
/// <summary> Generation 4 <see cref="PKM"/> format. </summary>
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; }

View file

@ -6,7 +6,7 @@ namespace PKHeX.Core;
/// <summary> Generation 8 <see cref="PKM"/> format. </summary>
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);

View file

@ -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);

View file

@ -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; }

View file

@ -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
}
}

View file

@ -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<bool> 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<MarkingColor> 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;
}
}
}