diff --git a/PKHeX.Core/Legality/Checks.cs b/PKHeX.Core/Legality/Checks.cs index 504a826bf..838a3a76c 100644 --- a/PKHeX.Core/Legality/Checks.cs +++ b/PKHeX.Core/Legality/Checks.cs @@ -782,29 +782,29 @@ private static IEnumerable GetRibbonResults(PKM pkm) var c3 = u4.RibbonBitsContest3(); var c3n = u4.RibbonNamesContest3(); var c4 = u4.RibbonBitsContest4(); var c4n = u4.RibbonNamesContest4(); - var iter3 = gen == 3 ? getGapRibbons(c3, c3n) : GetRibbonMessageNone(c3, c3n); - var iter4 = gen == 4 && IsAllowedInContest4(pkm.Species) ? getGapRibbons(c4, c4n) : GetRibbonMessageNone(c4, c4n); + var iter3 = gen == 3 ? getMissingContestRibbons(c3, c3n) : GetRibbonMessageNone(c3, c3n); + var iter4 = gen == 4 && IsAllowedInContest4(pkm.Species) ? getMissingContestRibbons(c4, c4n) : GetRibbonMessageNone(c4, c4n); foreach (var z in iter3.Concat(iter4)) yield return z; - IEnumerable getGapRibbons(IReadOnlyList bits, IReadOnlyList names) + IEnumerable getMissingContestRibbons(IReadOnlyList bits, IReadOnlyList names) { for (int i = 0; i < bits.Count; i += 4) { bool required = false; - for (int j = i; j < i + 4; j++) + for (int j = i + 3; j >= i; j--) if (bits[j]) required = true; else if (required) - yield return new RibbonResult(names[j]); + yield return new RibbonResult(names[j], false); } } } if (pkm is IRibbonSetCommon4 s4) { - bool inhabited45 = 4 <= gen && gen <= 5; + bool inhabited4 = 3 <= gen && gen <= 4; IEnumerable iterate = GetRibbonMessage4Any(pkm, s4, gen); - if (!inhabited45) + if (!inhabited4) iterate = iterate.Concat(GetRibbonMessageNone(s4.RibbonBitsOnly(), s4.RibbonNamesOnly())); foreach (var z in iterate) yield return z; @@ -824,6 +824,9 @@ IEnumerable getGapRibbons(IReadOnlyList bits, IReadOnlyList< if (s6.RibbonCountMemoryBattle > 0) yield return new RibbonResult(nameof(s6.RibbonCountMemoryBattle)); } + + if (s6.RibbonBestFriends && pkm.OT_Affection < 255 && pkm.IsUntraded) // can't lower affection + yield return new RibbonResult(nameof(s6.RibbonBestFriends)); } if (pkm is IRibbonSetCommon7 s7) { @@ -838,24 +841,28 @@ IEnumerable getGapRibbons(IReadOnlyList bits, IReadOnlyList< yield return new RibbonResult(nameof(s3.RibbonChampionG3Hoenn)); // RSE HoF if (s3.RibbonArtist && (gen != 3 || !artist)) yield return new RibbonResult(nameof(s3.RibbonArtist)); // RSE Master Rank Portrait + if (s3.RibbonEffort && gen == 5 && pkm.Format == 5) // unobtainable in Gen 5 + yield return new RibbonResult(nameof(s3.RibbonEffort)); } } private static IEnumerable GetRibbonMessage4Any(PKM pkm, IRibbonSetCommon4 s4, int gen) { if (s4.RibbonRecord) yield return new RibbonResult(nameof(s4.RibbonRecord)); // Unobtainable - if (s4.RibbonFootprint && gen >= 6 && pkm.CurrentLevel - pkm.Met_Level < 30) + if (s4.RibbonFootprint && (pkm.Format < 6 && gen == 5 || gen >= 6 && pkm.CurrentLevel - pkm.Met_Level < 30)) yield return new RibbonResult(nameof(s4.RibbonFootprint)); - if (pkm.Format < 6 || gen > 6 || pkm.IsUntraded && pkm.XY) - { - if (s4.RibbonGorgeous) - yield return new RibbonResult(nameof(s4.RibbonGorgeous)); - if (s4.RibbonRoyal) - yield return new RibbonResult(nameof(s4.RibbonRoyal)); - if (s4.RibbonGorgeousRoyal) - yield return new RibbonResult(nameof(s4.RibbonGorgeousRoyal)); - } + bool gen34 = gen == 3 || gen == 4; + bool not6 = pkm.Format < 6 || gen > 6 || gen < 3; + bool noDaily = !gen34 && (not6 || pkm.AO && pkm.IsUntraded); + bool noCosmetic = !gen34 && (not6 || pkm.XY && pkm.IsUntraded); + + if (noDaily) + foreach (var z in GetRibbonMessageNone(s4.RibbonBitsDaily(), s4.RibbonNamesDaily())) + yield return z; + if (noCosmetic) + foreach (var z in GetRibbonMessageNone(s4.RibbonBitsCosmetic(), s4.RibbonNamesCosmetic())) + yield return z; } private static IEnumerable GetRibbonMessage6Any(PKM pkm, IRibbonSetCommon6 s6, int gen) { @@ -867,14 +874,18 @@ private static IEnumerable GetRibbonMessage6Any(PKM pkm, IRibbonSe foreach (var p in iter) yield return p; + bool allContest = s6.RibbonBitsContest().All(z => z); + if (allContest ^ s6.RibbonContestStar && !(untraded && pkm.XY)) // if not already checked + yield return new RibbonResult(nameof(s6.RibbonContestStar), s6.RibbonContestStar); + const int mem_Chatelaine = 30; - if (pkm.HT_Memory == mem_Chatelaine || pkm.OT_Memory == mem_Chatelaine) - { - if (!s6.RibbonBattlerSkillful) - yield return new RibbonResult(nameof(s6.RibbonBattlerSkillful), false); - else if (!s6.RibbonBattlerExpert) - yield return new RibbonResult(nameof(s6.RibbonBattlerExpert), false); - } + bool hasChampMemory = pkm.HT_Memory == mem_Chatelaine || pkm.OT_Memory == mem_Chatelaine; + if (!hasChampMemory || s6.RibbonBattlerSkillful || s6.RibbonBattlerExpert) + yield break; + + var result = new RibbonResult(nameof(s6.RibbonBattlerSkillful), false); + result.Combine(new RibbonResult(nameof(s6.RibbonBattlerExpert))); + yield return result; } private static IEnumerable GetRibbonMessage6Memory(PKM pkm, IRibbonSetCommon6 s6, int gen) { @@ -898,13 +909,11 @@ private static IEnumerable GetRibbonMessage6Memory(PKM pkm, IRibbo } private static IEnumerable GetRibbonMessage6Untraded(PKM pkm, IRibbonSetCommon6 s6) { - if (s6.RibbonBestFriends && pkm.OT_Affection != 255) // can't lower affection - yield return new RibbonResult(nameof(s6.RibbonBestFriends), false); - if (pkm.XY) { if (s6.RibbonChampionG6Hoenn) yield return new RibbonResult(nameof(s6.RibbonChampionG6Hoenn)); + if (s6.RibbonContestStar) yield return new RibbonResult(nameof(s6.RibbonContestStar)); if (s6.RibbonMasterCoolness) @@ -926,20 +935,6 @@ private static IEnumerable GetRibbonMessage6Untraded(PKM pkm, IRib } private static IEnumerable GetRibbonMessage6Traded(PKM pkm, IRibbonSetCommon6 s6) { - if (s6.RibbonContestStar) - { - if (!s6.RibbonMasterCoolness) - yield return new RibbonResult(nameof(s6.RibbonMasterCoolness)); - if (!s6.RibbonMasterBeauty) - yield return new RibbonResult(nameof(s6.RibbonMasterBeauty)); - if (!s6.RibbonMasterCuteness) - yield return new RibbonResult(nameof(s6.RibbonMasterCuteness)); - if (!s6.RibbonMasterCleverness) - yield return new RibbonResult(nameof(s6.RibbonMasterCleverness)); - if (!s6.RibbonMasterToughness) - yield return new RibbonResult(nameof(s6.RibbonMasterToughness)); - } - if (s6.RibbonTraining) { const int req = 12; // only first 12 @@ -949,8 +944,13 @@ private static IEnumerable GetRibbonMessage6Traded(PKM pkm, IRibbo } const int mem_Champion = 27; - if ((pkm.HT_Memory == mem_Champion || pkm.OT_Memory == mem_Champion) && !s6.RibbonChampionKalos && !s6.RibbonChampionG6Hoenn) - yield return new RibbonResult(pkm.XY ? nameof(s6.RibbonChampionKalos) : nameof(s6.RibbonChampionG6Hoenn), false); + bool hasChampMemory = pkm.HT_Memory == mem_Champion || pkm.OT_Memory == mem_Champion; + if (!hasChampMemory || s6.RibbonChampionKalos || s6.RibbonChampionG6Hoenn) + yield break; + + var result = new RibbonResult(nameof(s6.RibbonChampionKalos), false); + result.Combine(new RibbonResult(nameof(s6.RibbonChampionG6Hoenn))); + yield return result; } private static IEnumerable GetRibbonMessage7Any(PKM pkm, IRibbonSetCommon7 s7, int gen) { @@ -976,7 +976,7 @@ private static bool IsAllowedBattleFrontier(int species, int form = 0, int gen = if (gen == 4 && species == 172 && form == 1) // spiky return false; - return Legal.BattleFrontierBanlist.Contains(species); + return !Legal.BattleFrontierBanlist.Contains(species); } private void VerifyRibbonsEgg(object encounter) { @@ -1043,7 +1043,7 @@ private static IEnumerable VerifyRibbonSet2(PKM pkm, object encoun private class RibbonResult { /// Ribbon Display Name - public string Name { get; } + public string Name { get; private set; } /// Ribbon should not be present. /// If this is false, the Ribbon is missing. @@ -1054,6 +1054,11 @@ public RibbonResult(string prop, bool invalid = true) Name = RibbonStrings.GetName(prop) ?? prop; Invalid = invalid; } + + public void Combine(RibbonResult other) + { + Name += " / " + other.Name; + } } private void VerifyCXD() diff --git a/PKHeX.Core/PKM/PK4.cs b/PKHeX.Core/PKM/PK4.cs index 52d39a9c0..d6f6acb2e 100644 --- a/PKHeX.Core/PKM/PK4.cs +++ b/PKHeX.Core/PKM/PK4.cs @@ -3,7 +3,7 @@ namespace PKHeX.Core { - public class PK4 : PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4 + public class PK4 : PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4 { public static readonly byte[] ExtraBytes = { diff --git a/PKHeX.Core/PKM/PK5.cs b/PKHeX.Core/PKM/PK5.cs index 8f179b752..ac4356c63 100644 --- a/PKHeX.Core/PKM/PK5.cs +++ b/PKHeX.Core/PKM/PK5.cs @@ -3,7 +3,7 @@ namespace PKHeX.Core { - public class PK5 : PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCommon3, IRibbonSetCommon4, IRibbonSetUnique4 + public class PK5 : PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUnique3, IRibbonSetUnique4, IRibbonSetCommon3, IRibbonSetCommon4 { public static readonly byte[] ExtraBytes = { diff --git a/PKHeX.Core/Ribbons/IRibbonSetCommon4.cs b/PKHeX.Core/Ribbons/IRibbonSetCommon4.cs index 9dfc89477..f28c66d77 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetCommon4.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetCommon4.cs @@ -23,63 +23,59 @@ internal static partial class RibbonExtensions { private static readonly string[] RibbonSetNamesCommon4 = { - nameof(IRibbonSetCommon4.RibbonChampionSinnoh), nameof(IRibbonSetCommon4.RibbonAlert), nameof(IRibbonSetCommon4.RibbonShock), - nameof(IRibbonSetCommon4.RibbonDowncast), nameof(IRibbonSetCommon4.RibbonCareless), nameof(IRibbonSetCommon4.RibbonRelax), - nameof(IRibbonSetCommon4.RibbonSnooze), nameof(IRibbonSetCommon4.RibbonSmile), nameof(IRibbonSetCommon4.RibbonGorgeous), - nameof(IRibbonSetCommon4.RibbonRoyal), nameof(IRibbonSetCommon4.RibbonGorgeousRoyal), nameof(IRibbonSetCommon4.RibbonFootprint), - nameof(IRibbonSetCommon4.RibbonRecord), nameof(IRibbonSetCommon4.RibbonLegend), + nameof(IRibbonSetCommon4.RibbonGorgeous), nameof(IRibbonSetCommon4.RibbonRoyal), nameof(IRibbonSetCommon4.RibbonGorgeousRoyal), }; - internal static bool[] RibbonBits(this IRibbonSetCommon4 set) + internal static bool[] RibbonBitsCosmetic(this IRibbonSetCommon4 set) { if (set == null) - return new bool[15]; + return new bool[3]; return new[] { - set.RibbonChampionSinnoh, - set.RibbonAlert, - set.RibbonShock, - set.RibbonDowncast, - set.RibbonCareless, - set.RibbonRelax, - set.RibbonSnooze, - set.RibbonSmile, set.RibbonGorgeous, set.RibbonRoyal, set.RibbonGorgeousRoyal, - set.RibbonFootprint, - set.RibbonRecord, - set.RibbonLegend, }; } - internal static string[] RibbonNames(this IRibbonSetCommon4 set) => RibbonSetNamesCommon4; + internal static string[] RibbonNamesCosmetic(this IRibbonSetCommon4 set) => RibbonSetNamesCommon4; private static readonly string[] RibbonSetNamesCommon4Only = { - nameof(IRibbonSetCommon4.RibbonChampionSinnoh), nameof(IRibbonSetCommon4.RibbonAlert), nameof(IRibbonSetCommon4.RibbonShock), - nameof(IRibbonSetCommon4.RibbonDowncast), nameof(IRibbonSetCommon4.RibbonCareless), nameof(IRibbonSetCommon4.RibbonRelax), - nameof(IRibbonSetCommon4.RibbonSnooze), nameof(IRibbonSetCommon4.RibbonSmile), - nameof(IRibbonSetCommon4.RibbonRecord), nameof(IRibbonSetCommon4.RibbonLegend), - - // nameof(IRibbonSetCommon4.RibbonGorgeous), nameof(IRibbonSetCommon4.RibbonRoyal), nameof(IRibbonSetCommon4.RibbonGorgeousRoyal), - // nameof(IRibbonSetCommon4.RibbonFootprint), + nameof(IRibbonSetCommon4.RibbonRecord), nameof(IRibbonSetCommon4.RibbonChampionSinnoh), nameof(IRibbonSetCommon4.RibbonLegend), }; internal static bool[] RibbonBitsOnly(this IRibbonSetCommon4 set) { if (set == null) - return new bool[10]; + return new bool[3]; return new[] { set.RibbonChampionSinnoh, - set.RibbonAlert, - set.RibbonShock, - set.RibbonDowncast, - set.RibbonCareless, - set.RibbonRelax, - set.RibbonSnooze, - set.RibbonSmile, set.RibbonRecord, set.RibbonLegend, }; } internal static string[] RibbonNamesOnly(this IRibbonSetCommon4 set) => RibbonSetNamesCommon4Only; + + private static readonly string[] RibbonSetNamesCommon4Daily = + { + nameof(IRibbonSetCommon4.RibbonAlert), nameof(IRibbonSetCommon4.RibbonShock), + nameof(IRibbonSetCommon4.RibbonDowncast), nameof(IRibbonSetCommon4.RibbonCareless), nameof(IRibbonSetCommon4.RibbonRelax), + nameof(IRibbonSetCommon4.RibbonSnooze), nameof(IRibbonSetCommon4.RibbonSmile), + }; + + internal static bool[] RibbonBitsDaily(this IRibbonSetCommon4 set) + { + if (set == null) + return new bool[7]; + return new[] + { + set.RibbonAlert, + set.RibbonShock, + set.RibbonDowncast, + set.RibbonCareless, + set.RibbonRelax, + set.RibbonSnooze, + set.RibbonSmile, + }; + } + internal static string[] RibbonNamesDaily(this IRibbonSetCommon4 set) => RibbonSetNamesCommon4Daily; } } diff --git a/PKHeX.Core/Ribbons/IRibbonSetCommon6.cs b/PKHeX.Core/Ribbons/IRibbonSetCommon6.cs index d9a7f399c..3b0a031f3 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetCommon6.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetCommon6.cs @@ -25,21 +25,20 @@ internal static partial class RibbonExtensions { private static readonly string[] RibbonSetNamesCommon6Bool = { - nameof(IRibbonSetCommon6.RibbonChampionKalos), nameof(IRibbonSetCommon6.RibbonChampionG6Hoenn), nameof(IRibbonSetCommon6.RibbonBestFriends), + nameof(IRibbonSetCommon6.RibbonChampionKalos), nameof(IRibbonSetCommon6.RibbonChampionG6Hoenn), // nameof(IRibbonSetCommon6.RibbonBestFriends), nameof(IRibbonSetCommon6.RibbonTraining), nameof(IRibbonSetCommon6.RibbonBattlerSkillful), nameof(IRibbonSetCommon6.RibbonBattlerExpert), nameof(IRibbonSetCommon6.RibbonContestStar), nameof(IRibbonSetCommon6.RibbonMasterCoolness), nameof(IRibbonSetCommon6.RibbonMasterBeauty), nameof(IRibbonSetCommon6.RibbonMasterCuteness), nameof(IRibbonSetCommon6.RibbonMasterCleverness), nameof(IRibbonSetCommon6.RibbonMasterToughness), - }; internal static bool[] RibbonBits(this IRibbonSetCommon6 set) { if (set == null) - return new bool[12]; + return new bool[11]; return new[] { set.RibbonChampionKalos, set.RibbonChampionG6Hoenn, - set.RibbonBestFriends, + //set.RibbonBestFriends, set.RibbonTraining, set.RibbonBattlerSkillful, set.RibbonBattlerExpert, @@ -52,6 +51,19 @@ internal static bool[] RibbonBits(this IRibbonSetCommon6 set) set.RibbonMasterToughness, }; } + internal static bool[] RibbonBitsContest(this IRibbonSetCommon6 set) + { + if (set == null) + return new bool[5]; + return new[] + { + set.RibbonMasterCoolness, + set.RibbonMasterBeauty, + set.RibbonMasterCuteness, + set.RibbonMasterCleverness, + set.RibbonMasterToughness, + }; + } internal static string[] RibbonNamesBool(this IRibbonSetCommon6 set) => RibbonSetNamesCommon6Bool; } }