Narrow ribbon count type from int->byte, split interface

Fix RibbonVerifier4 not checking gen4 contest ribbons correctly
Split IRibbonCommon6 to have memory ribbons separate, as they are not implemented in mystery gifts. Also, we can add the boolean flags to the interface, and check that the boolean is set if count is nonzero.
Fix adding ribbons to Gen8 gift templates
Improve Gen8 template ribbon fetch (no closure, faster IndexOf)
This commit is contained in:
Kurt 2022-08-23 21:25:22 -07:00
parent eb2cef10c9
commit 26b1453002
21 changed files with 137 additions and 110 deletions

View file

@ -55,7 +55,9 @@ public static class RibbonIndex3Extensions
if (pk is IRibbonSetOnly3 o3)
{
var value = state ? 4 : 0;
const byte max = 4;
const byte min = 0;
byte value = state ? max : min;
if (r is Cool)
o3.RibbonCountG3Cool = value;
else if (r is Beauty)

View file

@ -9,7 +9,8 @@ public static class RibbonVerifierCommon6
{
public static void Parse(this IRibbonSetCommon6 r, RibbonVerifierArguments args, ref RibbonResultList list)
{
GetInvalidRibbons6Memory(r, args, ref list);
if (r is IRibbonSetMemory6 m)
GetInvalidRibbons6Memory(m, args, ref list);
var pk = args.Entity;
var evos = args.History;
@ -88,12 +89,12 @@ public static class RibbonVerifierCommon6
FlagContest(r, ref list);
}
private static void GetInvalidRibbons6Memory(IRibbonSetCommon6 r, RibbonVerifierArguments args, ref RibbonResultList list)
private static void GetInvalidRibbons6Memory(IRibbonSetMemory6 r, RibbonVerifierArguments args, ref RibbonResultList list)
{
(int contest, int battle) = RibbonRules.GetMaxMemoryCounts(args.History, args.Entity, args.Encounter);
if (r.RibbonCountMemoryContest > contest)
if (r.RibbonCountMemoryContest > contest || r.HasContestMemoryRibbon != (r.RibbonCountMemoryContest != 0))
list.Add(CountMemoryContest);
if (r.RibbonCountMemoryBattle > battle)
if (r.RibbonCountMemoryBattle > battle || r.HasBattleMemoryRibbon != (r.RibbonCountMemoryBattle != 0))
list.Add(CountMemoryBattle);
}

View file

@ -56,15 +56,15 @@ public static class RibbonVerifierUnique4
private static void AddMissingContest4(IRibbonSetUnique4 r, ref RibbonResultList list)
{
static void CheckSet(bool Master, bool Hyper, bool Super, bool Initial, ref RibbonResultList list, RibbonIndex4 index)
static void CheckSet(bool Master, bool Ultra, bool Great, bool Initial, ref RibbonResultList list, RibbonIndex4 index)
{
bool top = Master;
if (Hyper)
if (Ultra)
top = true;
else if (top)
list.Add((RibbonIndex4)((byte)index + 2));
if (Super)
if (Great)
top = true;
else if (top)
list.Add((RibbonIndex4)((byte)index + 1));
@ -72,11 +72,11 @@ public static class RibbonVerifierUnique4
if (top && !Initial)
list.Add(index);
}
CheckSet(r.RibbonG3CoolMaster, r.RibbonG3CoolHyper, r.RibbonG3CoolSuper, r.RibbonG3Cool, ref list, RibbonIndex4.Cool);
CheckSet(r.RibbonG3BeautyMaster, r.RibbonG3BeautyHyper, r.RibbonG3BeautySuper, r.RibbonG3Beauty, ref list, RibbonIndex4.Beauty);
CheckSet(r.RibbonG3CuteMaster , r.RibbonG3CuteHyper, r.RibbonG3CuteSuper, r.RibbonG3Cute, ref list, RibbonIndex4.Cute);
CheckSet(r.RibbonG3SmartMaster, r.RibbonG3SmartHyper, r.RibbonG3SmartSuper, r.RibbonG3Smart, ref list, RibbonIndex4.Smart);
CheckSet(r.RibbonG3ToughMaster, r.RibbonG3ToughHyper, r.RibbonG3ToughSuper, r.RibbonG3Tough, ref list, RibbonIndex4.Tough);
CheckSet(r.RibbonG4CoolMaster, r.RibbonG4CoolUltra, r.RibbonG4CoolGreat, r.RibbonG4Cool, ref list, RibbonIndex4.Cool);
CheckSet(r.RibbonG4BeautyMaster, r.RibbonG4BeautyUltra, r.RibbonG4BeautyGreat, r.RibbonG4Beauty, ref list, RibbonIndex4.Beauty);
CheckSet(r.RibbonG4CuteMaster , r.RibbonG4CuteUltra, r.RibbonG4CuteGreat, r.RibbonG4Cute, ref list, RibbonIndex4.Cute);
CheckSet(r.RibbonG4SmartMaster, r.RibbonG4SmartUltra, r.RibbonG4SmartGreat, r.RibbonG4Smart, ref list, RibbonIndex4.Smart);
CheckSet(r.RibbonG4ToughMaster, r.RibbonG4ToughUltra, r.RibbonG4ToughGreat, r.RibbonG4Tough, ref list, RibbonIndex4.Tough);
}
private static void FlagAnyAbility(IRibbonSetUnique4 r, ref RibbonResultList list)
@ -115,21 +115,21 @@ public static class RibbonVerifierUnique4
private static void FlagAnyContest4(IRibbonSetUnique4 r, ref RibbonResultList list)
{
static void CheckSet(bool Master, bool Hyper, bool Super, bool Initial, ref RibbonResultList list, RibbonIndex4 index)
static void CheckSet(bool Master, bool Ultra, bool Great, bool Initial, ref RibbonResultList list, RibbonIndex4 index)
{
if (Master)
list.Add((RibbonIndex4)((byte)index + 3));
if (Hyper)
if (Ultra)
list.Add((RibbonIndex4)((byte)index + 2));
if (Super)
if (Great)
list.Add((RibbonIndex4)((byte)index + 1));
if (Initial)
list.Add(index);
}
CheckSet(r.RibbonG3CoolMaster, r.RibbonG3CoolHyper, r.RibbonG3CoolSuper, r.RibbonG3Cool, ref list, RibbonIndex4.Cool);
CheckSet(r.RibbonG3BeautyMaster, r.RibbonG3BeautyHyper, r.RibbonG3BeautySuper, r.RibbonG3Beauty, ref list, RibbonIndex4.Beauty);
CheckSet(r.RibbonG3CuteMaster , r.RibbonG3CuteHyper, r.RibbonG3CuteSuper, r.RibbonG3Cute, ref list, RibbonIndex4.Cute);
CheckSet(r.RibbonG3SmartMaster, r.RibbonG3SmartHyper, r.RibbonG3SmartSuper, r.RibbonG3Smart, ref list, RibbonIndex4.Smart);
CheckSet(r.RibbonG3ToughMaster, r.RibbonG3ToughHyper, r.RibbonG3ToughSuper, r.RibbonG3Tough, ref list, RibbonIndex4.Tough);
CheckSet(r.RibbonG4CoolMaster, r.RibbonG4CoolUltra, r.RibbonG4CoolGreat, r.RibbonG4Cool, ref list, RibbonIndex4.Cool);
CheckSet(r.RibbonG4BeautyMaster, r.RibbonG4BeautyUltra, r.RibbonG4BeautyGreat, r.RibbonG4Beauty, ref list, RibbonIndex4.Beauty);
CheckSet(r.RibbonG4CuteMaster , r.RibbonG4CuteUltra, r.RibbonG4CuteGreat, r.RibbonG4Cute, ref list, RibbonIndex4.Cute);
CheckSet(r.RibbonG4SmartMaster, r.RibbonG4SmartUltra, r.RibbonG4SmartGreat, r.RibbonG4Smart, ref list, RibbonIndex4.Smart);
CheckSet(r.RibbonG4ToughMaster, r.RibbonG4ToughUltra, r.RibbonG4ToughGreat, r.RibbonG4Tough, ref list, RibbonIndex4.Tough);
}
}

View file

@ -751,9 +751,6 @@ public sealed class WA8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
public bool RibbonMasterCleverness { get => this.GetRibbonIndex(MasterCleverness); set => this.SetRibbonIndex(MasterCleverness, value); }
public bool RibbonMasterToughness { get => this.GetRibbonIndex(MasterToughness); set => this.SetRibbonIndex(MasterToughness, value); }
public int RibbonCountMemoryContest { get => 0; set { } }
public int RibbonCountMemoryBattle { get => 0; set { } }
public bool RibbonChampionAlola { get => this.GetRibbonIndex(ChampionAlola); set => this.SetRibbonIndex(ChampionAlola, value); }
public bool RibbonBattleRoyale { get => this.GetRibbonIndex(BattleRoyale); set => this.SetRibbonIndex(BattleRoyale, value); }
public bool RibbonBattleTreeGreat { get => this.GetRibbonIndex(BattleTreeGreat); set => this.SetRibbonIndex(BattleTreeGreat, value); }
@ -809,7 +806,7 @@ public sealed class WA8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
public bool RibbonTwinklingStar { get => this.GetRibbonIndex(TwinklingStar); set => this.SetRibbonIndex(TwinklingStar, value); }
public bool RibbonPioneer { get => this.GetRibbonIndex(Pioneer); set => this.SetRibbonIndex(Pioneer, value); }
public int GetRibbonByte(int index) => Array.FindIndex(Data, RibbonBytesOffset, RibbonBytesCount, z => z == index);
public int GetRibbonByte(int index) => Array.IndexOf(Data, (byte)index, RibbonBytesOffset, RibbonBytesCount);
public bool GetRibbon(int index) => GetRibbonByte(index) >= 0;
public void SetRibbon(int index, bool value = true)
@ -821,8 +818,8 @@ public sealed class WA8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
{
if (GetRibbon(index))
return;
var openIndex = Array.FindIndex(Data, RibbonBytesOffset, RibbonBytesCount, z => z != RibbonByteNone);
if (openIndex < 0)
var openIndex = Array.IndexOf(Data, RibbonByteNone, RibbonBytesOffset, RibbonBytesCount);
if (openIndex == -1) // Full?
throw new ArgumentOutOfRangeException(nameof(index));
SetRibbonAtIndex(openIndex, (byte)index);
}

View file

@ -742,9 +742,6 @@ public sealed class WB8 : DataMysteryGift, ILangNick, INature, IRibbonIndex, ICo
public bool RibbonMasterCleverness { get => this.GetRibbonIndex(MasterCleverness); set => this.SetRibbonIndex(MasterCleverness, value); }
public bool RibbonMasterToughness { get => this.GetRibbonIndex(MasterToughness); set => this.SetRibbonIndex(MasterToughness, value); }
public int RibbonCountMemoryContest { get => 0; set { } }
public int RibbonCountMemoryBattle { get => 0; set { } }
public bool RibbonChampionAlola { get => this.GetRibbonIndex(ChampionAlola); set => this.SetRibbonIndex(ChampionAlola, value); }
public bool RibbonBattleRoyale { get => this.GetRibbonIndex(BattleRoyale); set => this.SetRibbonIndex(BattleRoyale, value); }
public bool RibbonBattleTreeGreat { get => this.GetRibbonIndex(BattleTreeGreat); set => this.SetRibbonIndex(BattleTreeGreat, value); }
@ -800,7 +797,7 @@ public sealed class WB8 : DataMysteryGift, ILangNick, INature, IRibbonIndex, ICo
public bool RibbonTwinklingStar { get => this.GetRibbonIndex(TwinklingStar); set => this.SetRibbonIndex(TwinklingStar, value); }
public bool RibbonPioneer { get => this.GetRibbonIndex(Pioneer); set => this.SetRibbonIndex(Pioneer, value); }
public int GetRibbonByte(int index) => Array.FindIndex(Data, RibbonBytesOffset, RibbonBytesCount, z => z == index);
public int GetRibbonByte(int index) => Array.IndexOf(Data, (byte)index, RibbonBytesOffset, RibbonBytesCount);
public bool GetRibbon(int index) => GetRibbonByte(index) >= 0;
public void SetRibbon(int index, bool value = true)
@ -812,8 +809,8 @@ public sealed class WB8 : DataMysteryGift, ILangNick, INature, IRibbonIndex, ICo
{
if (GetRibbon(index))
return;
var openIndex = Array.FindIndex(Data, RibbonBytesOffset, RibbonBytesCount, z => z != RibbonByteNone);
if (openIndex < 0)
var openIndex = Array.IndexOf(Data, RibbonByteNone, RibbonBytesOffset, RibbonBytesCount);
if (openIndex == -1) // Full?
throw new ArgumentOutOfRangeException(nameof(index));
SetRibbonAtIndex(openIndex, (byte)index);
}

View file

@ -764,9 +764,6 @@ public sealed class WC8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
public bool RibbonMasterCleverness { get => this.GetRibbonIndex(MasterCleverness); set => this.SetRibbonIndex(MasterCleverness, value); }
public bool RibbonMasterToughness { get => this.GetRibbonIndex(MasterToughness); set => this.SetRibbonIndex(MasterToughness, value); }
public int RibbonCountMemoryContest { get => 0; set { } }
public int RibbonCountMemoryBattle { get => 0; set { } }
public bool RibbonChampionAlola { get => this.GetRibbonIndex(ChampionAlola); set => this.SetRibbonIndex(ChampionAlola, value); }
public bool RibbonBattleRoyale { get => this.GetRibbonIndex(BattleRoyale); set => this.SetRibbonIndex(BattleRoyale, value); }
public bool RibbonBattleTreeGreat { get => this.GetRibbonIndex(BattleTreeGreat); set => this.SetRibbonIndex(BattleTreeGreat, value); }
@ -822,7 +819,7 @@ public sealed class WC8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
public bool RibbonTwinklingStar { get => this.GetRibbonIndex(TwinklingStar); set => this.SetRibbonIndex(TwinklingStar, value); }
public bool RibbonPioneer { get => this.GetRibbonIndex(Pioneer); set => this.SetRibbonIndex(Pioneer, value); }
public int GetRibbonByte(int index) => Array.FindIndex(Data, RibbonBytesOffset, RibbonBytesCount, z => z == index);
public int GetRibbonByte(int index) => Array.IndexOf(Data, (byte)index, RibbonBytesOffset, RibbonBytesCount);
public bool GetRibbon(int index) => GetRibbonByte(index) >= 0;
public void SetRibbon(int index, bool value = true)
@ -834,8 +831,8 @@ public sealed class WC8 : DataMysteryGift, ILangNick, INature, IGigantamax, IDyn
{
if (GetRibbon(index))
return;
var openIndex = Array.FindIndex(Data, RibbonBytesOffset, RibbonBytesCount, z => z != RibbonByteNone);
if (openIndex < 0)
var openIndex = Array.IndexOf(Data, RibbonByteNone, RibbonBytesOffset, RibbonBytesCount);
if (openIndex == -1) // Full?
throw new ArgumentOutOfRangeException(nameof(index));
SetRibbonAtIndex(openIndex, (byte)index);
}

View file

@ -145,11 +145,11 @@ public sealed class CK3 : G3PKM, IShadowPKM
public override byte CNT_Cute { get => Data[0xB4]; set => Data[0xB4] = value; }
public override byte CNT_Smart { get => Data[0xB5]; set => Data[0xB5] = value; }
public override byte CNT_Tough { get => Data[0xB6]; set => Data[0xB6] = value; }
public override int RibbonCountG3Cool { get => Data[0xB7]; set => Data[0xB7] = (byte)value; }
public override int RibbonCountG3Beauty { get => Data[0xB8]; set => Data[0xB8] = (byte)value; }
public override int RibbonCountG3Cute { get => Data[0xB9]; set => Data[0xB9] = (byte)value; }
public override int RibbonCountG3Smart { get => Data[0xBA]; set => Data[0xBA] = (byte)value; }
public override int RibbonCountG3Tough { get => Data[0xBB]; set => Data[0xBB] = (byte)value; }
public override byte RibbonCountG3Cool { get => Data[0xB7]; set => Data[0xB7] = value; }
public override byte RibbonCountG3Beauty { get => Data[0xB8]; set => Data[0xB8] = value; }
public override byte RibbonCountG3Cute { get => Data[0xB9]; set => Data[0xB9] = value; }
public override byte RibbonCountG3Smart { get => Data[0xBA]; set => Data[0xBA] = value; }
public override byte RibbonCountG3Tough { get => Data[0xBB]; set => Data[0xBB] = value; }
public override byte CNT_Sheen { get => Data[0xBC]; set => Data[0xBC] = value; }
// Ribbons

View file

@ -5,7 +5,7 @@ namespace PKHeX.Core;
/// <summary> Generation 8 <see cref="PKM"/> format. </summary>
public abstract class G8PKM : PKM, ISanityChecksum, IMoveReset,
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8, IRibbonSetAffixed, ITechRecord8, ISociability,
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8, IRibbonSetAffixed, ITechRecord8, ISociability,
IContestStats, IContestStatsMutable, IHyperTrain, IScaledSize, IGigantamax, IFavorite, IDynamaxLevel, IRibbonIndex, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories
{
protected G8PKM() : base(PokeCrypto.SIZE_8PARTY) { }
@ -227,8 +227,8 @@ public abstract class G8PKM : PKM, ISanityChecksum, IMoveReset,
public bool RibbonMarkBlizzard { get => FlagUtil.GetFlag(Data, 0x3B, 5); set => FlagUtil.SetFlag(Data, 0x3B, 5, value); }
public bool RibbonMarkDry { get => FlagUtil.GetFlag(Data, 0x3B, 6); set => FlagUtil.SetFlag(Data, 0x3B, 6, value); }
public bool RibbonMarkSandstorm { get => FlagUtil.GetFlag(Data, 0x3B, 7); set => FlagUtil.SetFlag(Data, 0x3B, 7, value); }
public int RibbonCountMemoryContest { get => Data[0x3C]; set => HasContestMemoryRibbon = (Data[0x3C] = (byte)value) != 0; }
public int RibbonCountMemoryBattle { get => Data[0x3D]; set => HasBattleMemoryRibbon = (Data[0x3D] = (byte)value) != 0; }
public byte RibbonCountMemoryContest { get => Data[0x3C]; set => HasContestMemoryRibbon = (Data[0x3C] = value) != 0; }
public byte RibbonCountMemoryBattle { get => Data[0x3D]; set => HasBattleMemoryRibbon = (Data[0x3D] = value) != 0; }
// 0x3E padding
// 0x3F padding

View file

@ -7,7 +7,7 @@ namespace PKHeX.Core;
/// Core game data storage, format 1.
/// </summary>
public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature, IContestStats, IContestStatsMutable, IScaledSize, ITrainerMemories, IHandlerLanguage, IBattleVersion, IHyperTrain, IFormArgument, IFavorite,
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8
{
// Internal Attributes set on creation
public readonly byte[] Data; // Raw Storage
@ -131,8 +131,8 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
public bool RibbonMarkDry { get => GetFlag(0x3B, 6); set => SetFlag(0x3B, 6, value); }
public bool RibbonMarkSandstorm { get => GetFlag(0x3B, 7); set => SetFlag(0x3B, 7, value); }
public int RibbonCountMemoryContest { get => Data[0x3C]; set => HasContestMemoryRibbon = (Data[0x3C] = (byte)value) != 0; }
public int RibbonCountMemoryBattle { get => Data[0x3D]; set => HasBattleMemoryRibbon = (Data[0x3D] = (byte)value) != 0; }
public byte RibbonCountMemoryContest { get => Data[0x3C]; set => HasContestMemoryRibbon = (Data[0x3C] = value) != 0; }
public byte RibbonCountMemoryBattle { get => Data[0x3D]; set => HasBattleMemoryRibbon = (Data[0x3D] = value) != 0; }
// 0x3E Ribbon 3
public bool RibbonMarkMisty { get => GetFlag(0x3E, 0); set => SetFlag(0x3E, 0, value); }
@ -421,6 +421,8 @@ public sealed class GameDataCore : IHomeTrack, ISpeciesForm, ITrainerID, INature
this.CopyRibbonSetCommon4(c4);
if (pk is IRibbonSetCommon6 c6)
this.CopyRibbonSetCommon6(c6);
if (pk is IRibbonSetMemory6 m6)
this.CopyRibbonSetMemory6(m6);
if (pk is IRibbonSetCommon7 c7)
this.CopyRibbonSetCommon7(c7);
if (pk is IRibbonSetCommon8 c8)

View file

@ -7,7 +7,7 @@ namespace PKHeX.Core;
/// <summary> Generation 8 <see cref="PKM"/> format. </summary>
public sealed class PA8 : PKM, ISanityChecksum, IMoveReset,
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8, IRibbonSetAffixed, IGanbaru, IAlpha, INoble, ITechRecord8, ISociability, IMoveShop8Mastery,
IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7, IRibbonSetCommon8, IRibbonSetMark8, IRibbonSetAffixed, IGanbaru, IAlpha, INoble, ITechRecord8, ISociability, IMoveShop8Mastery,
IContestStats, IContestStatsMutable, IHyperTrain, IScaledSizeValue, IGigantamax, IFavorite, IDynamaxLevel, IRibbonIndex, IHandlerLanguage, IFormArgument, IHomeTrack, IBattleVersion, ITrainerMemories
{
private static readonly ushort[] Unused =
@ -256,8 +256,8 @@ public sealed class PA8 : PKM, ISanityChecksum, IMoveReset,
public bool RibbonMarkBlizzard { get => FlagUtil.GetFlag(Data, 0x3B, 5); set => FlagUtil.SetFlag(Data, 0x3B, 5, value); }
public bool RibbonMarkDry { get => FlagUtil.GetFlag(Data, 0x3B, 6); set => FlagUtil.SetFlag(Data, 0x3B, 6, value); }
public bool RibbonMarkSandstorm { get => FlagUtil.GetFlag(Data, 0x3B, 7); set => FlagUtil.SetFlag(Data, 0x3B, 7, value); }
public int RibbonCountMemoryContest { get => Data[0x3C]; set => HasContestMemoryRibbon = (Data[0x3C] = (byte)value) != 0; }
public int RibbonCountMemoryBattle { get => Data[0x3D]; set => HasBattleMemoryRibbon = (Data[0x3D] = (byte)value) != 0; }
public byte RibbonCountMemoryContest { get => Data[0x3C]; set => HasContestMemoryRibbon = (Data[0x3C] = value) != 0; }
public byte RibbonCountMemoryBattle { get => Data[0x3D]; set => HasBattleMemoryRibbon = (Data[0x3D] = value) != 0; }
public ushort AlphaMove { get => ReadUInt16LittleEndian(Data.AsSpan(0x3E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x3E), value); }
@ -523,7 +523,7 @@ public sealed class PA8 : PKM, ISanityChecksum, IMoveReset,
FlagUtil.SetFlag(Data, 0x155 + ofs, index & 7, value);
}
public bool GetPurchasedRecordFlagAny() => Array.FindIndex(Data, 0x155, 8, z => z != 0) >= 0;
public bool GetPurchasedRecordFlagAny() => Array.FindIndex(Data, 0x155, 8, static z => z != 0) >= 0;
public int GetPurchasedCount()
{

View file

@ -158,11 +158,11 @@ public sealed class PK3 : G3PKM, ISanityChecksum
public override bool AbilityBit { get => IV32 >> 31 == 1; set => IV32 = (IV32 & 0x7FFFFFFF) | (value ? 1u << 31 : 0u); }
private uint RIB0 { get => ReadUInt32LittleEndian(Data.AsSpan(0x4C)); set => WriteUInt32LittleEndian(Data.AsSpan(0x4C), value); }
public override int RibbonCountG3Cool { get => (int)(RIB0 >> 00) & 7; set => RIB0 = ((RIB0 & ~(7u << 00)) | ((uint)(value & 7) << 00)); }
public override int RibbonCountG3Beauty { get => (int)(RIB0 >> 03) & 7; set => RIB0 = ((RIB0 & ~(7u << 03)) | ((uint)(value & 7) << 03)); }
public override int RibbonCountG3Cute { get => (int)(RIB0 >> 06) & 7; set => RIB0 = ((RIB0 & ~(7u << 06)) | ((uint)(value & 7) << 06)); }
public override int RibbonCountG3Smart { get => (int)(RIB0 >> 09) & 7; set => RIB0 = ((RIB0 & ~(7u << 09)) | ((uint)(value & 7) << 09)); }
public override int RibbonCountG3Tough { get => (int)(RIB0 >> 12) & 7; set => RIB0 = ((RIB0 & ~(7u << 12)) | ((uint)(value & 7) << 12)); }
public override byte RibbonCountG3Cool { get => (byte)((RIB0 >> 00) & 7); set => RIB0 = ((RIB0 & ~(7u << 00)) | ((uint)(value & 7) << 00)); }
public override byte RibbonCountG3Beauty { get => (byte)((RIB0 >> 03) & 7); set => RIB0 = ((RIB0 & ~(7u << 03)) | ((uint)(value & 7) << 03)); }
public override byte RibbonCountG3Cute { get => (byte)((RIB0 >> 06) & 7); set => RIB0 = ((RIB0 & ~(7u << 06)) | ((uint)(value & 7) << 06)); }
public override byte RibbonCountG3Smart { get => (byte)((RIB0 >> 09) & 7); set => RIB0 = ((RIB0 & ~(7u << 09)) | ((uint)(value & 7) << 09)); }
public override byte RibbonCountG3Tough { get => (byte)((RIB0 >> 12) & 7); set => RIB0 = ((RIB0 & ~(7u << 12)) | ((uint)(value & 7) << 12)); }
public override bool RibbonChampionG3 { get => (RIB0 & (1 << 15)) == 1 << 15; set => RIB0 = ((RIB0 & ~(1u << 15)) | (value ? 1u << 15 : 0u)); }
public override bool RibbonWinning { get => (RIB0 & (1 << 16)) == 1 << 16; set => RIB0 = ((RIB0 & ~(1u << 16)) | (value ? 1u << 16 : 0u)); }
public override bool RibbonVictory { get => (RIB0 & (1 << 17)) == 1 << 17; set => RIB0 = ((RIB0 & ~(1u << 17)) | (value ? 1u << 17 : 0u)); }

View file

@ -5,7 +5,7 @@ using static System.Buffers.Binary.BinaryPrimitives;
namespace PKHeX.Core;
/// <summary> Generation 6 <see cref="PKM"/> format. </summary>
public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6,
public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6,
IContestStats, IContestStatsMutable, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection, IGroundTile
{
private static readonly ushort[] Unused =
@ -202,8 +202,8 @@ public sealed class PK6 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC
public bool RibbonMasterToughness { get => (RIB5 & (1 << 5)) == 1 << 5; set => RIB5 = (byte)((RIB5 & ~(1 << 5)) | (value ? 1 << 5 : 0)); }
public bool RIB5_6 { get => (RIB5 & (1 << 6)) == 1 << 6; set => RIB5 = (byte)((RIB5 & ~(1 << 6)) | (value ? 1 << 6 : 0)); } // Unused
public bool RIB5_7 { get => (RIB5 & (1 << 7)) == 1 << 7; set => RIB5 = (byte)((RIB5 & ~(1 << 7)) | (value ? 1 << 7 : 0)); } // Unused
public int RibbonCountMemoryContest { get => Data[0x38]; set => HasContestMemoryRibbon = (Data[0x38] = (byte)value) != 0; }
public int RibbonCountMemoryBattle { get => Data[0x39]; set => HasBattleMemoryRibbon = (Data[0x39] = (byte)value) != 0; }
public byte RibbonCountMemoryContest { get => Data[0x38]; set => HasContestMemoryRibbon = (Data[0x38] = value) != 0; }
public byte RibbonCountMemoryBattle { get => Data[0x39]; set => HasBattleMemoryRibbon = (Data[0x39] = value) != 0; }
private ushort DistByte { get => ReadUInt16LittleEndian(Data.AsSpan(0x3A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x3A), value); }
public bool DistSuperTrain1 { get => (DistByte & (1 << 0)) == 1 << 0; set => DistByte = (byte)((DistByte & ~(1 << 0)) | (value ? 1 << 0 : 0)); }
public bool DistSuperTrain2 { get => (DistByte & (1 << 1)) == 1 << 1; set => DistByte = (byte)((DistByte & ~(1 << 1)) | (value ? 1 << 1 : 0)); }

View file

@ -5,7 +5,7 @@ using static System.Buffers.Binary.BinaryPrimitives;
namespace PKHeX.Core;
/// <summary> Generation 7 <see cref="PKM"/> format. </summary>
public sealed class PK7 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetCommon7,
public sealed class PK7 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetCommon6, IRibbonSetMemory6, IRibbonSetCommon7,
IContestStats, IContestStatsMutable, IHyperTrain, IGeoTrack, ISuperTrain, IFormArgument, ITrainerMemories, IAffection
{
private static readonly ushort[] Unused =
@ -212,8 +212,8 @@ public sealed class PK7 : G6PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetC
public bool RIB6_5 { get => (RIB6 & (1 << 5)) == 1 << 5; set => RIB6 = (byte)((RIB6 & ~(1 << 5)) | (value ? 1 << 5 : 0)); } // Unused
public bool RIB6_6 { get => (RIB6 & (1 << 6)) == 1 << 6; set => RIB6 = (byte)((RIB6 & ~(1 << 6)) | (value ? 1 << 6 : 0)); } // Unused
public bool RIB6_7 { get => (RIB6 & (1 << 7)) == 1 << 7; set => RIB6 = (byte)((RIB6 & ~(1 << 7)) | (value ? 1 << 7 : 0)); } // Unused
public int RibbonCountMemoryContest { get => Data[0x38]; set => HasContestMemoryRibbon = (Data[0x38] = (byte)value) != 0; }
public int RibbonCountMemoryBattle { get => Data[0x39]; set => HasBattleMemoryRibbon = (Data[0x39] = (byte)value) != 0; }
public byte RibbonCountMemoryContest { get => Data[0x38]; set => HasContestMemoryRibbon = (Data[0x38] = value) != 0; }
public byte RibbonCountMemoryBattle { get => Data[0x39]; set => HasBattleMemoryRibbon = (Data[0x39] = value) != 0; }
private ushort DistByte { get => ReadUInt16LittleEndian(Data.AsSpan(0x3A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x3A), value); }
public bool DistSuperTrain1 { get => (DistByte & (1 << 0)) == 1 << 0; set => DistByte = (byte)((DistByte & ~(1 << 0)) | (value ? 1 << 0 : 0)); }
public bool DistSuperTrain2 { get => (DistByte & (1 << 1)) == 1 << 1; set => DistByte = (byte)((DistByte & ~(1 << 1)) | (value ? 1 << 1 : 0)); }

View file

@ -92,11 +92,11 @@ public abstract class G3PKM : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonS
public abstract bool RibbonEffort { get; set; }
public abstract bool RibbonWinning { get; set; }
public abstract bool RibbonVictory { get; set; }
public abstract int RibbonCountG3Cool { get; set; }
public abstract int RibbonCountG3Beauty { get; set; }
public abstract int RibbonCountG3Cute { get; set; }
public abstract int RibbonCountG3Smart { get; set; }
public abstract int RibbonCountG3Tough { get; set; }
public abstract byte RibbonCountG3Cool { get; set; }
public abstract byte RibbonCountG3Beauty { get; set; }
public abstract byte RibbonCountG3Cute { get; set; }
public abstract byte RibbonCountG3Smart { get; set; }
public abstract byte RibbonCountG3Tough { get; set; }
public abstract bool RibbonWorld { get; set; }
public abstract bool Unused1 { get; set; }
public abstract bool Unused2 { get; set; }

View file

@ -184,11 +184,11 @@ public sealed class XK3 : G3PKM, IShadowPKM
public override byte CNT_Cute { get => Data[0xB0]; set => Data[0xB0] = value; }
public override byte CNT_Smart { get => Data[0xB1]; set => Data[0xB1] = value; }
public override byte CNT_Tough { get => Data[0xB2]; set => Data[0xB2] = value; }
public override int RibbonCountG3Cool { get => Data[0xB3]; set => Data[0xB3] = (byte)value; }
public override int RibbonCountG3Beauty { get => Data[0xB4]; set => Data[0xB4] = (byte)value; }
public override int RibbonCountG3Cute { get => Data[0xB5]; set => Data[0xB5] = (byte)value; }
public override int RibbonCountG3Smart { get => Data[0xB6]; set => Data[0xB6] = (byte)value; }
public override int RibbonCountG3Tough { get => Data[0xB7]; set => Data[0xB7] = (byte)value; }
public override byte RibbonCountG3Cool { get => Data[0xB3]; set => Data[0xB3] = value; }
public override byte RibbonCountG3Beauty { get => Data[0xB4]; set => Data[0xB4] = value; }
public override byte RibbonCountG3Cute { get => Data[0xB5]; set => Data[0xB5] = value; }
public override byte RibbonCountG3Smart { get => Data[0xB6]; set => Data[0xB6] = value; }
public override byte RibbonCountG3Tough { get => Data[0xB7]; set => Data[0xB7] = value; }
public ushort ShadowID { get => ReadUInt16BigEndian(Data.AsSpan(0xBA)); set => WriteUInt16BigEndian(Data.AsSpan(0xBA), value); }

View file

@ -16,9 +16,6 @@ public interface IRibbonSetCommon6
bool RibbonMasterCuteness { get; set; }
bool RibbonMasterCleverness { get; set; }
bool RibbonMasterToughness { get; set; }
int RibbonCountMemoryContest { get; set; }
int RibbonCountMemoryBattle { get; set; }
}
internal static partial class RibbonExtensions
@ -42,7 +39,5 @@ internal static partial class RibbonExtensions
dest.RibbonMasterCuteness = set.RibbonMasterCuteness;
dest.RibbonMasterCleverness = set.RibbonMasterCleverness;
dest.RibbonMasterToughness = set.RibbonMasterToughness;
dest.RibbonCountMemoryContest = set.RibbonCountMemoryContest;
dest.RibbonCountMemoryBattle = set.RibbonCountMemoryBattle;
}
}

View file

@ -0,0 +1,20 @@
namespace PKHeX.Core;
public interface IRibbonSetMemory6
{
byte RibbonCountMemoryContest { get; set; }
byte RibbonCountMemoryBattle { get; set; }
bool HasContestMemoryRibbon { get; set; }
bool HasBattleMemoryRibbon { get; set; }
}
internal static partial class RibbonExtensions
{
internal static void CopyRibbonSetMemory6(this IRibbonSetMemory6 set, IRibbonSetMemory6 dest)
{
dest.RibbonCountMemoryContest = set.RibbonCountMemoryContest;
dest.RibbonCountMemoryBattle = set.RibbonCountMemoryBattle;
dest.HasContestMemoryRibbon = set.HasContestMemoryRibbon;
dest.HasBattleMemoryRibbon = set.HasBattleMemoryRibbon;
}
}

View file

@ -3,11 +3,11 @@ namespace PKHeX.Core;
/// <summary> Ribbons that originated in Generation 3 and were only present within that Generation. </summary>
public interface IRibbonSetOnly3
{
int RibbonCountG3Cool { get; set; }
int RibbonCountG3Beauty { get; set; }
int RibbonCountG3Cute { get; set; }
int RibbonCountG3Smart { get; set; }
int RibbonCountG3Tough { get; set; }
byte RibbonCountG3Cool { get; set; }
byte RibbonCountG3Beauty { get; set; }
byte RibbonCountG3Cute { get; set; }
byte RibbonCountG3Smart { get; set; }
byte RibbonCountG3Tough { get; set; }
bool RibbonWorld { get; set; }
bool Unused1 { get; set; }

View file

@ -1,4 +1,4 @@
using System;
using System;
using static PKHeX.Core.RibbonIndex;
namespace PKHeX.Core;
@ -229,7 +229,7 @@ public static class RibbonIndexExtensions
r.FixMark(pk, state);
return;
case RibbonIndexGroup.CountMemory:
if (pk is not IRibbonSetCommon6 m6)
if (pk is not IRibbonSetMemory6 m6)
return;
(byte contest, byte battle) = state ? RibbonRules.GetMaxMemoryCounts(args.History, args.Entity, args.Encounter) : default;
if (r is CountMemoryContest)
@ -417,8 +417,8 @@ public static class RibbonIndexExtensions
ChampionRegional => nameof(IRibbonSetEvent3.RibbonChampionRegional),
ChampionNational => nameof(IRibbonSetEvent3.RibbonChampionNational),
ChampionWorld => nameof(IRibbonSetEvent4.RibbonChampionWorld),
CountMemoryContest => nameof(IRibbonSetCommon6.RibbonCountMemoryContest),
CountMemoryBattle => nameof(IRibbonSetCommon6.RibbonCountMemoryBattle),
CountMemoryContest => nameof(IRibbonSetMemory6.RibbonCountMemoryContest),
CountMemoryBattle => nameof(IRibbonSetMemory6.RibbonCountMemoryBattle),
ChampionG6Hoenn => nameof(IRibbonSetCommon6.RibbonChampionG6Hoenn),
ContestStar => nameof(IRibbonSetCommon6.RibbonContestStar),
MasterCoolness => nameof(IRibbonSetCommon6.RibbonMasterCoolness),

View file

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
namespace PKHeX.Core;
@ -10,20 +11,22 @@ public sealed class RibbonInfo
public const string PropertyPrefix = "Ribbon";
public readonly string Name;
public readonly RibbonValueType Type;
public bool HasRibbon { get; set; }
public int RibbonCount { get; set; }
public byte RibbonCount { get; set; }
private RibbonInfo(string name, bool hasRibbon)
{
Name = name;
HasRibbon = hasRibbon;
RibbonCount = -1;
Type = RibbonValueType.Boolean;
}
private RibbonInfo(string name, int count)
private RibbonInfo(string name, byte count)
{
Name = name;
HasRibbon = false;
Type = RibbonValueType.Byte;
RibbonCount = count;
}
@ -31,13 +34,14 @@ public sealed class RibbonInfo
{
get
{
if (RibbonCount < 0)
return -1;
if (Type is RibbonValueType.Boolean)
throw new ArgumentOutOfRangeException(nameof(Type));
return Name switch
{
nameof(IRibbonSetCommon6.RibbonCountMemoryContest) => 40,
nameof(IRibbonSetCommon6.RibbonCountMemoryBattle) => 8,
_ => 4,
nameof(IRibbonSetMemory6.RibbonCountMemoryContest) => 40,
nameof(IRibbonSetMemory6.RibbonCountMemoryBattle) => 8,
_ => 4, // Gen3/4 Contest Ribbons
};
}
}
@ -50,12 +54,20 @@ public sealed class RibbonInfo
foreach (var name in names)
{
object? RibbonValue = ReflectUtil.GetValue(pk, name);
if (RibbonValue is int x)
riblist.Add(new RibbonInfo(name, x));
if (RibbonValue is bool b)
riblist.Add(new RibbonInfo(name, b));
else if (RibbonValue is byte x)
riblist.Add(new RibbonInfo(name, x));
}
return riblist;
}
}
/// <summary>
/// Type of Ribbon Value
/// </summary>
public enum RibbonValueType
{
Boolean,
Byte,
}

View file

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
@ -45,10 +45,13 @@ public partial class RibbonEditor : Form
return;
}
var ds = new List<ComboItem> { new(GameInfo.GetStrings(Main.CurrentLanguage).Move[0], -1) };
var list = Enumerable.Range(0, (int)RibbonIndex.MAX_COUNT)
.Select(z => new ComboItem(RibbonStrings.GetName($"Ribbon{(RibbonIndex)z}"), z))
.OrderBy(z => z.Text);
const int count = (int)RibbonIndex.MAX_COUNT;
static string GetRibbonPropertyName(int z) => RibbonStrings.GetName($"Ribbon{(RibbonIndex)z}");
static ComboItem GetComboItem(int ribbonIndex) => new(GetRibbonPropertyName(ribbonIndex), ribbonIndex);
var none = GameInfo.GetStrings(Main.CurrentLanguage).Move[0];
var ds = new List<ComboItem>(1 + count) { new(none, -1) };
var list = Enumerable.Range(0, count).Select(GetComboItem).OrderBy(z => z.Text);
ds.AddRange(list);
CB_Affixed.InitializeBinding();
@ -111,7 +114,7 @@ public partial class RibbonEditor : Form
};
TLP_Ribbons.Controls.Add(label, 1, row);
if (rib.RibbonCount >= 0) // numeric count ribbon
if (rib.Type is RibbonValueType.Byte) // numeric count ribbon
AddRibbonNumericUpDown(rib, row);
else // boolean ribbon
AddRibbonCheckBox(rib, row, label);
@ -133,8 +136,9 @@ public partial class RibbonEditor : Form
nud.ValueChanged += (sender, e) =>
{
FLP_Ribbons.Controls[PrefixPB + rib.Name].Visible = (rib.RibbonCount = (int)nud.Value) > 0;
FLP_Ribbons.Controls[PrefixPB + rib.Name].BackgroundImage = RibbonSpriteUtil.GetRibbonSprite(rib.Name, (int)nud.Maximum, (int)nud.Value);
var pb = FLP_Ribbons.Controls[PrefixPB + rib.Name];
pb.Visible = (rib.RibbonCount = (byte)nud.Value) != 0;
pb.BackgroundImage = RibbonSpriteUtil.GetRibbonSprite(rib.Name, (int)nud.Maximum, (int)nud.Value);
};
nud.Value = rib.RibbonCount > nud.Maximum ? nud.Maximum : rib.RibbonCount;
TLP_Ribbons.Controls.Add(nud, 0, row);
@ -164,7 +168,7 @@ public partial class RibbonEditor : Form
private void Save()
{
foreach (var rib in riblist)
ReflectUtil.SetValue(Entity, rib.Name, rib.RibbonCount < 0 ? rib.HasRibbon : rib.RibbonCount);
ReflectUtil.SetValue(Entity, rib.Name, rib.Type is RibbonValueType.Boolean ? rib.HasRibbon : rib.RibbonCount);
if (Entity is IRibbonSetAffixed affixed)
affixed.AffixedRibbon = (sbyte)WinFormsUtil.GetIndex(CB_Affixed);