mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-09-13 00:35:19 -05:00
Legality: Rewrite Ribbon Verifier (#3570)
* Rewrite ribbon verification * Explicitly verifies all ribbons instead of chained iterators. * Verifies using only the stack, using `struct` and `Span<T>`. No allocation on heap, or `IEnumerable` iterators. * Verifies all egg ribbons using a separate method, explicitly implemented. No reflection overhead. * Separates each ribbon interface to separate `static` classes. Easier to identify code needing change on new game update. * Extracted logic for specific ribbons. Can easily revise complicated ribbon's acquisition rules. * Simplifies GiveAll/RemoveAll legal ribbon mutations. No reflection overhead, and no allocation. * Can be expanded in the future if we need to track conditions for ribbon acquisition (was Sinnoh Champ received in BDSP or Gen4?) End result is a more performant implementation and easier to maintain & reuse logic.
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
@@ -8,238 +7,80 @@ namespace PKHeX.Core;
|
||||
/// </summary>
|
||||
public static class RibbonApplicator
|
||||
{
|
||||
private static List<string> GetAllRibbonNames(PKM pk) => RibbonInfo.GetRibbonInfo(pk).ConvertAll(z => z.Name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of valid ribbons for the <see cref="pk"/>.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to fetch the list for.</param>
|
||||
/// <param name="allRibbons">All ribbon names.</param>
|
||||
/// <returns>List of all valid ribbon names.</returns>
|
||||
public static IReadOnlyList<string> GetValidRibbons(PKM pk, IList<string> allRibbons)
|
||||
{
|
||||
var clone = pk.Clone();
|
||||
return SetAllValidRibbons(allRibbons, clone);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of valid ribbons for the <see cref="pk"/>.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to fetch the list for.</param>
|
||||
/// <returns>List of all valid ribbon names.</returns>
|
||||
public static IReadOnlyList<string> GetValidRibbons(PKM pk)
|
||||
{
|
||||
var names = GetAllRibbonNames(pk);
|
||||
return GetValidRibbons(pk, names);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of valid ribbons for the <see cref="pk"/> that can be removed.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to fetch the list for.</param>
|
||||
/// <param name="allRibbons">All ribbon names.</param>
|
||||
/// <returns>List of all removable ribbon names.</returns>
|
||||
public static IReadOnlyList<string> GetRemovableRibbons(PKM pk, IList<string> allRibbons)
|
||||
{
|
||||
var clone = pk.Clone();
|
||||
return RemoveAllValidRibbons(allRibbons, clone);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of valid ribbons for the <see cref="pk"/> that can be removed.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to fetch the list for.</param>
|
||||
/// <returns>List of all removable ribbon names.</returns>
|
||||
public static IReadOnlyList<string> GetRemovableRibbons(PKM pk)
|
||||
{
|
||||
var names = GetAllRibbonNames(pk);
|
||||
return GetRemovableRibbons(pk, names);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets all valid ribbons to the <see cref="pk"/>.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to set ribbons for.</param>
|
||||
/// <returns>True if any ribbons were applied.</returns>
|
||||
public static bool SetAllValidRibbons(PKM pk)
|
||||
{
|
||||
var ribNames = GetAllRibbonNames(pk);
|
||||
ribNames.RemoveAll(z => z.StartsWith("RibbonMark", StringComparison.Ordinal)); // until marking legality is handled
|
||||
return SetAllValidRibbons(pk, ribNames);
|
||||
}
|
||||
public static void SetAllValidRibbons(PKM pk) => SetAllValidRibbons(new LegalityAnalysis(pk));
|
||||
|
||||
/// <summary>
|
||||
/// Sets all valid ribbons to the <see cref="pk"/>.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to set ribbons for.</param>
|
||||
/// <param name="ribNames">Ribbon names to try setting.</param>
|
||||
/// <returns>True if any ribbons were applied.</returns>
|
||||
public static bool SetAllValidRibbons(PKM pk, List<string> ribNames)
|
||||
/// <inheritdoc cref="SetAllValidRibbons(PKM)"/>
|
||||
public static void SetAllValidRibbons(LegalityAnalysis la)
|
||||
{
|
||||
var list = SetAllValidRibbons(ribNames, pk);
|
||||
return list.Count != 0;
|
||||
}
|
||||
|
||||
private static IReadOnlyList<string> SetAllValidRibbons(IList<string> allRibbons, PKM pk)
|
||||
{
|
||||
var la = new LegalityAnalysis(pk);
|
||||
var valid = new List<string>();
|
||||
|
||||
while (TryApplyAllRibbons(pk, la, allRibbons, valid) != 0)
|
||||
{
|
||||
// Repeat the operation until no more ribbons are set.
|
||||
}
|
||||
var args = new RibbonVerifierArguments(la.Entity, la.EncounterMatch, la.Info.EvoChainsAllGens);
|
||||
SetAllRibbonState(args, true);
|
||||
FixInvalidRibbons(args);
|
||||
|
||||
// Ribbon Deadlock
|
||||
if (pk is IRibbonSetCommon6 c6)
|
||||
InvertDeadlockContest(c6, la, true);
|
||||
|
||||
return valid;
|
||||
if (la.Entity is IRibbonSetCommon6 c6)
|
||||
InvertDeadlockContest(c6, true, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets all valid ribbons to the <see cref="pk"/>.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to set ribbons for.</param>
|
||||
/// <returns>True if any ribbons were removed.</returns>
|
||||
public static bool RemoveAllValidRibbons(PKM pk)
|
||||
public static void RemoveAllValidRibbons(PKM pk) => RemoveAllValidRibbons(new LegalityAnalysis(pk));
|
||||
|
||||
/// <inheritdoc cref="RemoveAllValidRibbons(PKM)"/>
|
||||
public static void RemoveAllValidRibbons(LegalityAnalysis la)
|
||||
{
|
||||
var ribNames = GetAllRibbonNames(pk);
|
||||
return RemoveAllValidRibbons(pk, ribNames);
|
||||
var args = new RibbonVerifierArguments(la.Entity, la.EncounterMatch, la.Info.EvoChainsAllGens);
|
||||
SetAllRibbonState(args, false);
|
||||
FixInvalidRibbons(args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets all valid ribbons to the <see cref="pk"/>.
|
||||
/// Parses the Entity for all ribbons, then fixes any ribbon that was invalid.
|
||||
/// </summary>
|
||||
/// <param name="pk">Entity to set ribbons for.</param>
|
||||
/// <param name="ribNames">Ribbon names to try setting.</param>
|
||||
/// <returns>True if any ribbons were removed.</returns>
|
||||
public static bool RemoveAllValidRibbons(PKM pk, List<string> ribNames)
|
||||
public static void FixInvalidRibbons(RibbonVerifierArguments args)
|
||||
{
|
||||
var list = RemoveAllValidRibbons(ribNames, pk);
|
||||
return list.Count != 0;
|
||||
Span<RibbonResult> result = stackalloc RibbonResult[RibbonVerifier.MaxRibbonCount];
|
||||
var count = RibbonVerifier.GetRibbonResults(args, result);
|
||||
foreach (var ribbon in result[..count])
|
||||
ribbon.Fix(args);
|
||||
}
|
||||
|
||||
private static IReadOnlyList<string> RemoveAllValidRibbons(IList<string> allRibbons, PKM pk)
|
||||
private static void SetAllRibbonState(RibbonVerifierArguments args, bool desiredState)
|
||||
{
|
||||
var la = new LegalityAnalysis(pk);
|
||||
var valid = new List<string>();
|
||||
for (RibbonIndex3 r = 0; r < RibbonIndex3.MAX_COUNT; r++)
|
||||
r.Fix(args, desiredState);
|
||||
for (RibbonIndex4 r = 0; r < RibbonIndex4.MAX_COUNT; r++)
|
||||
r.Fix(args, desiredState);
|
||||
|
||||
// Ribbon Deadlock
|
||||
if (pk is IRibbonSetCommon6 c6)
|
||||
InvertDeadlockContest(c6, la, false);
|
||||
|
||||
while (TryRemoveAllRibbons(pk, la, allRibbons, valid) != 0)
|
||||
if (desiredState)
|
||||
{
|
||||
// Repeat the operation until no more ribbons are set.
|
||||
// Skip Marks, don't set them.
|
||||
for (RibbonIndex r = 0; r <= RibbonIndex.MasterRank; r++)
|
||||
r.Fix(args, desiredState);
|
||||
for (RibbonIndex r = RibbonIndex.Pioneer; r < RibbonIndex.MAX_COUNT; r++)
|
||||
r.Fix(args, desiredState);
|
||||
}
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
private static int TryApplyAllRibbons(PKM pk, LegalityAnalysis la, IList<string> allRibbons, ICollection<string> valid)
|
||||
{
|
||||
int applied = 0;
|
||||
for (int i = 0; i < allRibbons.Count;)
|
||||
else
|
||||
{
|
||||
la.ResetParse();
|
||||
var rib = allRibbons[i];
|
||||
var success = TryApplyRibbon(pk, la, rib);
|
||||
if (success)
|
||||
{
|
||||
++applied;
|
||||
allRibbons.RemoveAt(i);
|
||||
valid.Add(rib);
|
||||
}
|
||||
else
|
||||
{
|
||||
RemoveRibbon(pk, rib);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return applied;
|
||||
}
|
||||
|
||||
private static int TryRemoveAllRibbons(PKM pk, LegalityAnalysis la, IList<string> allRibbons, ICollection<string> valid)
|
||||
{
|
||||
int removed = 0;
|
||||
for (int i = 0; i < allRibbons.Count;)
|
||||
{
|
||||
la.ResetParse();
|
||||
var rib = allRibbons[i];
|
||||
var success = TryRemoveRibbon(pk, la, rib);
|
||||
if (success)
|
||||
{
|
||||
++removed;
|
||||
allRibbons.RemoveAt(i);
|
||||
valid.Add(rib);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetRibbonValue(pk, rib, 1);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
private static void RemoveRibbon(PKM pk, string rib) => SetRibbonValue(pk, rib, 0);
|
||||
|
||||
private static bool TryRemoveRibbon(PKM pk, LegalityAnalysis la, string rib)
|
||||
{
|
||||
RemoveRibbon(pk, rib);
|
||||
return UpdateIsValid(la);
|
||||
}
|
||||
|
||||
private static bool TryApplyRibbon(PKM pk, LegalityAnalysis la, string rib)
|
||||
{
|
||||
SetRibbonValue(pk, rib, 1);
|
||||
return UpdateIsValid(la);
|
||||
}
|
||||
|
||||
private static bool UpdateIsValid(LegalityAnalysis la)
|
||||
{
|
||||
LegalityAnalyzers.Ribbon.Verify(la);
|
||||
foreach (var p in la.Results)
|
||||
{
|
||||
if (!p.Valid)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void SetRibbonValue(PKM pk, string rib, int value)
|
||||
{
|
||||
switch (rib)
|
||||
{
|
||||
case nameof(PK7.RibbonCountMemoryBattle):
|
||||
ReflectUtil.SetValue(pk, rib, value * (pk.Gen4 ? 6 : 8));
|
||||
break;
|
||||
case nameof(PK7.RibbonCountMemoryContest):
|
||||
ReflectUtil.SetValue(pk, rib, value * (pk.Gen4 ? 20 : 40));
|
||||
break;
|
||||
default:
|
||||
if (rib.StartsWith("RibbonCountG3", StringComparison.Ordinal))
|
||||
ReflectUtil.SetValue(pk, rib, value * 4);
|
||||
else
|
||||
ReflectUtil.SetValue(pk, rib, value != 0);
|
||||
break;
|
||||
// Remove Marks too.
|
||||
for (RibbonIndex r = 0; r < RibbonIndex.MAX_COUNT; r++)
|
||||
r.Fix(args, desiredState);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InvertDeadlockContest(IRibbonSetCommon6 c6, LegalityAnalysis la, bool desiredState)
|
||||
private static void InvertDeadlockContest(IRibbonSetCommon6 c6, bool desiredState, RibbonVerifierArguments args)
|
||||
{
|
||||
// RibbonContestStar depends on having all contest ribbons, and having RibbonContestStar requires all.
|
||||
// Since the above logic sets individual ribbons, we must try setting this deadlock pair manually.
|
||||
if (c6.RibbonMasterToughness == desiredState || c6.RibbonContestStar == desiredState)
|
||||
return;
|
||||
|
||||
la.ResetParse();
|
||||
c6.RibbonMasterToughness = c6.RibbonContestStar = desiredState;
|
||||
bool result = UpdateIsValid(la);
|
||||
if (!result)
|
||||
c6.RibbonMasterToughness = c6.RibbonContestStar = !desiredState;
|
||||
FixInvalidRibbons(args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,11 +54,10 @@ public static ModifyResult SetSuggestedMasteryData(BatchInfo info, string propVa
|
||||
|
||||
public static ModifyResult SetSuggestedRibbons(BatchInfo info, string value)
|
||||
{
|
||||
var pk = info.Entity;
|
||||
if (IsNone(value))
|
||||
RibbonApplicator.RemoveAllValidRibbons(pk);
|
||||
RibbonApplicator.RemoveAllValidRibbons(info.Legality);
|
||||
else // All
|
||||
RibbonApplicator.SetAllValidRibbons(pk);
|
||||
RibbonApplicator.SetAllValidRibbons(info.Legality);
|
||||
return ModifyResult.Modified;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,9 +40,6 @@ public static class LegalityCheckStrings
|
||||
/// <summary>Format text for exporting the <see cref="PIDIV.Type"/> that was matched for the <see cref="PKM"/></summary>
|
||||
public static string L_FPIDType_0 { get; set; } = "PID Type: {0}";
|
||||
|
||||
/// <summary>Severity string for <see cref="Severity.Indeterminate"/></summary>
|
||||
public static string L_SIndeterminate { get; set; } = "Indeterminate";
|
||||
|
||||
/// <summary>Severity string for <see cref="Severity.Invalid"/></summary>
|
||||
public static string L_SInvalid { get; set; } = "Invalid";
|
||||
|
||||
@@ -436,8 +433,8 @@ public static class LegalityCheckStrings
|
||||
|
||||
public static string LRibbonAllValid { get; set; } = "All ribbons accounted for.";
|
||||
public static string LRibbonEgg { get; set; } = "Can't receive Ribbon(s) as an Egg.";
|
||||
public static string LRibbonFInvalid_0 { get; set; } = "Invalid Ribbons: {0}";
|
||||
public static string LRibbonFMissing_0 { get; set; } = "Missing Ribbons: {0}";
|
||||
public static string LRibbonFInvalid_0 { get; set; } = "Invalid Ribbons: ";
|
||||
public static string LRibbonFMissing_0 { get; set; } = "Missing Ribbons: ";
|
||||
public static string LRibbonMarkingFInvalid_0 { get; set; } = "Invalid Marking: {0}";
|
||||
public static string LRibbonMarkingAffixedF_0 { get; set; } = "Invalid Affixed Ribbon/Marking: {0}";
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System.Linq;
|
||||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
@@ -182,10 +181,10 @@ private void VerifyShedinjaAffixed(LegalityAnalysis data, sbyte affix, PKM pk, I
|
||||
|
||||
var clone = pk.Clone();
|
||||
clone.Species = (int) Species.Nincada;
|
||||
((IRibbonIndex) clone).SetRibbon(affix);
|
||||
var parse = RibbonVerifier.GetRibbonResults(clone, data.Info.EvoChainsAllGens, enc);
|
||||
var args = new RibbonVerifierArguments(clone, enc, data.Info.EvoChainsAllGens);
|
||||
((RibbonIndex)affix).Fix(args, true);
|
||||
var name = GetRibbonNameSafe((RibbonIndex)affix);
|
||||
bool invalid = parse.FirstOrDefault(z => z.Name == name)?.Invalid == true;
|
||||
bool invalid = RibbonVerifier.IsValidExtra((RibbonIndex)affix, args);
|
||||
var severity = invalid ? Severity.Invalid : Severity.Fishy;
|
||||
data.AddLine(Get(string.Format(LRibbonMarkingAffixedF_0, name), severity));
|
||||
}
|
||||
|
||||
127
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonIndex3.cs
Normal file
127
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonIndex3.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using static PKHeX.Core.RibbonIndex3;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Ribbons from Generation 3 that were not carried forward to future formats.
|
||||
/// </summary>
|
||||
public enum RibbonIndex3 : byte
|
||||
{
|
||||
// Battle: Gen3
|
||||
Winning,
|
||||
Victory,
|
||||
|
||||
// Contest: Gen3
|
||||
Cool,
|
||||
CoolSuper,
|
||||
CoolHyper,
|
||||
CoolMaster,
|
||||
Beauty,
|
||||
BeautySuper,
|
||||
BeautyHyper,
|
||||
BeautyMaster,
|
||||
Cute,
|
||||
CuteSuper,
|
||||
CuteHyper,
|
||||
CuteMaster,
|
||||
Smart,
|
||||
SmartSuper,
|
||||
SmartHyper,
|
||||
SmartMaster,
|
||||
Tough,
|
||||
ToughSuper,
|
||||
ToughHyper,
|
||||
ToughMaster,
|
||||
|
||||
MAX_COUNT,
|
||||
}
|
||||
|
||||
public static class RibbonIndex3Extensions
|
||||
{
|
||||
public static void Fix(this RibbonIndex3 r, RibbonVerifierArguments args, bool state)
|
||||
{
|
||||
var pk = args.Entity;
|
||||
if (r is Victory or Winning)
|
||||
{
|
||||
if (pk is not IRibbonSetUnique3 u3)
|
||||
return;
|
||||
if (r is Victory)
|
||||
u3.RibbonVictory = state;
|
||||
else
|
||||
u3.RibbonWinning = state;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pk is IRibbonSetOnly3 o3)
|
||||
{
|
||||
var value = state ? 4 : 0;
|
||||
if (r is Cool)
|
||||
o3.RibbonCountG3Cool = value;
|
||||
else if (r is Beauty)
|
||||
o3.RibbonCountG3Beauty = value;
|
||||
else if (r is Cute)
|
||||
o3.RibbonCountG3Cute = value;
|
||||
else if (r is Smart)
|
||||
o3.RibbonCountG3Smart = value;
|
||||
else if (r is Tough)
|
||||
o3.RibbonCountG3Tough = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (pk is not IRibbonSetUnique4 u4)
|
||||
return;
|
||||
|
||||
_ = r switch
|
||||
{
|
||||
Cool => u4.RibbonG3Cool = state,
|
||||
CoolSuper => u4.RibbonG3CoolSuper = state,
|
||||
CoolHyper => u4.RibbonG3CoolHyper = state,
|
||||
CoolMaster => u4.RibbonG3CoolMaster = state,
|
||||
Beauty => u4.RibbonG3Beauty = state,
|
||||
BeautySuper => u4.RibbonG3BeautySuper = state,
|
||||
BeautyHyper => u4.RibbonG3BeautyHyper = state,
|
||||
BeautyMaster => u4.RibbonG3BeautyMaster = state,
|
||||
Cute => u4.RibbonG3Cute = state,
|
||||
CuteSuper => u4.RibbonG3CuteSuper = state,
|
||||
CuteHyper => u4.RibbonG3CuteHyper = state,
|
||||
CuteMaster => u4.RibbonG3CuteMaster = state,
|
||||
Smart => u4.RibbonG3Smart = state,
|
||||
SmartSuper => u4.RibbonG3SmartSuper = state,
|
||||
SmartHyper => u4.RibbonG3SmartHyper = state,
|
||||
SmartMaster => u4.RibbonG3SmartMaster = state,
|
||||
Tough => u4.RibbonG3Tough = state,
|
||||
ToughSuper => u4.RibbonG3ToughSuper = state,
|
||||
ToughHyper => u4.RibbonG3ToughHyper = state,
|
||||
ToughMaster => u4.RibbonG3ToughMaster = state,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(r), r, null),
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetPropertyName(this RibbonIndex3 r) => r switch
|
||||
{
|
||||
Winning => nameof(IRibbonSetUnique3.RibbonWinning),
|
||||
Victory => nameof(IRibbonSetUnique3.RibbonVictory),
|
||||
Cool => nameof(IRibbonSetUnique4.RibbonG3Cool),
|
||||
CoolSuper => nameof(IRibbonSetUnique4.RibbonG3CoolSuper),
|
||||
CoolHyper => nameof(IRibbonSetUnique4.RibbonG3CoolHyper),
|
||||
CoolMaster => nameof(IRibbonSetUnique4.RibbonG3CoolMaster),
|
||||
Beauty => nameof(IRibbonSetUnique4.RibbonG3Beauty),
|
||||
BeautySuper => nameof(IRibbonSetUnique4.RibbonG3BeautySuper),
|
||||
BeautyHyper => nameof(IRibbonSetUnique4.RibbonG3BeautyHyper),
|
||||
BeautyMaster => nameof(IRibbonSetUnique4.RibbonG3BeautyMaster),
|
||||
Cute => nameof(IRibbonSetUnique4.RibbonG3Cute),
|
||||
CuteSuper => nameof(IRibbonSetUnique4.RibbonG3CuteSuper),
|
||||
CuteHyper => nameof(IRibbonSetUnique4.RibbonG3CuteHyper),
|
||||
CuteMaster => nameof(IRibbonSetUnique4.RibbonG3CuteMaster),
|
||||
Smart => nameof(IRibbonSetUnique4.RibbonG3Smart),
|
||||
SmartSuper => nameof(IRibbonSetUnique4.RibbonG3SmartSuper),
|
||||
SmartHyper => nameof(IRibbonSetUnique4.RibbonG3SmartHyper),
|
||||
SmartMaster => nameof(IRibbonSetUnique4.RibbonG3SmartMaster),
|
||||
Tough => nameof(IRibbonSetUnique4.RibbonG3Tough),
|
||||
ToughSuper => nameof(IRibbonSetUnique4.RibbonG3ToughSuper),
|
||||
ToughHyper => nameof(IRibbonSetUnique4.RibbonG3ToughHyper),
|
||||
ToughMaster => nameof(IRibbonSetUnique4.RibbonG3ToughMaster),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(r), r, null),
|
||||
};
|
||||
}
|
||||
114
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonIndex4.cs
Normal file
114
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonIndex4.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using static PKHeX.Core.RibbonIndex4;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Ribbons from Generation 4 that were not carried forward to future formats.
|
||||
/// </summary>
|
||||
public enum RibbonIndex4 : byte
|
||||
{
|
||||
// Battle: Gen4
|
||||
Ability,
|
||||
AbilityGreat,
|
||||
AbilityDouble,
|
||||
AbilityMulti,
|
||||
AbilityPair,
|
||||
AbilityWorld,
|
||||
|
||||
// Contest: Gen4
|
||||
Cool,
|
||||
CoolGreat,
|
||||
CoolUltra,
|
||||
CoolMaster,
|
||||
Beauty,
|
||||
BeautyGreat,
|
||||
BeautyUltra,
|
||||
BeautyMaster,
|
||||
Cute,
|
||||
CuteGreat,
|
||||
CuteUltra,
|
||||
CuteMaster,
|
||||
Smart,
|
||||
SmartGreat,
|
||||
SmartUltra,
|
||||
SmartMaster,
|
||||
Tough,
|
||||
ToughGreat,
|
||||
ToughUltra,
|
||||
ToughMaster,
|
||||
|
||||
MAX_COUNT,
|
||||
}
|
||||
|
||||
public static class RibbonIndex4Extensions
|
||||
{
|
||||
public static void Fix(this RibbonIndex4 r, RibbonVerifierArguments args, bool state)
|
||||
{
|
||||
var pk = args.Entity;
|
||||
if (pk is not IRibbonSetUnique4 u4)
|
||||
return;
|
||||
|
||||
_ = r switch
|
||||
{
|
||||
RibbonIndex4.Ability => u4.RibbonAbility = state,
|
||||
AbilityGreat => u4.RibbonAbilityGreat = state,
|
||||
AbilityDouble => u4.RibbonAbilityDouble = state,
|
||||
AbilityMulti => u4.RibbonAbilityMulti = state,
|
||||
AbilityPair => u4.RibbonAbilityPair = state,
|
||||
AbilityWorld => u4.RibbonAbilityWorld = state,
|
||||
Cool => u4.RibbonG4Cool = state,
|
||||
CoolGreat => u4.RibbonG4CoolGreat = state,
|
||||
CoolUltra => u4.RibbonG4CoolUltra = state,
|
||||
CoolMaster => u4.RibbonG4CoolMaster = state,
|
||||
Beauty => u4.RibbonG4Beauty = state,
|
||||
BeautyGreat => u4.RibbonG4BeautyGreat = state,
|
||||
BeautyUltra => u4.RibbonG4BeautyUltra = state,
|
||||
BeautyMaster => u4.RibbonG4BeautyMaster = state,
|
||||
Cute => u4.RibbonG4Cute = state,
|
||||
CuteGreat => u4.RibbonG4CuteGreat = state,
|
||||
CuteUltra => u4.RibbonG4CuteUltra = state,
|
||||
CuteMaster => u4.RibbonG4CuteMaster = state,
|
||||
Smart => u4.RibbonG4Smart = state,
|
||||
SmartGreat => u4.RibbonG4SmartGreat = state,
|
||||
SmartUltra => u4.RibbonG4SmartUltra = state,
|
||||
SmartMaster => u4.RibbonG4SmartMaster = state,
|
||||
Tough => u4.RibbonG4Tough = state,
|
||||
ToughGreat => u4.RibbonG4ToughGreat = state,
|
||||
ToughUltra => u4.RibbonG4ToughUltra = state,
|
||||
ToughMaster => u4.RibbonG4ToughMaster = state,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(r), r, null)
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetPropertyName(this RibbonIndex4 r) => r switch
|
||||
{
|
||||
RibbonIndex4.Ability => nameof(IRibbonSetUnique4.RibbonAbility),
|
||||
AbilityGreat => nameof(IRibbonSetUnique4.RibbonAbilityGreat),
|
||||
AbilityDouble => nameof(IRibbonSetUnique4.RibbonAbilityDouble),
|
||||
AbilityMulti => nameof(IRibbonSetUnique4.RibbonAbilityMulti),
|
||||
AbilityPair => nameof(IRibbonSetUnique4.RibbonAbilityPair),
|
||||
AbilityWorld => nameof(IRibbonSetUnique4.RibbonAbilityWorld),
|
||||
Cool => nameof(IRibbonSetUnique4.RibbonG4Cool),
|
||||
CoolGreat => nameof(IRibbonSetUnique4.RibbonG4CoolGreat),
|
||||
CoolUltra => nameof(IRibbonSetUnique4.RibbonG4CoolUltra),
|
||||
CoolMaster => nameof(IRibbonSetUnique4.RibbonG4CoolMaster),
|
||||
Beauty => nameof(IRibbonSetUnique4.RibbonG4Beauty),
|
||||
BeautyGreat => nameof(IRibbonSetUnique4.RibbonG4BeautyGreat),
|
||||
BeautyUltra => nameof(IRibbonSetUnique4.RibbonG4BeautyUltra),
|
||||
BeautyMaster => nameof(IRibbonSetUnique4.RibbonG4BeautyMaster),
|
||||
Cute => nameof(IRibbonSetUnique4.RibbonG4Cute),
|
||||
CuteGreat => nameof(IRibbonSetUnique4.RibbonG4CuteGreat),
|
||||
CuteUltra => nameof(IRibbonSetUnique4.RibbonG4CuteUltra),
|
||||
CuteMaster => nameof(IRibbonSetUnique4.RibbonG4CuteMaster),
|
||||
Smart => nameof(IRibbonSetUnique4.RibbonG4Smart),
|
||||
SmartGreat => nameof(IRibbonSetUnique4.RibbonG4SmartGreat),
|
||||
SmartUltra => nameof(IRibbonSetUnique4.RibbonG4SmartUltra),
|
||||
SmartMaster => nameof(IRibbonSetUnique4.RibbonG4SmartMaster),
|
||||
Tough => nameof(IRibbonSetUnique4.RibbonG4Tough),
|
||||
ToughGreat => nameof(IRibbonSetUnique4.RibbonG4ToughGreat),
|
||||
ToughUltra => nameof(IRibbonSetUnique4.RibbonG4ToughUltra),
|
||||
ToughMaster => nameof(IRibbonSetUnique4.RibbonG4ToughMaster),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(r), r, null),
|
||||
};
|
||||
}
|
||||
@@ -1,28 +1,64 @@
|
||||
namespace PKHeX.Core;
|
||||
using System;
|
||||
using static PKHeX.Core.RibbonParseFlags;
|
||||
|
||||
/// <summary>
|
||||
/// Legality Check Parse object containing information about a single ribbon.
|
||||
/// </summary>
|
||||
internal sealed class RibbonResult
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public readonly record struct RibbonResult
|
||||
{
|
||||
/// <summary>Ribbon Display Name</summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>Ribbon should not be present.</summary>
|
||||
/// <remarks>If this is false, the Ribbon is missing.</remarks>
|
||||
public bool Invalid { get; }
|
||||
|
||||
public RibbonResult(string prop, bool invalid = true)
|
||||
{
|
||||
Name = RibbonStrings.GetName(prop);
|
||||
Invalid = invalid;
|
||||
}
|
||||
private readonly byte Value;
|
||||
private readonly RibbonParseFlags Flags;
|
||||
|
||||
/// <summary>
|
||||
/// Merges the result name with another provided result.
|
||||
/// True: ribbon is missing -- should have the ribbon.
|
||||
/// False: ribbon is invalid -- should not have the ribbon.
|
||||
/// </summary>
|
||||
public void Combine(RibbonResult other)
|
||||
public bool IsMissing => (Flags & Missing) != 0;
|
||||
|
||||
private RibbonParseFlags Type => Flags & ~Missing;
|
||||
|
||||
public RibbonResult(RibbonIndex index, bool missing = false) { Value = (byte)index; Flags = missing ? MissingM : Mainline; }
|
||||
public RibbonResult(RibbonIndex3 index, bool missing = false) { Value = (byte)index; Flags = missing ? Missing3 : Index3; }
|
||||
public RibbonResult(RibbonIndex4 index, bool missing = false) { Value = (byte)index; Flags = missing ? Missing4 : Index4; }
|
||||
public bool Equals(RibbonIndex index) => Type == Mainline && Value == (byte)index;
|
||||
public bool Equals(RibbonIndex3 index) => Type == Index3 && Value == (byte)index;
|
||||
public bool Equals(RibbonIndex4 index) => Type == Index4 && Value == (byte)index;
|
||||
|
||||
/// <summary>
|
||||
/// Property Name that the ribbon can be get/set with, or looked up for localization.
|
||||
/// </summary>
|
||||
public string PropertyName => Type switch
|
||||
{
|
||||
Name += $" / {other.Name}";
|
||||
Mainline => ((RibbonIndex)Value).GetPropertyName(),
|
||||
Index3 => ((RibbonIndex3)Value).GetPropertyName(),
|
||||
Index4 => ((RibbonIndex4)Value).GetPropertyName(),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Updates the ribbon state depending on the <see cref="args"/> and <see cref="IsMissing"/> state.
|
||||
/// </summary>
|
||||
public void Fix(RibbonVerifierArguments args)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case Mainline: ((RibbonIndex)Value).Fix(args, IsMissing); break;
|
||||
case Index3: ((RibbonIndex3)Value).Fix(args, IsMissing); break;
|
||||
case Index4: ((RibbonIndex4)Value).Fix(args, IsMissing); break;
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum RibbonParseFlags : byte
|
||||
{
|
||||
None = 0,
|
||||
Mainline,
|
||||
Index3,
|
||||
Index4,
|
||||
|
||||
Missing = 0x80,
|
||||
MissingM = Missing | Mainline,
|
||||
Missing3 = Missing | Index3,
|
||||
Missing4 = Missing | Index4,
|
||||
}
|
||||
|
||||
25
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonResultList.cs
Normal file
25
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonResultList.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public ref struct RibbonResultList
|
||||
{
|
||||
private readonly Span<RibbonResult> Span;
|
||||
public int Count { get; private set; }
|
||||
|
||||
public RibbonResultList(Span<RibbonResult> span)
|
||||
{
|
||||
Span = span;
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
private void Add(RibbonResult item)
|
||||
{
|
||||
Span[Count] = item;
|
||||
++Count;
|
||||
}
|
||||
|
||||
public void Add(RibbonIndex index, bool missing = false) => Add(new(index, missing));
|
||||
public void Add(RibbonIndex3 index, bool missing = false) => Add(new(index, missing));
|
||||
public void Add(RibbonIndex4 index, bool missing = false) => Add(new(index, missing));
|
||||
}
|
||||
342
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonRules.cs
Normal file
342
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonRules.cs
Normal file
@@ -0,0 +1,342 @@
|
||||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Rules for obtaining ribbons.
|
||||
/// </summary>
|
||||
public static class RibbonRules
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if the input can receive the <see cref="IRibbonSetCommon7.RibbonChampionAlola"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidAlolaChamp(IRibbonSetCommon7 s7, IEncounterTemplate enc, bool inhabited7)
|
||||
{
|
||||
// If the encounter comes with the ribbon, it must have the ribbon.
|
||||
if (enc is IRibbonSetCommon7 { RibbonChampionAlola: true })
|
||||
return s7.RibbonChampionAlola;
|
||||
// If it has visited, it can be either state.
|
||||
if (inhabited7)
|
||||
return true;
|
||||
// If it has not visited, it must not have it.
|
||||
return !s7.RibbonChampionAlola;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can receive the <see cref="IRibbonSetCommon3.RibbonEffort"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidEffort(PKM pk, EvolutionHistory evos, int gen) => gen switch
|
||||
{
|
||||
5 when pk.Format == 5 => false, // Not available in BW/B2W2
|
||||
8 when !evos.HasVisitedSWSH && !evos.HasVisitedBDSP => false, // not available in PLA
|
||||
_ => true,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can receive the <see cref="IRibbonSetCommon6.RibbonBestFriends"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidBestFriends(PKM pk, EvolutionHistory evos, int gen) => gen switch
|
||||
{
|
||||
< 7 when pk is { IsUntraded: true } and IAffection { OT_Affection: < 255 } => false, // Gen6/7 uses affection. Can't lower it on OT!
|
||||
8 when !evos.HasVisitedSWSH && !evos.HasVisitedBDSP => false, // Gen8+ replaced with Max Friendship.
|
||||
_ => true,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can receive the <see cref="IRibbonSetCommon4.RibbonFootprint"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidFootprint(PKM pk, EvolutionHistory evos)
|
||||
{
|
||||
// Gen3/4: Friendship maxed. Can decrease after obtaining ribbon, no check needed.
|
||||
if (evos.HasVisitedGen3 || evos.HasVisitedGen4)
|
||||
return true;
|
||||
|
||||
// Gen5: Can't obtain
|
||||
if (pk.Format < 6)
|
||||
return false;
|
||||
|
||||
// Gen6/7: Increase level by 30 from original level
|
||||
static bool IsWellTraveled30(PKM pk) => pk.CurrentLevel - pk.Met_Level >= 30;
|
||||
if ((evos.HasVisitedGen6 || evos.HasVisitedGen7) && IsWellTraveled30(pk))
|
||||
return true;
|
||||
|
||||
// Gen8-BDSP: Variable by species Footprint
|
||||
if (evos.HasVisitedBDSP)
|
||||
{
|
||||
if (IsAnyWithoutFootprint8b(evos.Gen8b))
|
||||
return true; // no footprint
|
||||
if (IsWellTraveled30(pk))
|
||||
return true; // traveled well
|
||||
}
|
||||
|
||||
// Otherwise: Can't obtain
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the entity participated in SW/SH ranked battles for the <see cref="IRibbonSetCommon8.RibbonMasterRank"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidMasterRankSWSH(PKM pk, IEncounterTemplate enc, EvolutionHistory evos)
|
||||
{
|
||||
if (!evos.HasVisitedSWSH)
|
||||
return false;
|
||||
|
||||
if (enc.Generation < 8 && pk is IBattleVersion { BattleVersion: 0 })
|
||||
return false;
|
||||
|
||||
// GO transfers: Capture date is global time, and not console changeable.
|
||||
bool hasRealDate = enc.Version == GameVersion.GO || enc is IEncounterServerDate { IsDateRestricted: true };
|
||||
if (hasRealDate)
|
||||
{
|
||||
var met = pk.MetDate;
|
||||
if (met > new DateTime(2022, 11, 1)) // Series 13 end date +1 day (wiggle room)
|
||||
return false; // Ranked is done!
|
||||
}
|
||||
|
||||
// Series 13 rule-set was the first time Ranked Battles allowed the use of Mythical Pokémon.
|
||||
// All species that can exist in SW/SH can compete in ranked.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can receive the <see cref="IRibbonSetCommon6.RibbonTraining"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidSuperTraining(ISuperTrain pk)
|
||||
{
|
||||
// It is assumed that the entity existed in the Gen6 game to receive the ribbon.
|
||||
// We only enter this method if the entity implements the interface.
|
||||
const int req = 12; // only first 12 are required to get the ribbon.
|
||||
int count = pk.SuperTrainingMedalCount(req);
|
||||
return count >= req;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the entity participated in battles for the <see cref="IRibbonSetCommon8.RibbonTowerMaster"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidTowerMaster(EvolutionHistory evos)
|
||||
{
|
||||
if (evos.HasVisitedSWSH)
|
||||
return true; // Anything in SW/SH can be used in battle tower.
|
||||
|
||||
if (!evos.HasVisitedBDSP)
|
||||
return false;
|
||||
// Mythicals cannot be used in BD/SP's Battle Tower
|
||||
return !Legal.Mythicals.Contains(evos.Gen8b[0].Species);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can receive the <see cref="IRibbonSetUnique3.RibbonWinning"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidWinning(PKM pk, IEncounterTemplate enc, EvolutionHistory evos)
|
||||
{
|
||||
if (!evos.HasVisitedGen3)
|
||||
return false;
|
||||
if (!IsAllowedBattleFrontier(evos.Gen3[0].Species))
|
||||
return false;
|
||||
|
||||
// Can only obtain if the current level on receiving the ribbon is <= level 50.
|
||||
if (pk.Format == 3) // Stored value is not yet overwritten (G3->G4), check directly.
|
||||
return pk.Met_Level <= 50;
|
||||
|
||||
// Most encounter types can be below level 50; only Shadow Dragonite & Tyranitar, and select Gen3 Event Gifts.
|
||||
// These edge cases can't be obtained below level 50, unlike some wild Pokémon which can be encountered at different locations for lower levels.
|
||||
if (enc.LevelMin <= 50)
|
||||
return true;
|
||||
|
||||
return enc is not (EncounterStaticShadow or WC3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can receive the <see cref="IRibbonSetUnique3.RibbonVictory"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidVictory(EvolutionHistory evos)
|
||||
{
|
||||
if (evos.HasVisitedGen3)
|
||||
return IsAllowedBattleFrontier(evos.Gen3[0].Species);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can receive the <see cref="IRibbonSetCommon8.RibbonTwinklingStar"/> ribbon.
|
||||
/// </summary>
|
||||
public static bool IsRibbonValidTwinklingStar(EvolutionHistory evos, PKM pk)
|
||||
{
|
||||
// Can currently only obtain from BD/SP.
|
||||
if (!evos.HasVisitedBDSP)
|
||||
return false;
|
||||
|
||||
// Can only obtain if it has already completed all the other contests and received the summation ribbon.
|
||||
if (pk is IRibbonSetCommon6 { RibbonContestStar: false })
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if any of the species it existed as in BD/SP lacked footprints.
|
||||
/// </summary>
|
||||
private static bool IsAnyWithoutFootprint8b(EvoCriteria[] evos)
|
||||
{
|
||||
var arr = HasFootprintBDSP;
|
||||
foreach (var evo in evos)
|
||||
{
|
||||
var species = evo.Species;
|
||||
if ((uint)species >= arr.Length)
|
||||
continue;
|
||||
if (!arr[species])
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Derived from ROM data: true for all Footprint types besides 5 (5 = no feet).
|
||||
// If true, requires gaining 30 levels to obtain ribbon. If false, can obtain ribbon at any level.
|
||||
private static readonly bool[] HasFootprintBDSP =
|
||||
{
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, false, true, true, false, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, false, false, true, false,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, false, false, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
false, false, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, false, true, true,
|
||||
false, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, false, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, false, true, true, false, false, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, false, true, true, true, true, true, true,
|
||||
true, true, true, false, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, false, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, false, true, false, true,
|
||||
true, true, true, false, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
false, true, true, true, true, true, true, true, true, false,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, false, false, true,
|
||||
true, true, true, false, false, false, false, false, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, false, true, false, false, true, false, false, false,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, false, false, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, false, true, true, true, true, true, true, true,
|
||||
true, true, true, true, false, true, false, true, true, true,
|
||||
true, true, true, true, true, true, false, true, true, true,
|
||||
true, true, true, true,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the input can receive the <see cref="IRibbonSetEvent3.RibbonNational"/> ribbon.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If returns true, must have the ribbon. If returns false, must not have the ribbon.
|
||||
/// </remarks>
|
||||
public static bool GetValidRibbonStateNational(PKM pk, IEncounterTemplate enc)
|
||||
{
|
||||
// Can only obtain from Generation 3 Shadow Pokémon
|
||||
if (enc.Generation != 3)
|
||||
return false;
|
||||
|
||||
if (enc is not EncounterStaticShadow)
|
||||
return false;
|
||||
|
||||
// Ribbon is awarded when the Pokémon is purified in the game of origin.
|
||||
if (pk is IShadowPKM { IsShadow: true })
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the max count values the input can receive for the <see cref="IRibbonSetCommon6.RibbonCountMemoryContest"/> and <see cref="IRibbonSetCommon6.RibbonCountMemoryBattle"/> ribbon counts.
|
||||
/// </summary>
|
||||
public static (byte Contest, byte Battle) GetMaxMemoryCounts(EvolutionHistory evos, PKM pk, IEncounterTemplate enc)
|
||||
{
|
||||
// Contest: 20 in both Generations.
|
||||
const byte MaxContest4 = 20;
|
||||
const byte MaxContest3 = 20;
|
||||
const byte MaxContestBoth = MaxContest3 + MaxContest4; // 40
|
||||
|
||||
// Battle: 2 in Gen3, 6 in Gen4; one (Winning) in Gen3 has extra restrictions.
|
||||
const byte MaxBattle3 = 2;
|
||||
const byte MaxBattle4 = 6;
|
||||
const byte MaxBattleBoth = MaxBattle3 + MaxBattle4; // 8
|
||||
const byte MaxBattleBothNoWinning = MaxBattleBoth - 1; // 7
|
||||
|
||||
if (evos.HasVisitedGen3)
|
||||
{
|
||||
var head = evos.Gen3[0]; // Checking contest with Gen3 head is fine; all false cases cannot evolve (evolution chain is same Gen3/Gen4).
|
||||
var contest = IsAllowedContest4(head.Species, head.Form) ? MaxContestBoth : MaxContest3;
|
||||
var battle = IsAllowedBattleFrontier(head.Species) ? IsRibbonValidWinning(pk, enc, evos) ? MaxBattleBoth : MaxBattleBothNoWinning : (byte)0;
|
||||
return (contest, battle);
|
||||
}
|
||||
if (evos.HasVisitedGen4)
|
||||
{
|
||||
var head = evos.Gen4[0];
|
||||
var contest = IsAllowedContest4(head.Species, head.Form) ? MaxContest4 : (byte)0;
|
||||
var battle = IsAllowedBattleFrontier(head.Species) ? MaxBattle4 : (byte)0;
|
||||
return (contest, battle);
|
||||
}
|
||||
return default;
|
||||
}
|
||||
|
||||
public static bool IsAllowedContest3(EvolutionHistory evos)
|
||||
{
|
||||
// Any species can enter contests in Gen3.
|
||||
return evos.HasVisitedGen3;
|
||||
}
|
||||
|
||||
public static bool IsAllowedContest4(EvolutionHistory evos)
|
||||
{
|
||||
if (!evos.HasVisitedGen4)
|
||||
return false;
|
||||
var head = evos.Gen4[0];
|
||||
return IsAllowedContest4(head.Species, head.Form);
|
||||
}
|
||||
|
||||
public static bool IsAllowedContest4(int species, int form) => species switch
|
||||
{
|
||||
// Disallow Unown and Ditto, and Spiky Pichu (cannot trade)
|
||||
(int)Species.Ditto => false,
|
||||
(int)Species.Unown => false,
|
||||
(int)Species.Pichu when form == 1 => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
public static bool IsAllowedBattleFrontier(int species) => !Legal.BattleFrontierBanlist.Contains(species);
|
||||
|
||||
public static bool IsAllowedBattleFrontier4(EvolutionHistory evos)
|
||||
{
|
||||
if (!evos.HasVisitedGen4)
|
||||
return false;
|
||||
var head = evos.Gen4[0];
|
||||
return IsAllowedBattleFrontier(head.Species, head.Form, 4);
|
||||
}
|
||||
|
||||
public static bool IsAllowedBattleFrontier(int species, int form, int gen)
|
||||
{
|
||||
if (gen == 4 && species == (int)Species.Pichu && form == 1) // spiky
|
||||
return false;
|
||||
return IsAllowedBattleFrontier(species);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
@@ -12,6 +11,17 @@ public sealed class RibbonVerifier : Verifier
|
||||
{
|
||||
protected override CheckIdentifier Identifier => CheckIdentifier.Ribbon;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum amount of ribbons to consider when allocating a span for parsing.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Minor optimization is to stackalloc as little as possible, without too much calculation.
|
||||
/// <see cref="RibbonIndex3.MAX_COUNT"/> + <see cref="RibbonIndex4.MAX_COUNT"/> is 48, but are not present after Gen5.
|
||||
/// <see cref="PK5"/> only has 80 ribbons implemented.
|
||||
/// Instead of using the sum of all 3 enums, we can use <see cref="RibbonIndex.MAX_COUNT"/> as the true maximum count.
|
||||
/// </remarks>
|
||||
public const int MaxRibbonCount = (int)RibbonIndex.MAX_COUNT;
|
||||
|
||||
public override void Verify(LegalityAnalysis data)
|
||||
{
|
||||
// Flag VC (Gen1/2) ribbons using Gen7 origin rules.
|
||||
@@ -19,696 +29,155 @@ public override void Verify(LegalityAnalysis data)
|
||||
var pk = data.Entity;
|
||||
|
||||
// Check Unobtainable Ribbons
|
||||
if (pk.IsEgg)
|
||||
var args = new RibbonVerifierArguments(pk, enc, data.Info.EvoChainsAllGens);
|
||||
Span<RibbonResult> result = stackalloc RibbonResult[MaxRibbonCount];
|
||||
int count = GetRibbonResults(args, result);
|
||||
if (count == 0)
|
||||
{
|
||||
if (GetIncorrectRibbonsEgg(pk, enc))
|
||||
data.AddLine(GetInvalid(LRibbonEgg));
|
||||
data.AddLine(GetValid(LRibbonAllValid));
|
||||
return;
|
||||
}
|
||||
|
||||
var result = GetIncorrectRibbons(pk, data.Info.EvoChainsAllGens, enc);
|
||||
if (result.Count != 0)
|
||||
var msg = GetMessage(result[..count]);
|
||||
data.AddLine(GetInvalid(msg));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="index"/> is not an invalid/missing ribbon in the result parse.
|
||||
/// </summary>
|
||||
/// <param name="index">Ribbon Index to check for</param>
|
||||
/// <param name="args">Inputs to analyze</param>
|
||||
/// <returns>True if not present in the flagged result span.</returns>
|
||||
public static bool IsValidExtra(RibbonIndex index, RibbonVerifierArguments args)
|
||||
{
|
||||
Span<RibbonResult> result = stackalloc RibbonResult[MaxRibbonCount];
|
||||
int count = GetRibbonResults(args, result);
|
||||
if (count == 0)
|
||||
return true;
|
||||
|
||||
var span = result[..count];
|
||||
foreach (var x in span)
|
||||
{
|
||||
var msg = string.Join(Environment.NewLine, result);
|
||||
data.AddLine(GetInvalid(msg));
|
||||
if (x.Equals(index))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uses the input <see cref="args"/> and stores results in the <see cref="result"/> span.
|
||||
/// </summary>
|
||||
/// <param name="args">Inputs to analyze</param>
|
||||
/// <param name="result">Result storage</param>
|
||||
/// <returns>Count of elements filled in the <see cref="result"/> span.</returns>
|
||||
public static int GetRibbonResults(RibbonVerifierArguments args, Span<RibbonResult> result)
|
||||
{
|
||||
var list = new RibbonResultList(result);
|
||||
return GetRibbonResults(args, ref list);
|
||||
}
|
||||
|
||||
private static int GetRibbonResults(RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
if (!args.Entity.IsEgg)
|
||||
Parse(args, ref list);
|
||||
else
|
||||
ParseEgg(args, ref list);
|
||||
|
||||
return list.Count;
|
||||
}
|
||||
|
||||
private static string GetMessage(ReadOnlySpan<RibbonResult> result)
|
||||
{
|
||||
var total = result.Length;
|
||||
int missing = GetCountMissing(result);
|
||||
int invalid = total - missing;
|
||||
var sb = new StringBuilder(total * 20);
|
||||
if (missing != 0)
|
||||
AppendAll(result, sb, LRibbonFMissing_0, true);
|
||||
if (invalid != 0)
|
||||
{
|
||||
data.AddLine(GetValid(LRibbonAllValid));
|
||||
if (missing != 0) // need to visually separate the message
|
||||
sb.Append(Environment.NewLine);
|
||||
AppendAll(result, sb, LRibbonFInvalid_0, false);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static List<string> GetIncorrectRibbons(PKM pk, EvolutionHistory evos, IEncounterTemplate enc)
|
||||
private static int GetCountMissing(ReadOnlySpan<RibbonResult> result)
|
||||
{
|
||||
List<string> missingRibbons = new();
|
||||
List<string> invalidRibbons = new();
|
||||
var ribs = GetRibbonResults(pk, evos, enc);
|
||||
foreach (var bad in ribs)
|
||||
(bad.Invalid ? invalidRibbons : missingRibbons).Add(bad.Name);
|
||||
|
||||
var result = new List<string>();
|
||||
if (missingRibbons.Count > 0)
|
||||
result.Add(string.Format(LRibbonFMissing_0, string.Join(", ", missingRibbons).Replace(RibbonInfo.PropertyPrefix, string.Empty)));
|
||||
if (invalidRibbons.Count > 0)
|
||||
result.Add(string.Format(LRibbonFInvalid_0, string.Join(", ", invalidRibbons).Replace(RibbonInfo.PropertyPrefix, string.Empty)));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool GetIncorrectRibbonsEgg(PKM pk, IEncounterTemplate enc)
|
||||
{
|
||||
var names = ReflectUtil.GetPropertiesStartWithPrefix(pk.GetType(), RibbonInfo.PropertyPrefix);
|
||||
if (enc is IRibbonSetEvent3 event3)
|
||||
names = names.Except(event3.RibbonNames());
|
||||
if (enc is IRibbonSetEvent4 event4)
|
||||
names = names.Except(event4.RibbonNames());
|
||||
|
||||
foreach (var value in names.Select(name => ReflectUtil.GetValue(pk, name)))
|
||||
int count = 0;
|
||||
foreach (var x in result)
|
||||
{
|
||||
if (value is null)
|
||||
if (x.IsMissing)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private const string MessageSplitNextRibbon = ", ";
|
||||
|
||||
private static void AppendAll(ReadOnlySpan<RibbonResult> result, StringBuilder sb, string startText, bool stateMissing)
|
||||
{
|
||||
int added = 0;
|
||||
sb.Append(startText);
|
||||
foreach (var x in result)
|
||||
{
|
||||
if (x.IsMissing != stateMissing)
|
||||
continue;
|
||||
if (HasFlag(value) || HasCount(value))
|
||||
return true;
|
||||
|
||||
static bool HasFlag(object o) => o is true;
|
||||
static bool HasCount(object o) => o is > 0;
|
||||
if (added++ != 0)
|
||||
sb.Append(MessageSplitNextRibbon);
|
||||
var localized = RibbonStrings.GetName(x.PropertyName);
|
||||
sb.Append(localized);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static IEnumerable<RibbonResult> GetRibbonResults(PKM pk, EvolutionHistory evos, IEncounterTemplate enc)
|
||||
private static void Parse(RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
return GetInvalidRibbons(pk, evos, enc)
|
||||
.Concat(GetInvalidRibbonsEvent1(pk, enc))
|
||||
.Concat(GetInvalidRibbonsEvent2(pk, enc));
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbons(PKM pk, EvolutionHistory evos, IEncounterTemplate enc)
|
||||
{
|
||||
// is a part of Event4, but O3 doesn't have the others
|
||||
if (pk is IRibbonSetOnly3 {RibbonWorld: true})
|
||||
yield return new RibbonResult(nameof(IRibbonSetOnly3.RibbonWorld));
|
||||
|
||||
var pk = args.Entity;
|
||||
if (pk is IRibbonSetOnly3 o3)
|
||||
o3.Parse(args, ref list);
|
||||
if (pk is IRibbonSetEvent3 e3)
|
||||
e3.Parse(args, ref list);
|
||||
if (pk is IRibbonSetEvent4 e4)
|
||||
e4.Parse(args, ref list);
|
||||
if (pk is IRibbonSetUnique3 u3)
|
||||
{
|
||||
if (enc.Generation != 3)
|
||||
{
|
||||
if (u3.RibbonWinning)
|
||||
yield return new RibbonResult(nameof(u3.RibbonWinning));
|
||||
if (u3.RibbonVictory)
|
||||
yield return new RibbonResult(nameof(u3.RibbonVictory));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (u3.RibbonWinning && !CanHaveRibbonWinning(pk, enc, 3))
|
||||
yield return new RibbonResult(nameof(u3.RibbonWinning));
|
||||
if (u3.RibbonVictory && !CanHaveRibbonVictory(pk, 3))
|
||||
yield return new RibbonResult(nameof(u3.RibbonVictory));
|
||||
}
|
||||
}
|
||||
|
||||
int gen = enc.Generation;
|
||||
if (pk is IRibbonSetUnique4 u4)
|
||||
{
|
||||
if (!IsAllowedBattleFrontier(pk.Species, pk.Form, 4) || gen > 4)
|
||||
{
|
||||
foreach (var z in GetInvalidRibbonsNone(u4.RibbonBitsAbility(), u4.RibbonNamesAbility()))
|
||||
yield return z;
|
||||
}
|
||||
|
||||
var c3 = u4.RibbonBitsContest3();
|
||||
var c3n = u4.RibbonNamesContest3();
|
||||
var iter3 = gen == 3 ? GetMissingContestRibbons(c3, c3n) : GetInvalidRibbonsNone(c3, c3n);
|
||||
foreach (var z in iter3)
|
||||
yield return z;
|
||||
|
||||
var c4 = u4.RibbonBitsContest4();
|
||||
var c4n = u4.RibbonNamesContest4();
|
||||
var iter4 = (gen is 3 or 4) && IsAllowedInContest4(pk.Species, pk.Form) ? GetMissingContestRibbons(c4, c4n) : GetInvalidRibbonsNone(c4, c4n);
|
||||
foreach (var z in iter4)
|
||||
yield return z;
|
||||
}
|
||||
if (pk is IRibbonSetCommon4 s4)
|
||||
{
|
||||
bool inhabited4 = gen is 3 or 4;
|
||||
var iterate = GetInvalidRibbons4Any(pk, evos, s4, gen);
|
||||
if (!inhabited4)
|
||||
{
|
||||
if (evos.HasVisitedBDSP) // Allow Sinnoh Champion. ILCA reused the Gen4 ribbon for the remake.
|
||||
iterate = iterate.Concat(GetInvalidRibbonsNoneSkipIndex(s4.RibbonBitsOnly(), s4.RibbonNamesOnly(), 1));
|
||||
else
|
||||
iterate = iterate.Concat(GetInvalidRibbonsNone(s4.RibbonBitsOnly(), s4.RibbonNamesOnly()));
|
||||
}
|
||||
foreach (var z in iterate)
|
||||
yield return z;
|
||||
}
|
||||
if (pk is IRibbonSetCommon6 s6)
|
||||
{
|
||||
bool inhabited6 = gen is >= 3 and <= 6;
|
||||
|
||||
var iterate = inhabited6
|
||||
? GetInvalidRibbons6Any(pk, s6, gen, enc)
|
||||
: pk.Format >= 8
|
||||
? GetInvalidRibbons6AnyG8(s6, evos)
|
||||
: GetInvalidRibbonsNone(s6.RibbonBits(), s6.RibbonNamesBool());
|
||||
foreach (var z in iterate)
|
||||
yield return z;
|
||||
|
||||
if (!inhabited6)
|
||||
{
|
||||
if (s6.RibbonCountMemoryContest > 0)
|
||||
yield return new RibbonResult(nameof(s6.RibbonCountMemoryContest));
|
||||
if (s6.RibbonCountMemoryBattle > 0)
|
||||
yield return new RibbonResult(nameof(s6.RibbonCountMemoryBattle));
|
||||
}
|
||||
|
||||
if (s6.RibbonBestFriends && !IsRibbonValidBestFriend(pk, evos, gen))
|
||||
yield return new RibbonResult(nameof(IRibbonSetCommon6.RibbonBestFriends));
|
||||
}
|
||||
if (pk is IRibbonSetCommon7 s7)
|
||||
{
|
||||
bool inhabited7 = evos.HasVisitedGen7;
|
||||
bool alolaValid = GetIsAlolaChampValid(s7, enc, inhabited7);
|
||||
if (!alolaValid)
|
||||
yield return new RibbonResult(nameof(s7.RibbonChampionAlola));
|
||||
|
||||
if (!inhabited7 || !IsAllowedBattleFrontier(pk.Species))
|
||||
{
|
||||
if (s7.RibbonBattleRoyale)
|
||||
yield return new RibbonResult(nameof(s7.RibbonBattleRoyale));
|
||||
if (s7.RibbonBattleTreeGreat && !pk.USUM && pk.IsUntraded)
|
||||
yield return new RibbonResult(nameof(s7.RibbonBattleTreeGreat));
|
||||
if (s7.RibbonBattleTreeMaster)
|
||||
yield return new RibbonResult(nameof(s7.RibbonBattleTreeMaster));
|
||||
}
|
||||
}
|
||||
u3.Parse(args, ref list);
|
||||
if (pk is IRibbonSetCommon3 s3)
|
||||
{
|
||||
if (s3.RibbonChampionG3 && gen != 3)
|
||||
yield return new RibbonResult(nameof(s3.RibbonChampionG3)); // RSE HoF
|
||||
if (s3.RibbonArtist && gen != 3)
|
||||
yield return new RibbonResult(nameof(s3.RibbonArtist)); // RSE Master Rank Portrait
|
||||
if (s3.RibbonEffort && !IsRibbonValidEffort(pk, evos, gen)) // unobtainable in Gen 5
|
||||
yield return new RibbonResult(nameof(s3.RibbonEffort));
|
||||
}
|
||||
s3.Parse(args, ref list);
|
||||
if (pk is IRibbonSetUnique4 u4)
|
||||
u4.Parse(args, ref list);
|
||||
if (pk is IRibbonSetCommon4 s4)
|
||||
s4.Parse(args, ref list);
|
||||
if (pk is IRibbonSetCommon6 s6)
|
||||
s6.Parse(args, ref list);
|
||||
if (pk is IRibbonSetCommon7 s7)
|
||||
s7.Parse(args, ref list);
|
||||
if (pk is IRibbonSetCommon8 s8)
|
||||
{
|
||||
bool inhabited8 = gen <= 8;
|
||||
var iterate = inhabited8 ? GetInvalidRibbons8Any(pk, s8, enc, evos) : GetInvalidRibbonsNone(s8.RibbonBits(), s8.RibbonNames());
|
||||
foreach (var z in iterate)
|
||||
yield return z;
|
||||
}
|
||||
s8.Parse(args, ref list);
|
||||
}
|
||||
|
||||
private static bool GetIsAlolaChampValid(IRibbonSetCommon7 s7, IEncounterTemplate enc, bool inhabited7)
|
||||
private static void ParseEgg(RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
// If the encounter comes with the ribbon, it must have the ribbon.
|
||||
if (enc is IRibbonSetCommon7 { RibbonChampionAlola: true })
|
||||
return s7.RibbonChampionAlola;
|
||||
// If it has visited, it can be either state.
|
||||
if (inhabited7)
|
||||
return true;
|
||||
// If it has not visited, it must not have it.
|
||||
return !s7.RibbonChampionAlola;
|
||||
var pk = args.Entity;
|
||||
if (pk is IRibbonSetOnly3 o3)
|
||||
o3.ParseEgg(ref list);
|
||||
if (pk is IRibbonSetEvent3 e3)
|
||||
e3.ParseEgg(ref list);
|
||||
if (pk is IRibbonSetEvent4 e4)
|
||||
e4.ParseEgg(args, ref list); // Some event eggs can have ribbons!
|
||||
if (pk is IRibbonSetUnique3 u3)
|
||||
u3.ParseEgg(ref list);
|
||||
if (pk is IRibbonSetCommon3 s3)
|
||||
s3.ParseEgg(ref list);
|
||||
if (pk is IRibbonSetUnique4 u4)
|
||||
u4.ParseEgg(ref list);
|
||||
if (pk is IRibbonSetCommon4 s4)
|
||||
s4.ParseEgg(ref list);
|
||||
if (pk is IRibbonSetCommon6 s6)
|
||||
s6.ParseEgg(ref list);
|
||||
if (pk is IRibbonSetCommon7 s7)
|
||||
s7.ParseEgg(ref list);
|
||||
if (pk is IRibbonSetCommon8 s8)
|
||||
s8.ParseEgg(ref list);
|
||||
}
|
||||
|
||||
private static bool IsRibbonValidEffort(PKM pk, EvolutionHistory evos, int gen) => gen switch
|
||||
{
|
||||
5 when pk.Format == 5 => false,
|
||||
8 when !evos.HasVisitedSWSH && !evos.HasVisitedBDSP => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
private static bool IsRibbonValidBestFriend(PKM pk, EvolutionHistory evos, int gen) => gen switch
|
||||
{
|
||||
< 7 when pk is { IsUntraded: true } and IAffection { OT_Affection: < 255 } => false, // Gen6/7 uses affection. Can't lower it on OT!
|
||||
8 when !evos.HasVisitedSWSH && !evos.HasVisitedBDSP => false, // Gen8+ replaced with Max Friendship.
|
||||
_ => true,
|
||||
};
|
||||
|
||||
private static IEnumerable<RibbonResult> GetMissingContestRibbons(IReadOnlyList<bool> bits, IReadOnlyList<string> names)
|
||||
{
|
||||
for (int i = 0; i < bits.Count; i += 4)
|
||||
{
|
||||
bool required = false;
|
||||
for (int j = i + 3; j >= i; j--)
|
||||
{
|
||||
if (bits[j])
|
||||
required = true;
|
||||
else if (required) yield return new RibbonResult(names[j], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbons4Any(PKM pk, EvolutionHistory evos, IRibbonSetCommon4 s4, int gen)
|
||||
{
|
||||
if (s4.RibbonRecord)
|
||||
yield return new RibbonResult(nameof(s4.RibbonRecord)); // Unobtainable
|
||||
if (s4.RibbonFootprint && !CanHaveFootprintRibbon(pk, evos, gen))
|
||||
yield return new RibbonResult(nameof(s4.RibbonFootprint));
|
||||
|
||||
bool visitBDSP = evos.HasVisitedBDSP;
|
||||
bool gen34 = gen is 3 or 4;
|
||||
bool not6 = pk.Format < 6 || gen is > 6 or < 3;
|
||||
bool noDaily = !gen34 && not6 && !visitBDSP;
|
||||
bool noSinnoh = pk is G4PKM { Species: (int)Species.Pichu, Form: 1 }; // Spiky Pichu
|
||||
bool noCosmetic = (!gen34 && (not6 || (pk.XY && pk.IsUntraded)) && !visitBDSP) || noSinnoh;
|
||||
|
||||
if (noSinnoh)
|
||||
{
|
||||
if (s4.RibbonChampionSinnoh)
|
||||
yield return new RibbonResult(nameof(s4.RibbonChampionSinnoh));
|
||||
}
|
||||
|
||||
if (noDaily)
|
||||
{
|
||||
foreach (var z in GetInvalidRibbonsNone(s4.RibbonBitsDaily(), s4.RibbonNamesDaily()))
|
||||
yield return z;
|
||||
}
|
||||
|
||||
if (noCosmetic)
|
||||
{
|
||||
foreach (var z in GetInvalidRibbonsNone(s4.RibbonBitsCosmetic(), s4.RibbonNamesCosmetic()))
|
||||
yield return z;
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbons6Any(PKM pk, IRibbonSetCommon6 s6, int gen, IEncounterTemplate enc)
|
||||
{
|
||||
foreach (var p in GetInvalidRibbons6Memory(pk, s6, gen, enc))
|
||||
yield return p;
|
||||
|
||||
bool untraded = pk.IsUntraded || (enc is EncounterStatic6 {Species:(int)Species.Pikachu, Form: not 0}); // Disallow cosplay pikachu from XY ribbons
|
||||
var iter = untraded ? GetInvalidRibbons6Untraded(pk, s6) : GetInvalidRibbons6Traded(pk, s6);
|
||||
foreach (var p in iter)
|
||||
yield return p;
|
||||
|
||||
var contest = s6.RibbonBitsContest();
|
||||
bool allContest = contest.All(z => z);
|
||||
if ((allContest != s6.RibbonContestStar) && !(untraded && pk.XY)) // if not already checked
|
||||
yield return new RibbonResult(nameof(s6.RibbonContestStar), s6.RibbonContestStar);
|
||||
|
||||
// Each contest victory requires a contest participation; each participation gives 20 OT affection (not current trainer).
|
||||
// Affection is discarded on PK7->PK8 in favor of friendship, which can be lowered.
|
||||
if (pk is IAffection a)
|
||||
{
|
||||
var affect = a.OT_Affection;
|
||||
var contMemory = s6.RibbonNamesContest();
|
||||
int contCount = 0;
|
||||
var present = contMemory.Where((_, i) => contest[i] && affect < 20 * ++contCount);
|
||||
foreach (var rib in present)
|
||||
yield return new RibbonResult(rib);
|
||||
}
|
||||
|
||||
// Gen6 can get the memory on those who did not participate by being in the party with other participants.
|
||||
// This includes those who cannot enter into the Maison; having memory and no ribbon.
|
||||
const int memChatelaine = 30;
|
||||
bool hasChampMemory = enc.Generation == 7 && pk.Format == 7 && pk is ITrainerMemories m && (m.HT_Memory == memChatelaine || m.OT_Memory == memChatelaine);
|
||||
if (!IsAllowedBattleFrontier(pk.Species))
|
||||
{
|
||||
if (hasChampMemory || s6.RibbonBattlerSkillful) // having memory and not ribbon is too rare, just flag here.
|
||||
yield return new RibbonResult(nameof(s6.RibbonBattlerSkillful));
|
||||
if (s6.RibbonBattlerExpert)
|
||||
yield return new RibbonResult(nameof(s6.RibbonBattlerExpert));
|
||||
yield break;
|
||||
}
|
||||
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<RibbonResult> GetInvalidRibbons6AnyG8(IRibbonSetCommon6 s6, EvolutionHistory evos)
|
||||
{
|
||||
if (!evos.HasVisitedBDSP)
|
||||
{
|
||||
var none = GetInvalidRibbonsNone(s6.RibbonBits(), s6.RibbonNamesBool());
|
||||
foreach (var x in none)
|
||||
yield return x;
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (s6.RibbonChampionKalos)
|
||||
yield return new RibbonResult(nameof(s6.RibbonChampionKalos));
|
||||
if (s6.RibbonChampionG6Hoenn)
|
||||
yield return new RibbonResult(nameof(s6.RibbonChampionG6Hoenn));
|
||||
//if (s6.RibbonBestFriends)
|
||||
// yield return new RibbonResult(nameof(s6.RibbonBestFriends));
|
||||
if (s6.RibbonTraining)
|
||||
yield return new RibbonResult(nameof(s6.RibbonTraining));
|
||||
if (s6.RibbonBattlerSkillful)
|
||||
yield return new RibbonResult(nameof(s6.RibbonBattlerSkillful));
|
||||
if (s6.RibbonBattlerExpert)
|
||||
yield return new RibbonResult(nameof(s6.RibbonBattlerExpert));
|
||||
|
||||
if (s6.RibbonCountMemoryContest != 0)
|
||||
yield return new RibbonResult(nameof(s6.RibbonCountMemoryContest));
|
||||
if (s6.RibbonCountMemoryBattle != 0)
|
||||
yield return new RibbonResult(nameof(s6.RibbonCountMemoryBattle));
|
||||
|
||||
// Can get contest ribbons via BD/SP contests.
|
||||
//if (s6.RibbonContestStar)
|
||||
// yield return new RibbonResult(nameof(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));
|
||||
|
||||
var contest = s6.RibbonBitsContest();
|
||||
bool allContest = contest.All(z => z);
|
||||
if (allContest != s6.RibbonContestStar) // if not already checked
|
||||
yield return new RibbonResult(nameof(s6.RibbonContestStar), s6.RibbonContestStar);
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbons6Memory(PKM pk, IRibbonSetCommon6 s6, int gen, IEncounterTemplate enc)
|
||||
{
|
||||
int contest = 0;
|
||||
int battle = 0;
|
||||
switch (gen)
|
||||
{
|
||||
case 3:
|
||||
contest = IsAllowedInContest4(pk.Species, pk.Form) ? 40 : 20;
|
||||
battle = IsAllowedBattleFrontier(pk.Species) ? CanHaveRibbonWinning(pk, enc, 3) ? 8 : 7 : 0;
|
||||
break;
|
||||
case 4:
|
||||
contest = IsAllowedInContest4(pk.Species, pk.Form) ? 20 : 0;
|
||||
battle = IsAllowedBattleFrontier(pk.Species) ? 6 : 0;
|
||||
break;
|
||||
}
|
||||
if (s6.RibbonCountMemoryContest > contest)
|
||||
yield return new RibbonResult(nameof(s6.RibbonCountMemoryContest));
|
||||
if (s6.RibbonCountMemoryBattle > battle)
|
||||
yield return new RibbonResult(nameof(s6.RibbonCountMemoryBattle));
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbons6Untraded(PKM pk, IRibbonSetCommon6 s6)
|
||||
{
|
||||
if (pk.XY)
|
||||
{
|
||||
if (s6.RibbonChampionG6Hoenn)
|
||||
yield return new RibbonResult(nameof(s6.RibbonChampionG6Hoenn));
|
||||
|
||||
if (s6.RibbonContestStar)
|
||||
yield return new RibbonResult(nameof(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));
|
||||
}
|
||||
else if (pk.AO)
|
||||
{
|
||||
if (s6.RibbonChampionKalos)
|
||||
yield return new RibbonResult(nameof(s6.RibbonChampionKalos));
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbons6Traded(PKM pk, IRibbonSetCommon6 s6)
|
||||
{
|
||||
// Medal count is wiped on transfer to pk8
|
||||
if (s6.RibbonTraining && pk.Format <= 7)
|
||||
{
|
||||
const int req = 12; // only first 12
|
||||
int count = ((ISuperTrain)pk).SuperTrainingMedalCount(req);
|
||||
if (count < req)
|
||||
yield return new RibbonResult(nameof(s6.RibbonTraining));
|
||||
}
|
||||
|
||||
const int memChampion = 27;
|
||||
bool hasChampMemory = pk is ITrainerMemories m && ((pk.Format < 8 && m.HT_Memory == memChampion) || (pk.Gen6 && m.OT_Memory == memChampion));
|
||||
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<RibbonResult> GetInvalidRibbons8Any(PKM pk, IRibbonSetCommon8 s8, IEncounterTemplate enc, EvolutionHistory evos)
|
||||
{
|
||||
if (!CanObtainTowerMaster(evos) && s8.RibbonTowerMaster)
|
||||
{
|
||||
yield return new RibbonResult(nameof(s8.RibbonTowerMaster));
|
||||
}
|
||||
if (!evos.HasVisitedSWSH)
|
||||
{
|
||||
if (s8.RibbonChampionGalar)
|
||||
yield return new RibbonResult(nameof(s8.RibbonChampionGalar));
|
||||
if (s8.RibbonMasterRank)
|
||||
yield return new RibbonResult(nameof(s8.RibbonMasterRank));
|
||||
}
|
||||
else
|
||||
{
|
||||
const int memChampion = 27;
|
||||
{
|
||||
bool hasChampMemory = (pk.Format == 8 && pk is IMemoryHT {HT_Memory: memChampion}) ||
|
||||
(enc.Generation == 8 && pk is IMemoryOT {OT_Memory: memChampion});
|
||||
if (hasChampMemory && !s8.RibbonChampionGalar)
|
||||
yield return new RibbonResult(nameof(s8.RibbonChampionGalar));
|
||||
}
|
||||
|
||||
// Legends cannot compete in Ranked, thus cannot reach Master Rank and obtain the ribbon.
|
||||
// Past gen Pokemon can get the ribbon only if they've been reset.
|
||||
if (s8.RibbonMasterRank && !CanParticipateInRankedSWSH(pk, enc, evos))
|
||||
yield return new RibbonResult(nameof(s8.RibbonMasterRank));
|
||||
|
||||
if (!s8.RibbonTowerMaster)
|
||||
{
|
||||
// If the Tower Master ribbon is not present but a memory hint implies it should...
|
||||
// This memory can also be applied in Gen6/7 via defeating the Chatelaines, where legends are disallowed.
|
||||
const int strongest = 30;
|
||||
if (pk is IMemoryOT {OT_Memory: strongest} or IMemoryHT {HT_Memory: strongest})
|
||||
{
|
||||
if (enc.Generation == 8 || !IsAllowedBattleFrontier(pk.Species) || pk is IRibbonSetCommon6 {RibbonBattlerSkillful: false})
|
||||
yield return new RibbonResult(nameof(s8.RibbonTowerMaster));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s8.RibbonTwinklingStar && (!evos.HasVisitedBDSP || pk is IRibbonSetCommon6 {RibbonContestStar:false}))
|
||||
{
|
||||
yield return new RibbonResult(nameof(s8.RibbonTwinklingStar));
|
||||
}
|
||||
|
||||
// received when capturing photos with Pokémon in the Photography Studio
|
||||
if (!evos.HasVisitedPLA && s8.RibbonPioneer)
|
||||
{
|
||||
yield return new RibbonResult(nameof(s8.RibbonPioneer));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CanObtainTowerMaster(EvolutionHistory evos)
|
||||
{
|
||||
if (evos.HasVisitedSWSH)
|
||||
return true; // Anything in SW/SH can be used in battle tower.
|
||||
|
||||
if (!evos.HasVisitedBDSP)
|
||||
return false;
|
||||
// Mythicals cannot be used in BD/SP's Battle Tower
|
||||
return !Legal.Mythicals.Contains(evos.Gen8b[0].Species);
|
||||
}
|
||||
|
||||
private static bool CanParticipateInRankedSWSH(PKM pk, IEncounterTemplate enc, EvolutionHistory evos)
|
||||
{
|
||||
bool exist = enc.Generation switch
|
||||
{
|
||||
< 8 => pk is IBattleVersion { BattleVersion: (int)GameVersion.SW or (int)GameVersion.SH },
|
||||
_ => evos.HasVisitedSWSH,
|
||||
};
|
||||
if (!exist)
|
||||
return false;
|
||||
|
||||
// Clamp to permitted species
|
||||
var species = pk.Species;
|
||||
if (species > Legal.MaxSpeciesID_8_R2)
|
||||
return false;
|
||||
|
||||
// Series 13 rule-set was the first time Ranked Battles allowed the use of Mythical Pokémon.
|
||||
if (Legal.Legends.Contains(species))
|
||||
{
|
||||
if (enc.Version == GameVersion.GO || enc is IEncounterServerDate { IsDateRestricted: true }) // Capture date is global time, and not console changeable.
|
||||
{
|
||||
if (pk.MetDate > new DateTime(2022, 11, 1)) // Series 13 end date
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return PersonalTable.SWSH.IsPresentInGame(species, pk.Form);
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbonsEvent1(PKM pk, IEncounterTemplate enc)
|
||||
{
|
||||
if (pk is not IRibbonSetEvent3 set1)
|
||||
yield break;
|
||||
var names = set1.RibbonNames();
|
||||
var sb = set1.RibbonBits();
|
||||
var eb = enc is IRibbonSetEvent3 e3 ? e3.RibbonBits() : new bool[sb.Length];
|
||||
|
||||
if (enc.Generation == 3)
|
||||
{
|
||||
eb[0] = sb[0]; // permit Earth Ribbon
|
||||
if (pk.Version == 15 && enc is EncounterStaticShadow s)
|
||||
{
|
||||
// only require national ribbon if no longer on origin game
|
||||
bool untraded = s.Version == GameVersion.XD
|
||||
? pk is XK3 {RibbonNational: false}
|
||||
: pk is CK3 {RibbonNational: false};
|
||||
eb[1] = !untraded;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < sb.Length; i++)
|
||||
{
|
||||
if (sb[i] != eb[i])
|
||||
yield return new RibbonResult(names[i], !eb[i]); // only flag if invalid
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbonsEvent2(PKM pk, IEncounterTemplate enc)
|
||||
{
|
||||
if (pk is not IRibbonSetEvent4 set2)
|
||||
yield break;
|
||||
var names = set2.RibbonNames();
|
||||
var sb = set2.RibbonBits();
|
||||
var eb = enc is IRibbonSetEvent4 e4 ? e4.RibbonBits() : new bool[sb.Length];
|
||||
|
||||
if (enc is EncounterStatic7 {Species: (int)Species.Magearna})
|
||||
eb[1] = true; // require Wishing Ribbon
|
||||
|
||||
for (int i = 0; i < sb.Length; i++)
|
||||
{
|
||||
if (sb[i] != eb[i])
|
||||
yield return new RibbonResult(names[i], !eb[i]); // only flag if invalid
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbonsNone(IReadOnlyList<bool> bits, IReadOnlyList<string> names)
|
||||
{
|
||||
for (int i = 0; i < bits.Count; i++)
|
||||
{
|
||||
if (bits[i])
|
||||
yield return new RibbonResult(names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<RibbonResult> GetInvalidRibbonsNoneSkipIndex(IReadOnlyList<bool> bits, IReadOnlyList<string> names, int skipIndex)
|
||||
{
|
||||
for (int i = 0; i < bits.Count; i++)
|
||||
{
|
||||
if (bits[i] && i != skipIndex)
|
||||
yield return new RibbonResult(names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsAllowedInContest4(int species, int form) => species switch
|
||||
{
|
||||
// Disallow Unown and Ditto, and Spiky Pichu (cannot trade)
|
||||
(int)Species.Ditto => false,
|
||||
(int)Species.Unown => false,
|
||||
(int)Species.Pichu when form == 1 => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
private static bool IsAllowedBattleFrontier(int species) => !Legal.BattleFrontierBanlist.Contains(species);
|
||||
|
||||
private static bool IsAllowedBattleFrontier(int species, int form, int gen)
|
||||
{
|
||||
if (gen == 4 && species == (int)Species.Pichu && form == 1) // spiky
|
||||
return false;
|
||||
return IsAllowedBattleFrontier(species);
|
||||
}
|
||||
|
||||
private static bool CanHaveFootprintRibbon(PKM pk, EvolutionHistory evos, int gen)
|
||||
{
|
||||
if (gen <= 4) // Friendship Check unnecessary - can decrease after obtaining ribbon.
|
||||
return true;
|
||||
// Gen5: Can't obtain
|
||||
if (pk.Format < 6)
|
||||
return false;
|
||||
|
||||
// Gen6/7: Increase level by 30 from original level
|
||||
if (gen != 8 && !pk.GG && (pk.CurrentLevel - pk.Met_Level >= 30))
|
||||
return true;
|
||||
|
||||
// Gen8-BDSP: Variable by species Footprint
|
||||
if (evos.HasVisitedBDSP)
|
||||
{
|
||||
if (Array.Exists(evos.Gen8b, z => !HasFootprintBDSP[z.Species]))
|
||||
return true; // no footprint
|
||||
if (pk.CurrentLevel - pk.Met_Level >= 30)
|
||||
return true; // traveled well
|
||||
}
|
||||
|
||||
// Otherwise: Can't obtain
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool CanHaveRibbonWinning(PKM pk, IEncounterTemplate enc, int gen)
|
||||
{
|
||||
if (gen != 3)
|
||||
return false;
|
||||
if (!IsAllowedBattleFrontier(pk.Species))
|
||||
return false;
|
||||
if (pk.Format == 3)
|
||||
return pk.Met_Level <= 50;
|
||||
|
||||
// Most encounter types can be below level 50; only Shadow Dragonite & Tyranitar, and select Gen3 Event Gifts.
|
||||
// These edge cases can't be obtained below level 50, unlike some wild Pokémon which can be encountered at different locations for lower levels.
|
||||
if (enc.LevelMin <= 50)
|
||||
return true;
|
||||
|
||||
return enc is not (EncounterStaticShadow or WC3);
|
||||
}
|
||||
|
||||
private static bool CanHaveRibbonVictory(PKM pk, int gen)
|
||||
{
|
||||
return gen == 3 && IsAllowedBattleFrontier(pk.Species);
|
||||
}
|
||||
|
||||
// Footprint type is not Type 5, requiring 30 levels.
|
||||
private static readonly bool[] HasFootprintBDSP =
|
||||
{
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, false, true, true, false, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, false, false, true, false,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, false, false, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
false, false, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, false, true, true,
|
||||
false, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, false, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, false, true, true, false, false, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, false, true, true, true, true, true, true,
|
||||
true, true, true, false, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, false, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, false, true, false, true,
|
||||
true, true, true, false, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
false, true, true, true, true, true, true, true, true, false,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, false, false, true,
|
||||
true, true, true, false, false, false, false, false, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, false, true, false, false, true, false, false, false,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, false, false, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, true, true, true, true, true, true, true, true,
|
||||
true, true, false, true, true, true, true, true, true, true,
|
||||
true, true, true, true, false, true, false, true, true, true,
|
||||
true, true, true, true, true, true, false, true, true, true,
|
||||
true, true, true, true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Wraps details used for parsing ribbon states.
|
||||
/// </summary>
|
||||
/// <param name="Entity">Entity to parse</param>
|
||||
/// <param name="Encounter">Encounter originated as</param>
|
||||
/// <param name="History">History of visitation</param>
|
||||
/// <remarks>For Generation 1/2 encounters, use the transferred encounter data object.</remarks>
|
||||
public readonly record struct RibbonVerifierArguments(PKM Entity, IEncounterTemplate Encounter, EvolutionHistory History);
|
||||
@@ -0,0 +1,31 @@
|
||||
using static PKHeX.Core.RibbonIndex;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetCommon3"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierCommon3
|
||||
{
|
||||
public static void Parse(this IRibbonSetCommon3 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var evos = args.History;
|
||||
var pk = args.Entity;
|
||||
if (r.RibbonChampionG3 && !evos.HasVisitedGen3)
|
||||
list.Add(ChampionG3);
|
||||
if (r.RibbonArtist && !evos.HasVisitedGen3)
|
||||
list.Add(Artist);
|
||||
if (r.RibbonEffort && !RibbonRules.IsRibbonValidEffort(pk, evos, args.Encounter.Generation))
|
||||
list.Add(Effort);
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetCommon3 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonChampionG3)
|
||||
list.Add(ChampionG3);
|
||||
if (r.RibbonArtist)
|
||||
list.Add(Artist);
|
||||
if (r.RibbonEffort)
|
||||
list.Add(Effort);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using static PKHeX.Core.RibbonIndex;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetCommon4"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierCommon4
|
||||
{
|
||||
public static void Parse(this IRibbonSetCommon4 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var pk = args.Entity;
|
||||
var evos = args.History;
|
||||
if (r.RibbonFootprint && !RibbonRules.IsRibbonValidFootprint(pk, evos))
|
||||
list.Add(Footprint);
|
||||
if (r.RibbonRecord)
|
||||
list.Add(Record); // Unobtainable
|
||||
|
||||
bool gen4 = evos.HasVisitedGen4;
|
||||
bool gen6 = evos.HasVisitedGen6;
|
||||
bool bdsp = evos.HasVisitedBDSP;
|
||||
bool oras6 = gen6 && !(pk.IsUntraded && pk.XY);
|
||||
bool sinnoh4 = gen4 && args.Encounter is not EncounterStatic4 { Species: (int)Species.Pichu, Form: 1 };
|
||||
bool sinnohChamp = sinnoh4 || bdsp; // no gen4 hg/ss
|
||||
bool cosmetic = sinnoh4 || oras6 || bdsp; // no gen4 hg/ss
|
||||
bool daily = gen4 || gen6 || bdsp;
|
||||
|
||||
if (r.RibbonLegend && !gen4)
|
||||
list.Add(Legend);
|
||||
if (r.RibbonChampionSinnoh && !sinnohChamp)
|
||||
list.Add(ChampionSinnoh);
|
||||
if (!daily)
|
||||
FlagDaily(r, ref list);
|
||||
if (!cosmetic)
|
||||
FlagCosmetic(r, ref list);
|
||||
}
|
||||
|
||||
private static void FlagDaily(IRibbonSetCommon4 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonAlert) list.Add(Alert);
|
||||
if (r.RibbonShock) list.Add(Shock);
|
||||
if (r.RibbonDowncast) list.Add(Downcast);
|
||||
if (r.RibbonCareless) list.Add(Careless);
|
||||
if (r.RibbonRelax) list.Add(Relax);
|
||||
if (r.RibbonSnooze) list.Add(Snooze);
|
||||
if (r.RibbonSmile) list.Add(Smile);
|
||||
}
|
||||
|
||||
private static void FlagCosmetic(IRibbonSetCommon4 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonGorgeous) list.Add(Gorgeous);
|
||||
if (r.RibbonRoyal) list.Add(Royal);
|
||||
if (r.RibbonGorgeousRoyal) list.Add(GorgeousRoyal);
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetCommon4 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonFootprint)
|
||||
list.Add(Footprint);
|
||||
if (r.RibbonRecord)
|
||||
list.Add(Record);
|
||||
if (r.RibbonLegend)
|
||||
list.Add(Legend);
|
||||
if (r.RibbonChampionSinnoh)
|
||||
list.Add(ChampionSinnoh);
|
||||
|
||||
FlagDaily(r, ref list);
|
||||
FlagCosmetic(r, ref list);
|
||||
}
|
||||
}
|
||||
190
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifierCommon6.cs
Normal file
190
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifierCommon6.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using static PKHeX.Core.RibbonIndex;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetCommon6"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierCommon6
|
||||
{
|
||||
public static void Parse(this IRibbonSetCommon6 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
GetInvalidRibbons6Memory(r, args, ref list);
|
||||
var pk = args.Entity;
|
||||
var evos = args.History;
|
||||
|
||||
bool gen6 = evos.HasVisitedGen6;
|
||||
bool bdsp = evos.HasVisitedBDSP;
|
||||
bool kalos6 = gen6 && !(pk.IsUntraded && pk.AO) && args.Encounter is not EncounterStatic6 { Species: (int)Species.Pikachu, Form: not 0 };
|
||||
bool oras6 = gen6 && !(pk.IsUntraded && pk.XY);
|
||||
bool contest = oras6 || bdsp;
|
||||
|
||||
bool k = r.RibbonChampionKalos;
|
||||
bool h = r.RibbonChampionG6Hoenn;
|
||||
if (k && !kalos6)
|
||||
list.Add(ChampionKalos);
|
||||
if (h && !oras6)
|
||||
list.Add(ChampionG6Hoenn);
|
||||
if (!k && !h) // no champ ribbon, check memory.
|
||||
CheckChampionMemory(args, ref list);
|
||||
|
||||
if (!contest)
|
||||
{
|
||||
FlagContest(r, ref list);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Winning a contest in Gen6 adds 20 to OT affection. Each ribbon, add 20 to our expected minimum.
|
||||
if (pk is IAffection a) // False in Gen8+
|
||||
FlagContestAffection(r, ref list, a.OT_Affection);
|
||||
|
||||
// Winning all contests grants the Contest Star ribbon.
|
||||
// If we have all ribbons and the star is not present, flag it as missing.
|
||||
// If we have the star and not all are present, flag it as invalid.
|
||||
bool allContest = r.HasAllContestRibbons();
|
||||
if (allContest != r.RibbonContestStar)
|
||||
list.Add(ContestStar, !r.RibbonContestStar);
|
||||
}
|
||||
|
||||
if (r.RibbonBestFriends && !RibbonRules.IsRibbonValidBestFriends(args.Entity, evos, args.Encounter.Generation))
|
||||
list.Add(BestFriends);
|
||||
|
||||
if (!gen6)
|
||||
{
|
||||
if (r.RibbonTraining)
|
||||
list.Add(Training);
|
||||
|
||||
// Maison
|
||||
if (r.RibbonBattlerSkillful)
|
||||
list.Add(BattlerSkillful);
|
||||
if (r.RibbonBattlerExpert)
|
||||
list.Add(BattlerExpert);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r.RibbonTraining && pk is ISuperTrain s && !RibbonRules.IsRibbonValidSuperTraining(s))
|
||||
list.Add(Training);
|
||||
|
||||
// Maison
|
||||
CheckMaisonRibbons(r, args, ref list);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetCommon6 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonChampionKalos)
|
||||
list.Add(ChampionKalos);
|
||||
if (r.RibbonChampionG6Hoenn)
|
||||
list.Add(ChampionG6Hoenn);
|
||||
if (r.RibbonBestFriends)
|
||||
list.Add(BestFriends);
|
||||
if (r.RibbonTraining)
|
||||
list.Add(Training);
|
||||
if (r.RibbonBattlerSkillful)
|
||||
list.Add(BattlerSkillful);
|
||||
if (r.RibbonBattlerExpert)
|
||||
list.Add(BattlerExpert);
|
||||
|
||||
FlagContest(r, ref list);
|
||||
}
|
||||
|
||||
private static void GetInvalidRibbons6Memory(IRibbonSetCommon6 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
(int contest, int battle) = RibbonRules.GetMaxMemoryCounts(args.History, args.Entity, args.Encounter);
|
||||
if (r.RibbonCountMemoryContest > contest)
|
||||
list.Add(CountMemoryContest);
|
||||
if (r.RibbonCountMemoryBattle > battle)
|
||||
list.Add(CountMemoryBattle);
|
||||
}
|
||||
|
||||
private static void FlagContestAffection(IRibbonSetCommon6 r, ref RibbonResultList list, int current)
|
||||
{
|
||||
int expect = 0;
|
||||
if (r.RibbonMasterCoolness && current < (expect += 20))
|
||||
list.Add(MasterCoolness);
|
||||
if (r.RibbonMasterBeauty && current < (expect += 20))
|
||||
list.Add(MasterBeauty);
|
||||
if (r.RibbonMasterCuteness && current < (expect += 20))
|
||||
list.Add(MasterCuteness);
|
||||
if (r.RibbonMasterCleverness && current < (expect += 20))
|
||||
list.Add(MasterCleverness);
|
||||
if (r.RibbonMasterToughness && current < (expect + 20))
|
||||
list.Add(MasterToughness);
|
||||
}
|
||||
|
||||
private static void FlagContest(IRibbonSetCommon6 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonContestStar)
|
||||
list.Add(ContestStar);
|
||||
if (r.RibbonMasterCoolness)
|
||||
list.Add(MasterCoolness);
|
||||
if (r.RibbonMasterBeauty)
|
||||
list.Add(MasterBeauty);
|
||||
if (r.RibbonMasterCuteness)
|
||||
list.Add(MasterCuteness);
|
||||
if (r.RibbonMasterCleverness)
|
||||
list.Add(MasterCleverness);
|
||||
if (r.RibbonMasterToughness)
|
||||
list.Add(MasterToughness);
|
||||
}
|
||||
|
||||
private static void CheckChampionMemory(RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var pk = args.Entity;
|
||||
var enc = args.Encounter;
|
||||
bool hasChampMemory = GetHasGen6ChampMemory(pk, enc);
|
||||
if (!hasChampMemory)
|
||||
return;
|
||||
|
||||
var ribbon = pk.XY ? ChampionKalos : ChampionG6Hoenn;
|
||||
list.Add(ribbon, true);
|
||||
}
|
||||
|
||||
private static void CheckMaisonRibbons(IRibbonSetCommon6 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var pk = args.Entity;
|
||||
var enc = args.Encounter;
|
||||
bool hasChatelaine6Memory = GetHasGen6ChatelaineMemory(pk, enc);
|
||||
|
||||
if (!RibbonRules.IsAllowedBattleFrontier(pk.Species))
|
||||
{
|
||||
if (hasChatelaine6Memory || r.RibbonBattlerSkillful) // having memory and not ribbon is too rare, just flag here.
|
||||
list.Add(BattlerSkillful);
|
||||
if (r.RibbonBattlerExpert)
|
||||
list.Add(BattlerExpert);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!hasChatelaine6Memory)
|
||||
return;
|
||||
|
||||
if (r.RibbonBattlerSkillful || r.RibbonBattlerExpert)
|
||||
return;
|
||||
|
||||
list.Add(BattlerSkillful, true);
|
||||
//list.Add(BattlerExpert, true); // overkill to flag both as required. One is sufficient.
|
||||
}
|
||||
|
||||
private static bool GetHasGen6ChampMemory(PKM pk, IEncounterTemplate enc)
|
||||
{
|
||||
if (pk is not ITrainerMemories m)
|
||||
return false;
|
||||
|
||||
// Gen6 can get the memory with any party member when defeating the champion.
|
||||
const int memChampion = 27;
|
||||
return (enc.Generation == 6 && m.OT_Memory == memChampion)
|
||||
|| (pk.Format < 8 && m.HT_Memory == memChampion);
|
||||
}
|
||||
|
||||
private static bool GetHasGen6ChatelaineMemory(PKM pk, IEncounterTemplate enc)
|
||||
{
|
||||
if (pk is not ITrainerMemories m)
|
||||
return false;
|
||||
|
||||
// Gen6 can get the memory on those who did not participate by being in the party with other participants.
|
||||
// This includes those who cannot enter into the Maison; having memory and no ribbon.
|
||||
const int memChatelaine = 30;
|
||||
return (enc.Generation == 6 && m.OT_Memory == memChatelaine)
|
||||
|| (pk.Format < 8 && m.HT_Memory == memChatelaine);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using static PKHeX.Core.RibbonIndex;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetCommon7"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierCommon7
|
||||
{
|
||||
public static void Parse(this IRibbonSetCommon7 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
bool inhabited7 = args.History.HasVisitedGen7;
|
||||
bool alolaValid = RibbonRules.IsRibbonValidAlolaChamp(r, args.Encounter, inhabited7);
|
||||
if (!alolaValid)
|
||||
list.Add(ChampionAlola);
|
||||
|
||||
var pk = args.Entity;
|
||||
if (inhabited7 && RibbonRules.IsAllowedBattleFrontier(args.History.Gen7[0].Species))
|
||||
return; // Can have all 3 ribbons.
|
||||
|
||||
if (r.RibbonBattleRoyale)
|
||||
list.Add(BattleRoyale);
|
||||
if (r.RibbonBattleTreeGreat && pk.IsUntraded && !pk.USUM)
|
||||
list.Add(BattleTreeGreat);
|
||||
if (r.RibbonBattleTreeMaster)
|
||||
list.Add(BattleTreeMaster);
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetCommon7 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonChampionAlola)
|
||||
list.Add(ChampionAlola);
|
||||
|
||||
if (r.RibbonBattleRoyale)
|
||||
list.Add(BattleRoyale);
|
||||
if (r.RibbonBattleTreeGreat)
|
||||
list.Add(BattleTreeGreat);
|
||||
if (r.RibbonBattleTreeMaster)
|
||||
list.Add(BattleTreeMaster);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using static PKHeX.Core.RibbonIndex;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetCommon8"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierCommon8
|
||||
{
|
||||
public static void Parse(this IRibbonSetCommon8 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var evos = args.History;
|
||||
if (r.RibbonTowerMaster && !RibbonRules.IsRibbonValidTowerMaster(evos))
|
||||
list.Add(TowerMaster);
|
||||
|
||||
var pk = args.Entity;
|
||||
if (!evos.HasVisitedSWSH)
|
||||
{
|
||||
if (r.RibbonChampionGalar)
|
||||
list.Add(ChampionGalar);
|
||||
if (r.RibbonMasterRank)
|
||||
list.Add(MasterRank);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If it can exist in SW/SH, it can have the ribbon.
|
||||
// If it doesn't have the ribbon and has the memory of having it, then flag it.
|
||||
var enc = args.Encounter;
|
||||
if (!r.RibbonChampionGalar)
|
||||
{
|
||||
const int memChampion = 27;
|
||||
bool hasChampMemory = (enc.Generation == 8 && pk is IMemoryOT { OT_Memory: memChampion })
|
||||
|| (pk.Format == 8 && pk is IMemoryHT { HT_Memory: memChampion });
|
||||
if (hasChampMemory)
|
||||
list.Add(ChampionGalar);
|
||||
}
|
||||
|
||||
// Legends cannot compete in Ranked, thus cannot reach Master Rank and obtain the ribbon.
|
||||
// Past gen Pokemon can get the ribbon only if they've been reset.
|
||||
if (r.RibbonMasterRank && !RibbonRules.IsRibbonValidMasterRankSWSH(pk, enc, evos))
|
||||
list.Add(MasterRank);
|
||||
|
||||
if (!r.RibbonTowerMaster)
|
||||
{
|
||||
// If the Tower Master ribbon is not present but a memory hint implies it should...
|
||||
// This memory can also be applied in Gen6/7 via defeating the Chatelaines, where legends are disallowed.
|
||||
const int strongest = 30;
|
||||
if (pk is IMemoryOT { OT_Memory: strongest } or IMemoryHT { HT_Memory: strongest })
|
||||
{
|
||||
if (enc.Generation == 8 || !RibbonRules.IsAllowedBattleFrontier(pk.Species) || pk is IRibbonSetCommon6 { RibbonBattlerSkillful: false })
|
||||
list.Add(TowerMaster, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (r.RibbonTwinklingStar && !RibbonRules.IsRibbonValidTwinklingStar(evos, pk))
|
||||
list.Add(TwinklingStar);
|
||||
|
||||
// received when capturing photos with Pokémon in the Photography Studio
|
||||
if (r.RibbonPioneer && !evos.HasVisitedPLA)
|
||||
list.Add(Pioneer);
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetCommon8 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonChampionGalar)
|
||||
list.Add(ChampionGalar);
|
||||
if (r.RibbonTowerMaster)
|
||||
list.Add(TowerMaster);
|
||||
if (r.RibbonMasterRank)
|
||||
list.Add(MasterRank);
|
||||
if (r.RibbonTwinklingStar)
|
||||
list.Add(TwinklingStar);
|
||||
if (r.RibbonPioneer)
|
||||
list.Add(Pioneer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using static PKHeX.Core.RibbonIndex;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetEvent3"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierEvent3
|
||||
{
|
||||
public static void Parse(this IRibbonSetEvent3 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var enc = args.Encounter;
|
||||
if (enc is IRibbonSetEvent3 e)
|
||||
{
|
||||
// The Earth Ribbon is a ribbon exclusive to Pokémon Colosseum and Pokémon XD: Gale of Darkness
|
||||
// Awarded to all Pokémon on the player's team when they complete the Mt. Battle challenge without switching the team at any point.
|
||||
if (e.RibbonEarth)
|
||||
{
|
||||
if (!r.RibbonEarth)
|
||||
list.Add(Earth);
|
||||
}
|
||||
else if (r.RibbonEarth && enc.Generation != 3)
|
||||
{
|
||||
list.Add(Earth);
|
||||
}
|
||||
|
||||
if (r.RibbonNational != e.RibbonNational)
|
||||
list.Add(National);
|
||||
if (r.RibbonCountry != e.RibbonCountry)
|
||||
list.Add(Country);
|
||||
if (r.RibbonChampionBattle != e.RibbonChampionBattle)
|
||||
list.Add(ChampionBattle);
|
||||
if (r.RibbonChampionRegional != e.RibbonChampionRegional)
|
||||
list.Add(ChampionRegional);
|
||||
if (r.RibbonChampionNational != e.RibbonChampionNational)
|
||||
list.Add(ChampionNational);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The Earth Ribbon is a ribbon exclusive to Pokémon Colosseum and Pokémon XD: Gale of Darkness
|
||||
// Awarded to all Pokémon on the player's team when they complete the Mt. Battle challenge without switching the team at any point.
|
||||
if (r.RibbonEarth && enc.Generation != 3)
|
||||
list.Add(Earth);
|
||||
|
||||
if (r.RibbonNational != RibbonRules.GetValidRibbonStateNational(args.Entity, enc))
|
||||
list.Add(National);
|
||||
if (r.RibbonCountry)
|
||||
list.Add(Country);
|
||||
if (r.RibbonChampionBattle)
|
||||
list.Add(ChampionBattle);
|
||||
if (r.RibbonChampionRegional)
|
||||
list.Add(ChampionRegional);
|
||||
if (r.RibbonChampionNational)
|
||||
list.Add(ChampionNational);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetEvent3 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonEarth)
|
||||
list.Add(Earth);
|
||||
if (r.RibbonNational)
|
||||
list.Add(National);
|
||||
if (r.RibbonCountry)
|
||||
list.Add(Country);
|
||||
if (r.RibbonChampionBattle)
|
||||
list.Add(ChampionBattle);
|
||||
if (r.RibbonChampionRegional)
|
||||
list.Add(ChampionRegional);
|
||||
if (r.RibbonChampionNational)
|
||||
list.Add(ChampionNational);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using static PKHeX.Core.RibbonIndex;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetEvent4"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierEvent4
|
||||
{
|
||||
public static void Parse(this IRibbonSetEvent4 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var enc = args.Encounter;
|
||||
if (r.RibbonClassic && enc is not IRibbonSetEvent4 { RibbonClassic: true })
|
||||
list.Add(Classic);
|
||||
if ((r.RibbonWishing && enc is not IRibbonSetEvent4 { RibbonWishing: true }) || (enc is EncounterStatic7 { Species: (int)Species.Magearna } && !r.RibbonWishing))
|
||||
list.Add(Wishing);
|
||||
if (r.RibbonPremier && enc is not IRibbonSetEvent4 { RibbonPremier: true })
|
||||
list.Add(Premier);
|
||||
if (r.RibbonEvent && enc is not IRibbonSetEvent4 { RibbonEvent: true })
|
||||
list.Add(Event);
|
||||
if (r.RibbonBirthday && enc is not IRibbonSetEvent4 { RibbonBirthday: true })
|
||||
list.Add(Birthday);
|
||||
if (r.RibbonSpecial && enc is not IRibbonSetEvent4 { RibbonSpecial: true })
|
||||
list.Add(Special);
|
||||
if (r.RibbonWorld && enc is not IRibbonSetEvent4 { RibbonWorld: true })
|
||||
list.Add(World);
|
||||
if (r.RibbonChampionWorld && enc is not IRibbonSetEvent4 { RibbonChampionWorld: true })
|
||||
list.Add(ChampionWorld);
|
||||
if (r.RibbonSouvenir && enc is not IRibbonSetEvent4 { RibbonSouvenir: true })
|
||||
list.Add(Souvenir);
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetEvent4 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var enc = args.Encounter;
|
||||
if (r.RibbonClassic && enc is not IRibbonSetEvent4 { RibbonClassic: true })
|
||||
list.Add(Classic);
|
||||
if (r.RibbonWishing && enc is not IRibbonSetEvent4 { RibbonWishing: true })
|
||||
list.Add(Wishing);
|
||||
if (r.RibbonPremier && enc is not IRibbonSetEvent4 { RibbonPremier: true })
|
||||
list.Add(Premier);
|
||||
if (r.RibbonEvent && enc is not IRibbonSetEvent4 { RibbonEvent: true })
|
||||
list.Add(Event);
|
||||
if (r.RibbonBirthday && enc is not IRibbonSetEvent4 { RibbonBirthday: true })
|
||||
list.Add(Birthday);
|
||||
if (r.RibbonSpecial && enc is not IRibbonSetEvent4 { RibbonSpecial: true })
|
||||
list.Add(Special);
|
||||
if (r.RibbonWorld && enc is not IRibbonSetEvent4 { RibbonWorld: true })
|
||||
list.Add(World);
|
||||
if (r.RibbonChampionWorld && enc is not IRibbonSetEvent4 { RibbonChampionWorld: true })
|
||||
list.Add(ChampionWorld);
|
||||
if (r.RibbonSouvenir && enc is not IRibbonSetEvent4 { RibbonSouvenir: true })
|
||||
list.Add(Souvenir);
|
||||
}
|
||||
}
|
||||
49
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifierOnly3.cs
Normal file
49
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifierOnly3.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using static PKHeX.Core.RibbonIndex3;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetOnly3"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierOnly3
|
||||
{
|
||||
public static void Parse(this IRibbonSetOnly3 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonWorld)
|
||||
list.Add(RibbonIndex.World);
|
||||
|
||||
var max = RibbonRules.IsAllowedContest3(args.History) ? 4 : 0;
|
||||
FlagContest(r, ref list, max);
|
||||
}
|
||||
|
||||
private static void FlagContest(IRibbonSetOnly3 r, ref RibbonResultList list, int max = 4)
|
||||
{
|
||||
if (r.RibbonCountG3Cool > max)
|
||||
list.Add(Cool);
|
||||
if (r.RibbonCountG3Beauty > max)
|
||||
list.Add(Beauty);
|
||||
if (r.RibbonCountG3Cute > max)
|
||||
list.Add(Cute);
|
||||
if (r.RibbonCountG3Smart > max)
|
||||
list.Add(Smart);
|
||||
if (r.RibbonCountG3Tough > max)
|
||||
list.Add(Tough);
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetOnly3 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonWorld)
|
||||
list.Add(RibbonIndex.World);
|
||||
|
||||
if (r.RibbonCountG3Cool != 0)
|
||||
list.Add(Cool);
|
||||
if (r.RibbonCountG3Beauty != 0)
|
||||
list.Add(Beauty);
|
||||
if (r.RibbonCountG3Cute != 0)
|
||||
list.Add(Cute);
|
||||
if (r.RibbonCountG3Smart != 0)
|
||||
list.Add(Smart);
|
||||
if (r.RibbonCountG3Tough != 0)
|
||||
list.Add(Tough);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using static PKHeX.Core.RibbonIndex3;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetUnique3"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierUnique3
|
||||
{
|
||||
public static void Parse(this IRibbonSetUnique3 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var evos = args.History;
|
||||
if (evos.HasVisitedGen3)
|
||||
{
|
||||
PKM pk = args.Entity;
|
||||
if (r.RibbonWinning && !RibbonRules.IsRibbonValidWinning(pk, args.Encounter, evos))
|
||||
list.Add(Winning);
|
||||
if (r.RibbonVictory && !RibbonRules.IsRibbonValidVictory(evos))
|
||||
list.Add(Victory);
|
||||
}
|
||||
else // Gen4/5
|
||||
{
|
||||
if (r.RibbonWinning)
|
||||
list.Add(Winning);
|
||||
if (r.RibbonVictory)
|
||||
list.Add(Victory);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetUnique3 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonWinning)
|
||||
list.Add(Winning);
|
||||
if (r.RibbonVictory)
|
||||
list.Add(Victory);
|
||||
}
|
||||
}
|
||||
135
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifierUnique4.cs
Normal file
135
PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifierUnique4.cs
Normal file
@@ -0,0 +1,135 @@
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Parsing logic for <see cref="IRibbonSetUnique4"/>.
|
||||
/// </summary>
|
||||
public static class RibbonVerifierUnique4
|
||||
{
|
||||
public static void Parse(this IRibbonSetUnique4 r, RibbonVerifierArguments args, ref RibbonResultList list)
|
||||
{
|
||||
var evos = args.History;
|
||||
if (!RibbonRules.IsAllowedBattleFrontier4(evos))
|
||||
FlagAnyAbility(r, ref list);
|
||||
|
||||
if (RibbonRules.IsAllowedContest3(evos))
|
||||
AddMissingContest3(r, ref list);
|
||||
else
|
||||
FlagAnyContest3(r, ref list);
|
||||
|
||||
if (RibbonRules.IsAllowedContest4(evos))
|
||||
AddMissingContest4(r, ref list);
|
||||
else
|
||||
FlagAnyContest4(r, ref list);
|
||||
}
|
||||
|
||||
public static void ParseEgg(this IRibbonSetUnique4 r, ref RibbonResultList list)
|
||||
{
|
||||
FlagAnyAbility(r, ref list);
|
||||
FlagAnyContest3(r, ref list);
|
||||
FlagAnyContest4(r, ref list);
|
||||
}
|
||||
|
||||
private static void AddMissingContest3(IRibbonSetUnique4 r, ref RibbonResultList list)
|
||||
{
|
||||
static void CheckSet(bool Master, bool Hyper, bool Super, bool Initial, ref RibbonResultList list, RibbonIndex3 index)
|
||||
{
|
||||
bool top = Master;
|
||||
if (Hyper)
|
||||
top = true;
|
||||
else if (top)
|
||||
list.Add((RibbonIndex3)((byte)index + 2));
|
||||
|
||||
if (Super)
|
||||
top = true;
|
||||
else if (top)
|
||||
list.Add((RibbonIndex3)((byte)index + 1));
|
||||
|
||||
if (top && !Initial)
|
||||
list.Add(index);
|
||||
}
|
||||
CheckSet(r.RibbonG3CoolMaster, r.RibbonG3CoolHyper, r.RibbonG3CoolSuper, r.RibbonG3Cool, ref list, RibbonIndex3.Cool);
|
||||
CheckSet(r.RibbonG3BeautyMaster, r.RibbonG3BeautyHyper, r.RibbonG3BeautySuper, r.RibbonG3Beauty, ref list, RibbonIndex3.Beauty);
|
||||
CheckSet(r.RibbonG3CuteMaster , r.RibbonG3CuteHyper, r.RibbonG3CuteSuper, r.RibbonG3Cute, ref list, RibbonIndex3.Cute);
|
||||
CheckSet(r.RibbonG3SmartMaster, r.RibbonG3SmartHyper, r.RibbonG3SmartSuper, r.RibbonG3Smart, ref list, RibbonIndex3.Smart);
|
||||
CheckSet(r.RibbonG3ToughMaster, r.RibbonG3ToughHyper, r.RibbonG3ToughSuper, r.RibbonG3Tough, ref list, RibbonIndex3.Tough);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
bool top = Master;
|
||||
if (Hyper)
|
||||
top = true;
|
||||
else if (top)
|
||||
list.Add((RibbonIndex4)((byte)index + 2));
|
||||
|
||||
if (Super)
|
||||
top = true;
|
||||
else if (top)
|
||||
list.Add((RibbonIndex4)((byte)index + 1));
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private static void FlagAnyAbility(IRibbonSetUnique4 r, ref RibbonResultList list)
|
||||
{
|
||||
if (r.RibbonAbility)
|
||||
list.Add(RibbonIndex4.Ability);
|
||||
if (r.RibbonAbilityGreat)
|
||||
list.Add(RibbonIndex4.AbilityGreat);
|
||||
if (r.RibbonAbilityDouble)
|
||||
list.Add(RibbonIndex4.AbilityDouble);
|
||||
if (r.RibbonAbilityMulti)
|
||||
list.Add(RibbonIndex4.AbilityMulti);
|
||||
if (r.RibbonAbilityPair)
|
||||
list.Add(RibbonIndex4.AbilityPair);
|
||||
}
|
||||
|
||||
private static void FlagAnyContest3(IRibbonSetUnique4 r, ref RibbonResultList list)
|
||||
{
|
||||
static void CheckSet(bool Master, bool Hyper, bool Super, bool Initial, ref RibbonResultList list, RibbonIndex3 index)
|
||||
{
|
||||
if (Master)
|
||||
list.Add((RibbonIndex3)((byte)index + 3));
|
||||
if (Hyper)
|
||||
list.Add((RibbonIndex3)((byte)index + 2));
|
||||
if (Super)
|
||||
list.Add((RibbonIndex3)((byte)index + 1));
|
||||
if (Initial)
|
||||
list.Add(index);
|
||||
}
|
||||
CheckSet(r.RibbonG3CoolMaster, r.RibbonG3CoolHyper, r.RibbonG3CoolSuper, r.RibbonG3Cool, ref list, RibbonIndex3.Cool);
|
||||
CheckSet(r.RibbonG3BeautyMaster, r.RibbonG3BeautyHyper, r.RibbonG3BeautySuper, r.RibbonG3Beauty, ref list, RibbonIndex3.Beauty);
|
||||
CheckSet(r.RibbonG3CuteMaster , r.RibbonG3CuteHyper, r.RibbonG3CuteSuper, r.RibbonG3Cute, ref list, RibbonIndex3.Cute);
|
||||
CheckSet(r.RibbonG3SmartMaster, r.RibbonG3SmartHyper, r.RibbonG3SmartSuper, r.RibbonG3Smart, ref list, RibbonIndex3.Smart);
|
||||
CheckSet(r.RibbonG3ToughMaster, r.RibbonG3ToughHyper, r.RibbonG3ToughSuper, r.RibbonG3Tough, ref list, RibbonIndex3.Tough);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (Master)
|
||||
list.Add((RibbonIndex4)((byte)index + 3));
|
||||
if (Hyper)
|
||||
list.Add((RibbonIndex4)((byte)index + 2));
|
||||
if (Super)
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -347,8 +347,8 @@ LPokerusDaysTooHigh_0 = Pokérus Days Remaining value is too high; expected <= {
|
||||
LPokerusStrainUnobtainable_0 = Pokérus Strain {0} cannot be obtained.
|
||||
LRibbonAllValid = All ribbons accounted for.
|
||||
LRibbonEgg = Can't receive Ribbon(s) as an Egg.
|
||||
LRibbonFInvalid_0 = Invalid Ribbons: {0}
|
||||
LRibbonFMissing_0 = Missing Ribbons: {0}
|
||||
LRibbonFInvalid_0 = Invalid Ribbons:
|
||||
LRibbonFMissing_0 = Missing Ribbons:
|
||||
LRibbonMarkingAffixedF_0 = Invalid Affixed Ribbon/Marking: {0}
|
||||
LRibbonMarkingFInvalid_0 = Invalid Marking: {0}
|
||||
LStatAlphaInvalid = Alpha Flag mismatch.
|
||||
|
||||
@@ -347,8 +347,8 @@ LPokerusDaysTooHigh_0 = Pokérus Days Remaining value is too high; expected <= {
|
||||
LPokerusStrainUnobtainable_0 = Pokérus Strain {0} cannot be obtained.
|
||||
LRibbonAllValid = All ribbons accounted for.
|
||||
LRibbonEgg = Can't receive Ribbon(s) as an Egg.
|
||||
LRibbonFInvalid_0 = Invalid Ribbons: {0}
|
||||
LRibbonFMissing_0 = Missing Ribbons: {0}
|
||||
LRibbonFInvalid_0 = Invalid Ribbons:
|
||||
LRibbonFMissing_0 = Missing Ribbons:
|
||||
LRibbonMarkingAffixedF_0 = Invalid Affixed Ribbon/Marking: {0}
|
||||
LRibbonMarkingFInvalid_0 = Invalid Marking: {0}
|
||||
LStatAlphaInvalid = Alpha Flag mismatch.
|
||||
|
||||
@@ -347,8 +347,8 @@ LPokerusDaysTooHigh_0 = Pokérus Days Remaining value is too high; expected <= {
|
||||
LPokerusStrainUnobtainable_0 = Pokérus Strain {0} cannot be obtained.
|
||||
LRibbonAllValid = Todas las cintas están justificadas.
|
||||
LRibbonEgg = No se pueden recibir Cintas siendo un Huevo.
|
||||
LRibbonFInvalid_0 = Cintas inválidas: {0}
|
||||
LRibbonFMissing_0 = Cintas que faltan: {0}
|
||||
LRibbonFInvalid_0 = Cintas inválidas:
|
||||
LRibbonFMissing_0 = Cintas que faltan:
|
||||
LRibbonMarkingAffixedF_0 = Cinta / marca pegada no válida: {0}
|
||||
LRibbonMarkingFInvalid_0 = Marca Inválida: {0}
|
||||
LStatAlphaInvalid = Alpha Flag mismatch.
|
||||
|
||||
@@ -347,8 +347,8 @@ LPokerusDaysTooHigh_0 = Pokérus Days Remaining value is too high; expected <= {
|
||||
LPokerusStrainUnobtainable_0 = Pokérus Strain {0} cannot be obtained.
|
||||
LRibbonAllValid = Tous les rubans ont été comptabilisés.
|
||||
LRibbonEgg = L'Œuf ne peut pas recevoir de Rubans.
|
||||
LRibbonFInvalid_0 = Rubans invalides : {0}
|
||||
LRibbonFMissing_0 = Rubans manquants : {0}
|
||||
LRibbonFInvalid_0 = Rubans invalides :
|
||||
LRibbonFMissing_0 = Rubans manquants :
|
||||
LRibbonMarkingAffixedF_0 = Ruban / marquage apposé non valide: {0}
|
||||
LRibbonMarkingFInvalid_0 = Marquage non valide: {0}
|
||||
LStatAlphaInvalid = Alpha Flag mismatch.
|
||||
|
||||
@@ -347,8 +347,8 @@ LPokerusDaysTooHigh_0 = I giorni di Pokérus rimanenti sono troppi, previsto <=
|
||||
LPokerusStrainUnobtainable_0 = Pokérus Strain {0} non può essere ottenuta.
|
||||
LRibbonAllValid = Tutti i fiocchi sono stati contabilizzati.
|
||||
LRibbonEgg = Non può avere fiocchi da Uovo.
|
||||
LRibbonFInvalid_0 = Fiocchi invalidi: {0}
|
||||
LRibbonFMissing_0 = Fiocchi mancanti: {0}
|
||||
LRibbonFInvalid_0 = Fiocchi invalidi:
|
||||
LRibbonFMissing_0 = Fiocchi mancanti:
|
||||
LRibbonMarkingAffixedF_0 = Fioccho o Emblema fissato invalido: {0}
|
||||
LRibbonMarkingFInvalid_0 = Emblema invalido: {0}
|
||||
LStatAlphaInvalid = Alfa non corrispondente.
|
||||
|
||||
@@ -347,8 +347,8 @@ LPokerusDaysTooHigh_0 = Pokérus Days Remaining value is too high; expected <= {
|
||||
LPokerusStrainUnobtainable_0 = Pokérus Strain {0} cannot be obtained.
|
||||
LRibbonAllValid = All ribbons accounted for.
|
||||
LRibbonEgg = タマゴにリボンは設定できません
|
||||
LRibbonFInvalid_0 = 無効なリボンが設定されています: {0}
|
||||
LRibbonFMissing_0 = 次のリボンが不足しています: {0}
|
||||
LRibbonFInvalid_0 = 無効なリボンが設定されています:
|
||||
LRibbonFMissing_0 = 次のリボンが不足しています:
|
||||
LRibbonMarkingAffixedF_0 = Invalid Affixed Ribbon/Marking: {0}
|
||||
LRibbonMarkingFInvalid_0 = Invalid Marking: {0}
|
||||
LStatAlphaInvalid = Alpha Flag mismatch.
|
||||
|
||||
@@ -347,8 +347,8 @@ LPokerusDaysTooHigh_0 = Pokérus Days Remaining value is too high; expected <= {
|
||||
LPokerusStrainUnobtainable_0 = Pokérus Strain {0} cannot be obtained.
|
||||
LRibbonAllValid = 모든 리본이 채워졌습니다.
|
||||
LRibbonEgg = 알은 리본을 얻을 수 없습니다.
|
||||
LRibbonFInvalid_0 = 사용할 수 없는 리본: {0}
|
||||
LRibbonFMissing_0 = 없는 리본: {0}
|
||||
LRibbonFInvalid_0 = 사용할 수 없는 리본:
|
||||
LRibbonFMissing_0 = 없는 리본:
|
||||
LRibbonMarkingAffixedF_0 = Invalid Affixed Ribbon/Marking: {0}
|
||||
LRibbonMarkingFInvalid_0 = Invalid Marking: {0}
|
||||
LStatAlphaInvalid = Alpha Flag mismatch.
|
||||
|
||||
@@ -347,8 +347,8 @@ LPokerusDaysTooHigh_0 = Pokérus Days Remaining value is too high; expected <= {
|
||||
LPokerusStrainUnobtainable_0 = Pokérus Strain {0} cannot be obtained.
|
||||
LRibbonAllValid = 所有奖章合法。
|
||||
LRibbonEgg = 蛋不能接受奖章。
|
||||
LRibbonFInvalid_0 = 不合法奖章: {0}
|
||||
LRibbonFMissing_0 = 缺失奖章: {0}
|
||||
LRibbonFInvalid_0 = 不合法奖章:
|
||||
LRibbonFMissing_0 = 缺失奖章:
|
||||
LRibbonMarkingAffixedF_0 = 无效的奖章/证章: {0}
|
||||
LRibbonMarkingFInvalid_0 = 无效标记: {0}
|
||||
LStatAlphaInvalid = Alpha Flag mismatch.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Common Ribbons introduced in Generation 3 </summary>
|
||||
public interface IRibbonSetCommon3
|
||||
@@ -10,23 +10,6 @@ public interface IRibbonSetCommon3
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesCommon3 =
|
||||
{
|
||||
nameof(IRibbonSetCommon3.RibbonChampionG3), nameof(IRibbonSetCommon3.RibbonArtist), nameof(IRibbonSetCommon3.RibbonEffort),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBits(this IRibbonSetCommon3 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonChampionG3,
|
||||
set.RibbonArtist,
|
||||
set.RibbonEffort,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNames(this IRibbonSetCommon3 _) => RibbonSetNamesCommon3;
|
||||
|
||||
internal static void CopyRibbonSetCommon3(this IRibbonSetCommon3 set, IRibbonSetCommon3 dest)
|
||||
{
|
||||
dest.RibbonChampionG3 = set.RibbonChampionG3;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Common Ribbons introduced in Generation 4 </summary>
|
||||
public interface IRibbonSetCommon4
|
||||
@@ -21,63 +21,6 @@ public interface IRibbonSetCommon4
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesCommon4 =
|
||||
{
|
||||
nameof(IRibbonSetCommon4.RibbonGorgeous), nameof(IRibbonSetCommon4.RibbonRoyal), nameof(IRibbonSetCommon4.RibbonGorgeousRoyal),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBitsCosmetic(this IRibbonSetCommon4 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonGorgeous,
|
||||
set.RibbonRoyal,
|
||||
set.RibbonGorgeousRoyal,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNamesCosmetic(this IRibbonSetCommon4 _) => RibbonSetNamesCommon4;
|
||||
|
||||
private static readonly string[] RibbonSetNamesCommon4Only =
|
||||
{
|
||||
nameof(IRibbonSetCommon4.RibbonRecord), nameof(IRibbonSetCommon4.RibbonChampionSinnoh), nameof(IRibbonSetCommon4.RibbonLegend),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBitsOnly(this IRibbonSetCommon4 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonRecord,
|
||||
set.RibbonChampionSinnoh,
|
||||
set.RibbonLegend,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNamesOnly(this IRibbonSetCommon4 _) => 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)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonAlert,
|
||||
set.RibbonShock,
|
||||
set.RibbonDowncast,
|
||||
set.RibbonCareless,
|
||||
set.RibbonRelax,
|
||||
set.RibbonSnooze,
|
||||
set.RibbonSmile,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNamesDaily(this IRibbonSetCommon4 _) => RibbonSetNamesCommon4Daily;
|
||||
|
||||
internal static void CopyRibbonSetCommon4(this IRibbonSetCommon4 set, IRibbonSetCommon4 dest)
|
||||
{
|
||||
dest.RibbonChampionSinnoh = set.RibbonChampionSinnoh;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Common Ribbons introduced in Generation 6 </summary>
|
||||
public interface IRibbonSetCommon6
|
||||
@@ -23,55 +23,10 @@ public interface IRibbonSetCommon6
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesCommon6Bool =
|
||||
{
|
||||
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),
|
||||
};
|
||||
|
||||
private static readonly string[] RibbonSetNamesCommon6Contest =
|
||||
{
|
||||
nameof(IRibbonSetCommon6.RibbonMasterCoolness), nameof(IRibbonSetCommon6.RibbonMasterBeauty),
|
||||
nameof(IRibbonSetCommon6.RibbonMasterCuteness), nameof(IRibbonSetCommon6.RibbonMasterCleverness),
|
||||
nameof(IRibbonSetCommon6.RibbonMasterToughness),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBits(this IRibbonSetCommon6 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonChampionKalos,
|
||||
set.RibbonChampionG6Hoenn,
|
||||
//set.RibbonBestFriends,
|
||||
set.RibbonTraining,
|
||||
set.RibbonBattlerSkillful,
|
||||
set.RibbonBattlerExpert,
|
||||
|
||||
set.RibbonContestStar,
|
||||
set.RibbonMasterCoolness,
|
||||
set.RibbonMasterBeauty,
|
||||
set.RibbonMasterCuteness,
|
||||
set.RibbonMasterCleverness,
|
||||
set.RibbonMasterToughness,
|
||||
};
|
||||
}
|
||||
|
||||
internal static bool[] RibbonBitsContest(this IRibbonSetCommon6 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonMasterCoolness,
|
||||
set.RibbonMasterBeauty,
|
||||
set.RibbonMasterCuteness,
|
||||
set.RibbonMasterCleverness,
|
||||
set.RibbonMasterToughness,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNamesBool(this IRibbonSetCommon6 _) => RibbonSetNamesCommon6Bool;
|
||||
internal static string[] RibbonNamesContest(this IRibbonSetCommon6 _) => RibbonSetNamesCommon6Contest;
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="set"/> has all five contest stat ribbons true.
|
||||
/// </summary>
|
||||
public static bool HasAllContestRibbons(this IRibbonSetCommon6 set) => set.RibbonMasterCoolness && set.RibbonMasterBeauty && set.RibbonMasterCuteness && set.RibbonMasterCleverness && set.RibbonMasterToughness;
|
||||
|
||||
internal static void CopyRibbonSetCommon6(this IRibbonSetCommon6 set, IRibbonSetCommon6 dest)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Common Ribbons introduced in Generation 7 </summary>
|
||||
public interface IRibbonSetCommon7
|
||||
@@ -11,25 +11,6 @@ public interface IRibbonSetCommon7
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesCommon7 =
|
||||
{
|
||||
nameof(IRibbonSetCommon7.RibbonChampionAlola), nameof(IRibbonSetCommon7.RibbonBattleRoyale),
|
||||
nameof(IRibbonSetCommon7.RibbonBattleTreeGreat), nameof(IRibbonSetCommon7.RibbonBattleTreeMaster),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBits(this IRibbonSetCommon7 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonChampionAlola,
|
||||
set.RibbonBattleRoyale,
|
||||
set.RibbonBattleTreeGreat,
|
||||
set.RibbonBattleTreeMaster,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNames(this IRibbonSetCommon7 _) => RibbonSetNamesCommon7;
|
||||
|
||||
internal static void CopyRibbonSetCommon7(this IRibbonSetCommon7 set, IRibbonSetCommon7 dest)
|
||||
{
|
||||
dest.RibbonChampionAlola = set.RibbonChampionAlola;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Common Ribbons introduced in Generation 8 </summary>
|
||||
public interface IRibbonSetCommon8
|
||||
@@ -12,27 +12,6 @@ public interface IRibbonSetCommon8
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesCommon8 =
|
||||
{
|
||||
nameof(IRibbonSetCommon8.RibbonChampionGalar), nameof(IRibbonSetCommon8.RibbonTowerMaster),
|
||||
nameof(IRibbonSetCommon8.RibbonMasterRank),
|
||||
nameof(IRibbonSetCommon8.RibbonTwinklingStar), nameof(IRibbonSetCommon8.RibbonPioneer),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBits(this IRibbonSetCommon8 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonChampionGalar,
|
||||
set.RibbonTowerMaster,
|
||||
set.RibbonMasterRank,
|
||||
set.RibbonTwinklingStar,
|
||||
set.RibbonPioneer,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNames(this IRibbonSetCommon8 _) => RibbonSetNamesCommon8;
|
||||
|
||||
internal static void CopyRibbonSetCommon8(this IRibbonSetCommon8 set, IRibbonSetCommon8 dest)
|
||||
{
|
||||
dest.RibbonChampionGalar = set.RibbonChampionGalar;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Ribbons introduced in Generation 3 for Special Events </summary>
|
||||
public interface IRibbonSetEvent3
|
||||
@@ -13,27 +13,6 @@ public interface IRibbonSetEvent3
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesEvent3 =
|
||||
{
|
||||
nameof(IRibbonSetEvent3.RibbonEarth), nameof(IRibbonSetEvent3.RibbonNational), nameof(IRibbonSetEvent3.RibbonCountry),
|
||||
nameof(IRibbonSetEvent3.RibbonChampionBattle), nameof(IRibbonSetEvent3.RibbonChampionRegional), nameof(IRibbonSetEvent3.RibbonChampionNational),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBits(this IRibbonSetEvent3 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonEarth,
|
||||
set.RibbonNational,
|
||||
set.RibbonCountry,
|
||||
set.RibbonChampionBattle,
|
||||
set.RibbonChampionRegional,
|
||||
set.RibbonChampionNational,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNames(this IRibbonSetEvent3 _) => RibbonSetNamesEvent3;
|
||||
|
||||
internal static void CopyRibbonSetEvent3(this IRibbonSetEvent3 set, IRibbonSetEvent3 dest)
|
||||
{
|
||||
dest.RibbonEarth = set.RibbonEarth;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Ribbons introduced in Generation 4 for Special Events </summary>
|
||||
public interface IRibbonSetEvent4
|
||||
@@ -16,31 +16,6 @@ public interface IRibbonSetEvent4
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesEvent4 =
|
||||
{
|
||||
nameof(IRibbonSetEvent4.RibbonClassic), nameof(IRibbonSetEvent4.RibbonWishing), nameof(IRibbonSetEvent4.RibbonPremier),
|
||||
nameof(IRibbonSetEvent4.RibbonEvent), nameof(IRibbonSetEvent4.RibbonBirthday), nameof(IRibbonSetEvent4.RibbonSpecial),
|
||||
nameof(IRibbonSetEvent4.RibbonWorld), nameof(IRibbonSetEvent4.RibbonChampionWorld), nameof(IRibbonSetEvent4.RibbonSouvenir),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBits(this IRibbonSetEvent4 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonClassic,
|
||||
set.RibbonWishing,
|
||||
set.RibbonPremier,
|
||||
set.RibbonEvent,
|
||||
set.RibbonBirthday,
|
||||
set.RibbonSpecial,
|
||||
set.RibbonWorld,
|
||||
set.RibbonChampionWorld,
|
||||
set.RibbonSouvenir,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNames(this IRibbonSetEvent4 _) => RibbonSetNamesEvent4;
|
||||
|
||||
internal static void CopyRibbonSetEvent4(this IRibbonSetEvent4 set, IRibbonSetEvent4 dest)
|
||||
{
|
||||
dest.RibbonClassic = set.RibbonClassic;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Ribbons that originated in Generation 3 and were only present within that Generation. </summary>
|
||||
public interface IRibbonSetOnly3
|
||||
@@ -15,18 +15,3 @@ public interface IRibbonSetOnly3
|
||||
bool Unused3 { get; set; }
|
||||
bool Unused4 { get; set; }
|
||||
}
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesOnly3 =
|
||||
{
|
||||
nameof(IRibbonSetOnly3.RibbonCountG3Cool), nameof(IRibbonSetOnly3.RibbonCountG3Beauty), nameof(IRibbonSetOnly3.RibbonCountG3Cute),
|
||||
nameof(IRibbonSetOnly3.RibbonCountG3Smart), nameof(IRibbonSetOnly3.RibbonCountG3Tough),
|
||||
|
||||
nameof(IRibbonSetOnly3.RibbonWorld),
|
||||
nameof(IRibbonSetOnly3.Unused1), nameof(IRibbonSetOnly3.Unused2),
|
||||
nameof(IRibbonSetOnly3.Unused3), nameof(IRibbonSetOnly3.Unused4),
|
||||
};
|
||||
|
||||
internal static string[] RibbonNames(this IRibbonSetOnly3 _) => RibbonSetNamesOnly3;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace PKHeX.Core;
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary> Ribbons introduced in Generation 3 and were transferred to future Generations (4 and 5 only). </summary>
|
||||
public interface IRibbonSetUnique3
|
||||
@@ -9,22 +9,3 @@ public interface IRibbonSetUnique3
|
||||
/// <summary> Ribbon awarded for clearing Hoenn's Battle Tower's Lv. 100 challenge. </summary>
|
||||
bool RibbonVictory { get; set; }
|
||||
}
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesUnique3 =
|
||||
{
|
||||
nameof(IRibbonSetUnique3.RibbonWinning), nameof(IRibbonSetUnique3.RibbonVictory),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBits(this IRibbonSetUnique3 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonWinning,
|
||||
set.RibbonVictory,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNames(this IRibbonSetUnique3 _) => RibbonSetNamesUnique3;
|
||||
}
|
||||
|
||||
@@ -52,143 +52,3 @@ public interface IRibbonSetUnique4
|
||||
bool RibbonG4ToughUltra { get; set; }
|
||||
bool RibbonG4ToughMaster { get; set; }
|
||||
}
|
||||
|
||||
internal static partial class RibbonExtensions
|
||||
{
|
||||
private static readonly string[] RibbonSetNamesUnique4Ability =
|
||||
{
|
||||
nameof(IRibbonSetUnique4.RibbonAbility),
|
||||
nameof(IRibbonSetUnique4.RibbonAbilityGreat),
|
||||
nameof(IRibbonSetUnique4.RibbonAbilityDouble),
|
||||
nameof(IRibbonSetUnique4.RibbonAbilityMulti),
|
||||
nameof(IRibbonSetUnique4.RibbonAbilityPair),
|
||||
nameof(IRibbonSetUnique4.RibbonAbilityWorld),
|
||||
};
|
||||
|
||||
private static readonly string[] RibbonSetNamesUnique4Contest3 =
|
||||
{
|
||||
nameof(IRibbonSetUnique4.RibbonG3Cool),
|
||||
nameof(IRibbonSetUnique4.RibbonG3CoolSuper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3CoolHyper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3CoolMaster),
|
||||
nameof(IRibbonSetUnique4.RibbonG3Beauty),
|
||||
nameof(IRibbonSetUnique4.RibbonG3BeautySuper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3BeautyHyper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3BeautyMaster),
|
||||
nameof(IRibbonSetUnique4.RibbonG3Cute),
|
||||
nameof(IRibbonSetUnique4.RibbonG3CuteSuper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3CuteHyper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3CuteMaster),
|
||||
nameof(IRibbonSetUnique4.RibbonG3Smart),
|
||||
nameof(IRibbonSetUnique4.RibbonG3SmartSuper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3SmartHyper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3SmartMaster),
|
||||
nameof(IRibbonSetUnique4.RibbonG3Tough),
|
||||
nameof(IRibbonSetUnique4.RibbonG3ToughSuper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3ToughHyper),
|
||||
nameof(IRibbonSetUnique4.RibbonG3ToughMaster),
|
||||
};
|
||||
|
||||
private static readonly string[] RibbonSetNamesUnique4Contest4 =
|
||||
{
|
||||
nameof(IRibbonSetUnique4.RibbonG4Cool),
|
||||
nameof(IRibbonSetUnique4.RibbonG4CoolGreat),
|
||||
nameof(IRibbonSetUnique4.RibbonG4CoolUltra),
|
||||
nameof(IRibbonSetUnique4.RibbonG4CoolMaster),
|
||||
nameof(IRibbonSetUnique4.RibbonG4Beauty),
|
||||
nameof(IRibbonSetUnique4.RibbonG4BeautyGreat),
|
||||
nameof(IRibbonSetUnique4.RibbonG4BeautyUltra),
|
||||
nameof(IRibbonSetUnique4.RibbonG4BeautyMaster),
|
||||
nameof(IRibbonSetUnique4.RibbonG4Cute),
|
||||
nameof(IRibbonSetUnique4.RibbonG4CuteGreat),
|
||||
nameof(IRibbonSetUnique4.RibbonG4CuteUltra),
|
||||
nameof(IRibbonSetUnique4.RibbonG4CuteMaster),
|
||||
nameof(IRibbonSetUnique4.RibbonG4Smart),
|
||||
nameof(IRibbonSetUnique4.RibbonG4SmartGreat),
|
||||
nameof(IRibbonSetUnique4.RibbonG4SmartUltra),
|
||||
nameof(IRibbonSetUnique4.RibbonG4SmartMaster),
|
||||
nameof(IRibbonSetUnique4.RibbonG4Tough),
|
||||
nameof(IRibbonSetUnique4.RibbonG4ToughGreat),
|
||||
nameof(IRibbonSetUnique4.RibbonG4ToughUltra),
|
||||
nameof(IRibbonSetUnique4.RibbonG4ToughMaster),
|
||||
};
|
||||
|
||||
internal static bool[] RibbonBitsAbility(this IRibbonSetUnique4 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonAbility,
|
||||
set.RibbonAbilityGreat,
|
||||
set.RibbonAbilityDouble,
|
||||
set.RibbonAbilityMulti,
|
||||
set.RibbonAbilityPair,
|
||||
set.RibbonAbilityWorld,
|
||||
};
|
||||
}
|
||||
|
||||
internal static bool[] RibbonBitsContest3(this IRibbonSetUnique4 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonG3Cool,
|
||||
set.RibbonG3CoolSuper,
|
||||
set.RibbonG3CoolHyper,
|
||||
set.RibbonG3CoolMaster,
|
||||
|
||||
set.RibbonG3Beauty,
|
||||
set.RibbonG3BeautySuper,
|
||||
set.RibbonG3BeautyHyper,
|
||||
set.RibbonG3BeautyMaster,
|
||||
|
||||
set.RibbonG3Cute,
|
||||
set.RibbonG3CuteSuper,
|
||||
set.RibbonG3CuteHyper,
|
||||
set.RibbonG3CuteMaster,
|
||||
|
||||
set.RibbonG3Smart,
|
||||
set.RibbonG3SmartSuper,
|
||||
set.RibbonG3SmartHyper,
|
||||
set.RibbonG3SmartMaster,
|
||||
|
||||
set.RibbonG3Tough,
|
||||
set.RibbonG3ToughSuper,
|
||||
set.RibbonG3ToughHyper,
|
||||
set.RibbonG3ToughMaster,
|
||||
};
|
||||
}
|
||||
|
||||
internal static bool[] RibbonBitsContest4(this IRibbonSetUnique4 set)
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
set.RibbonG4Cool,
|
||||
set.RibbonG4CoolGreat,
|
||||
set.RibbonG4CoolUltra,
|
||||
set.RibbonG4CoolMaster,
|
||||
|
||||
set.RibbonG4Beauty,
|
||||
set.RibbonG4BeautyGreat,
|
||||
set.RibbonG4BeautyUltra,
|
||||
set.RibbonG4BeautyMaster,
|
||||
|
||||
set.RibbonG4Cute,
|
||||
set.RibbonG4CuteGreat,
|
||||
set.RibbonG4CuteUltra,
|
||||
set.RibbonG4CuteMaster,
|
||||
|
||||
set.RibbonG4Smart,
|
||||
set.RibbonG4SmartGreat,
|
||||
set.RibbonG4SmartUltra,
|
||||
set.RibbonG4SmartMaster,
|
||||
|
||||
set.RibbonG4Tough,
|
||||
set.RibbonG4ToughGreat,
|
||||
set.RibbonG4ToughUltra,
|
||||
set.RibbonG4ToughMaster,
|
||||
};
|
||||
}
|
||||
|
||||
internal static string[] RibbonNamesAbility(this IRibbonSetUnique4 _) => RibbonSetNamesUnique4Ability;
|
||||
internal static string[] RibbonNamesContest3(this IRibbonSetUnique4 _) => RibbonSetNamesUnique4Contest3;
|
||||
internal static string[] RibbonNamesContest4(this IRibbonSetUnique4 _) => RibbonSetNamesUnique4Contest4;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
namespace PKHeX.Core;
|
||||
using System;
|
||||
using static PKHeX.Core.RibbonIndex;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Ribbon Indexes for Generation 8
|
||||
/// </summary>
|
||||
public enum RibbonIndex
|
||||
public enum RibbonIndex : byte
|
||||
{
|
||||
ChampionKalos,
|
||||
ChampionG3,
|
||||
@@ -115,17 +118,368 @@ public static class RibbonIndexExtensions
|
||||
{
|
||||
public static bool GetRibbonIndex(this IRibbonIndex x, RibbonIndex r) => x.GetRibbon((int)r);
|
||||
public static void SetRibbonIndex(this IRibbonIndex x, RibbonIndex r, bool value = true) => x.SetRibbon((int)r, value);
|
||||
public static bool IsMark(this RibbonIndex r) => r is >= MarkLunchtime and <= MarkSlump;
|
||||
|
||||
public static AreaWeather8 GetWeather8(this RibbonIndex x) => x switch
|
||||
{
|
||||
RibbonIndex.MarkCloudy => AreaWeather8.Overcast,
|
||||
RibbonIndex.MarkRainy => AreaWeather8.Raining,
|
||||
RibbonIndex.MarkStormy => AreaWeather8.Thunderstorm,
|
||||
RibbonIndex.MarkDry => AreaWeather8.Intense_Sun,
|
||||
RibbonIndex.MarkSnowy => AreaWeather8.Snowing,
|
||||
RibbonIndex.MarkBlizzard => AreaWeather8.Snowstorm,
|
||||
RibbonIndex.MarkSandstorm => AreaWeather8.Sandstorm,
|
||||
RibbonIndex.MarkMisty => AreaWeather8.Heavy_Fog,
|
||||
MarkCloudy => AreaWeather8.Overcast,
|
||||
MarkRainy => AreaWeather8.Raining,
|
||||
MarkStormy => AreaWeather8.Thunderstorm,
|
||||
MarkDry => AreaWeather8.Intense_Sun,
|
||||
MarkSnowy => AreaWeather8.Snowing,
|
||||
MarkBlizzard => AreaWeather8.Snowstorm,
|
||||
MarkSandstorm => AreaWeather8.Sandstorm,
|
||||
MarkMisty => AreaWeather8.Heavy_Fog,
|
||||
_ => AreaWeather8.None,
|
||||
};
|
||||
|
||||
private enum RibbonIndexGroup : byte
|
||||
{
|
||||
None,
|
||||
Mark,
|
||||
CountMemory,
|
||||
Common3,
|
||||
Common4,
|
||||
Event3,
|
||||
Event4,
|
||||
Common6,
|
||||
Common7,
|
||||
Common8,
|
||||
}
|
||||
|
||||
private static RibbonIndexGroup GetGroup(this RibbonIndex r)
|
||||
{
|
||||
if (r.IsMark())
|
||||
return RibbonIndexGroup.Mark;
|
||||
return r switch
|
||||
{
|
||||
ChampionG3 => RibbonIndexGroup.Common3,
|
||||
Effort => RibbonIndexGroup.Common3,
|
||||
Artist => RibbonIndexGroup.Common3,
|
||||
|
||||
ChampionSinnoh => RibbonIndexGroup.Common4,
|
||||
Alert => RibbonIndexGroup.Common4,
|
||||
Shock => RibbonIndexGroup.Common4,
|
||||
Downcast => RibbonIndexGroup.Common4,
|
||||
Careless => RibbonIndexGroup.Common4,
|
||||
Relax => RibbonIndexGroup.Common4,
|
||||
Snooze => RibbonIndexGroup.Common4,
|
||||
Smile => RibbonIndexGroup.Common4,
|
||||
Gorgeous => RibbonIndexGroup.Common4,
|
||||
Royal => RibbonIndexGroup.Common4,
|
||||
GorgeousRoyal => RibbonIndexGroup.Common4,
|
||||
Footprint => RibbonIndexGroup.Common4,
|
||||
Record => RibbonIndexGroup.Common4,
|
||||
Legend => RibbonIndexGroup.Common4,
|
||||
|
||||
Country => RibbonIndexGroup.Event3,
|
||||
National => RibbonIndexGroup.Event3,
|
||||
Earth => RibbonIndexGroup.Event3,
|
||||
ChampionBattle => RibbonIndexGroup.Event3,
|
||||
ChampionRegional => RibbonIndexGroup.Event3,
|
||||
ChampionNational => RibbonIndexGroup.Event3,
|
||||
|
||||
World => RibbonIndexGroup.Event4,
|
||||
Classic => RibbonIndexGroup.Event4,
|
||||
Premier => RibbonIndexGroup.Event4,
|
||||
Event => RibbonIndexGroup.Event4,
|
||||
Birthday => RibbonIndexGroup.Event4,
|
||||
Special => RibbonIndexGroup.Event4,
|
||||
Souvenir => RibbonIndexGroup.Event4,
|
||||
Wishing => RibbonIndexGroup.Event4,
|
||||
ChampionWorld => RibbonIndexGroup.Event4,
|
||||
|
||||
ChampionKalos => RibbonIndexGroup.Common6,
|
||||
BestFriends => RibbonIndexGroup.Common6,
|
||||
Training => RibbonIndexGroup.Common6,
|
||||
BattlerSkillful => RibbonIndexGroup.Common6,
|
||||
BattlerExpert => RibbonIndexGroup.Common6,
|
||||
ChampionG6Hoenn => RibbonIndexGroup.Common6,
|
||||
ContestStar => RibbonIndexGroup.Common6,
|
||||
MasterCoolness => RibbonIndexGroup.Common6,
|
||||
MasterBeauty => RibbonIndexGroup.Common6,
|
||||
MasterCuteness => RibbonIndexGroup.Common6,
|
||||
MasterCleverness => RibbonIndexGroup.Common6,
|
||||
MasterToughness => RibbonIndexGroup.Common6,
|
||||
|
||||
CountMemoryContest => RibbonIndexGroup.CountMemory,
|
||||
CountMemoryBattle => RibbonIndexGroup.CountMemory,
|
||||
|
||||
ChampionAlola => RibbonIndexGroup.Common7,
|
||||
BattleRoyale => RibbonIndexGroup.Common7,
|
||||
BattleTreeGreat => RibbonIndexGroup.Common7,
|
||||
BattleTreeMaster => RibbonIndexGroup.Common7,
|
||||
|
||||
ChampionGalar => RibbonIndexGroup.Common8,
|
||||
TowerMaster => RibbonIndexGroup.Common8,
|
||||
MasterRank => RibbonIndexGroup.Common8,
|
||||
Pioneer => RibbonIndexGroup.Common8,
|
||||
TwinklingStar => RibbonIndexGroup.Common8,
|
||||
_ => RibbonIndexGroup.None,
|
||||
};
|
||||
}
|
||||
|
||||
public static void Fix(this RibbonIndex r, RibbonVerifierArguments args, bool state)
|
||||
{
|
||||
var pk = args.Entity;
|
||||
var group = r.GetGroup();
|
||||
switch (group)
|
||||
{
|
||||
case RibbonIndexGroup.Mark:
|
||||
r.FixMark(pk, state);
|
||||
return;
|
||||
case RibbonIndexGroup.CountMemory:
|
||||
if (pk is not IRibbonSetCommon6 m6)
|
||||
return;
|
||||
(byte contest, byte battle) = state ? RibbonRules.GetMaxMemoryCounts(args.History, args.Entity, args.Encounter) : default;
|
||||
if (r is CountMemoryContest)
|
||||
m6.RibbonCountMemoryContest = contest;
|
||||
else
|
||||
m6.RibbonCountMemoryBattle = battle;
|
||||
return;
|
||||
case RibbonIndexGroup.Common3:
|
||||
if (pk is not IRibbonSetCommon3 c3)
|
||||
return;
|
||||
if (r == ChampionG3) c3.RibbonChampionG3 = state;
|
||||
else if (r == Effort) c3.RibbonEffort = state;
|
||||
else if (r == Artist) c3.RibbonArtist = state;
|
||||
return;
|
||||
case RibbonIndexGroup.Common4:
|
||||
if (pk is not IRibbonSetCommon4 c4)
|
||||
return;
|
||||
if (r == ChampionSinnoh) c4.RibbonChampionSinnoh = state;
|
||||
else if (r == Alert) c4.RibbonAlert = state;
|
||||
else if (r == Shock) c4.RibbonShock = state;
|
||||
else if (r == Downcast) c4.RibbonDowncast = state;
|
||||
else if (r == Careless) c4.RibbonCareless = state;
|
||||
else if (r == Relax) c4.RibbonRelax = state;
|
||||
else if (r == Snooze) c4.RibbonSnooze = state;
|
||||
else if (r == Smile) c4.RibbonSmile = state;
|
||||
else if (r == Gorgeous) c4.RibbonGorgeous = state;
|
||||
else if (r == Royal) c4.RibbonRoyal = state;
|
||||
else if (r == GorgeousRoyal) c4.RibbonGorgeousRoyal = state;
|
||||
else if (r == Footprint) c4.RibbonFootprint = state;
|
||||
else if (r == Record) c4.RibbonRecord = state;
|
||||
else if (r == Legend) c4.RibbonLegend = state;
|
||||
return;
|
||||
case RibbonIndexGroup.Event3:
|
||||
if (pk is not IRibbonSetEvent3 e3)
|
||||
return;
|
||||
if (r == Country) e3.RibbonCountry = state;
|
||||
else if (r == National) e3.RibbonNational = state;
|
||||
else if (r == Earth) e3.RibbonEarth = state;
|
||||
else if (r == ChampionBattle) e3.RibbonChampionBattle = state;
|
||||
else if (r == ChampionRegional) e3.RibbonChampionRegional = state;
|
||||
else if (r == ChampionNational) e3.RibbonChampionNational = state;
|
||||
return;
|
||||
case RibbonIndexGroup.Event4:
|
||||
if (pk is not IRibbonSetEvent4 e4)
|
||||
return;
|
||||
if (r == World) e4.RibbonWorld = state;
|
||||
else if (r == Classic) e4.RibbonClassic = state;
|
||||
else if (r == Premier) e4.RibbonPremier = state;
|
||||
else if (r == Event) e4.RibbonEvent = state;
|
||||
else if (r == Birthday) e4.RibbonBirthday = state;
|
||||
else if (r == Special) e4.RibbonSpecial = state;
|
||||
else if (r == Souvenir) e4.RibbonSouvenir = state;
|
||||
else if (r == Wishing) e4.RibbonWishing = state;
|
||||
else if (r == ChampionWorld) e4.RibbonChampionWorld = state;
|
||||
return;
|
||||
case RibbonIndexGroup.Common6:
|
||||
if (pk is not IRibbonSetCommon6 c6)
|
||||
return;
|
||||
if (r == ChampionKalos) c6.RibbonChampionKalos = state;
|
||||
else if (r == BestFriends) c6.RibbonBestFriends = state;
|
||||
else if (r == Training) c6.RibbonTraining = state;
|
||||
else if (r == BattlerSkillful) c6.RibbonBattlerSkillful = state;
|
||||
else if (r == BattlerExpert) c6.RibbonBattlerExpert = state;
|
||||
else if (r == ChampionG6Hoenn) c6.RibbonChampionG6Hoenn = state;
|
||||
else if (r == ContestStar) c6.RibbonContestStar = state;
|
||||
else if (r == MasterCoolness) c6.RibbonMasterCoolness = state;
|
||||
else if (r == MasterBeauty) c6.RibbonMasterBeauty = state;
|
||||
else if (r == MasterCuteness) c6.RibbonMasterCuteness = state;
|
||||
else if (r == MasterCleverness) c6.RibbonMasterCleverness = state;
|
||||
else if (r == MasterToughness) c6.RibbonMasterToughness = state;
|
||||
return;
|
||||
case RibbonIndexGroup.Common7:
|
||||
if (pk is not IRibbonSetCommon7 c7)
|
||||
return;
|
||||
if (r == ChampionAlola) c7.RibbonChampionAlola = state;
|
||||
else if (r == BattleRoyale) c7.RibbonBattleRoyale = state;
|
||||
else if (r == BattleTreeGreat) c7.RibbonBattleTreeGreat = state;
|
||||
else if (r == BattleTreeMaster) c7.RibbonBattleTreeMaster = state;
|
||||
return;
|
||||
case RibbonIndexGroup.Common8:
|
||||
if (pk is not IRibbonSetCommon8 c8)
|
||||
return;
|
||||
if (r == ChampionGalar) c8.RibbonChampionGalar = state;
|
||||
else if (r == TowerMaster) c8.RibbonTowerMaster = state;
|
||||
else if (r == MasterRank) c8.RibbonMasterRank = state;
|
||||
else if (r == Pioneer) c8.RibbonPioneer = state;
|
||||
else if (r == TwinklingStar) c8.RibbonTwinklingStar = state;
|
||||
return;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void FixMark(this RibbonIndex r, PKM pk, bool state)
|
||||
{
|
||||
if (pk is not IRibbonSetMark8 m)
|
||||
return;
|
||||
_ = r switch
|
||||
{
|
||||
MarkLunchtime => m.RibbonMarkLunchtime = state,
|
||||
MarkSleepyTime => m.RibbonMarkSleepyTime = state,
|
||||
MarkDusk => m.RibbonMarkDusk = state,
|
||||
MarkDawn => m.RibbonMarkDawn = state,
|
||||
MarkCloudy => m.RibbonMarkCloudy = state,
|
||||
MarkRainy => m.RibbonMarkRainy = state,
|
||||
MarkStormy => m.RibbonMarkStormy = state,
|
||||
MarkSnowy => m.RibbonMarkSnowy = state,
|
||||
MarkBlizzard => m.RibbonMarkBlizzard = state,
|
||||
MarkDry => m.RibbonMarkDry = state,
|
||||
MarkSandstorm => m.RibbonMarkSandstorm = state,
|
||||
MarkMisty => m.RibbonMarkMisty = state,
|
||||
MarkDestiny => m.RibbonMarkDestiny = state,
|
||||
MarkFishing => m.RibbonMarkFishing = state,
|
||||
MarkCurry => m.RibbonMarkCurry = state,
|
||||
MarkUncommon => m.RibbonMarkUncommon = state,
|
||||
MarkRare => m.RibbonMarkRare = state,
|
||||
MarkRowdy => m.RibbonMarkRowdy = state,
|
||||
MarkAbsentMinded => m.RibbonMarkAbsentMinded = state,
|
||||
MarkJittery => m.RibbonMarkJittery = state,
|
||||
MarkExcited => m.RibbonMarkExcited = state,
|
||||
MarkCharismatic => m.RibbonMarkCharismatic = state,
|
||||
MarkCalmness => m.RibbonMarkCalmness = state,
|
||||
MarkIntense => m.RibbonMarkIntense = state,
|
||||
MarkZonedOut => m.RibbonMarkZonedOut = state,
|
||||
MarkJoyful => m.RibbonMarkJoyful = state,
|
||||
MarkAngry => m.RibbonMarkAngry = state,
|
||||
MarkSmiley => m.RibbonMarkSmiley = state,
|
||||
MarkTeary => m.RibbonMarkTeary = state,
|
||||
MarkUpbeat => m.RibbonMarkUpbeat = state,
|
||||
MarkPeeved => m.RibbonMarkPeeved = state,
|
||||
MarkIntellectual => m.RibbonMarkIntellectual = state,
|
||||
MarkFerocious => m.RibbonMarkFerocious = state,
|
||||
MarkCrafty => m.RibbonMarkCrafty = state,
|
||||
MarkScowling => m.RibbonMarkScowling = state,
|
||||
MarkKindly => m.RibbonMarkKindly = state,
|
||||
MarkFlustered => m.RibbonMarkFlustered = state,
|
||||
MarkPumpedUp => m.RibbonMarkPumpedUp = state,
|
||||
MarkZeroEnergy => m.RibbonMarkZeroEnergy = state,
|
||||
MarkPrideful => m.RibbonMarkPrideful = state,
|
||||
MarkUnsure => m.RibbonMarkUnsure = state,
|
||||
MarkHumble => m.RibbonMarkHumble = state,
|
||||
MarkThorny => m.RibbonMarkThorny = state,
|
||||
MarkVigor => m.RibbonMarkVigor = state,
|
||||
MarkSlump => m.RibbonMarkSlump = state,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(r), r, null),
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetPropertyName(this RibbonIndex r) => r switch
|
||||
{
|
||||
ChampionKalos => nameof(IRibbonSetCommon6.RibbonChampionKalos),
|
||||
ChampionG3 => nameof(IRibbonSetCommon3.RibbonChampionG3),
|
||||
ChampionSinnoh => nameof(IRibbonSetCommon4.RibbonChampionSinnoh),
|
||||
BestFriends => nameof(IRibbonSetCommon6.RibbonBestFriends),
|
||||
Training => nameof(IRibbonSetCommon6.RibbonTraining),
|
||||
BattlerSkillful => nameof(IRibbonSetCommon6.RibbonBattlerSkillful),
|
||||
BattlerExpert => nameof(IRibbonSetCommon6.RibbonBattlerExpert),
|
||||
Effort => nameof(IRibbonSetCommon3.RibbonEffort),
|
||||
Alert => nameof(IRibbonSetCommon4.RibbonAlert),
|
||||
Shock => nameof(IRibbonSetCommon4.RibbonShock),
|
||||
Downcast => nameof(IRibbonSetCommon4.RibbonDowncast),
|
||||
Careless => nameof(IRibbonSetCommon4.RibbonCareless),
|
||||
Relax => nameof(IRibbonSetCommon4.RibbonRelax),
|
||||
Snooze => nameof(IRibbonSetCommon4.RibbonSnooze),
|
||||
Smile => nameof(IRibbonSetCommon4.RibbonSmile),
|
||||
Gorgeous => nameof(IRibbonSetCommon4.RibbonGorgeous),
|
||||
Royal => nameof(IRibbonSetCommon4.RibbonRoyal),
|
||||
GorgeousRoyal => nameof(IRibbonSetCommon4.RibbonGorgeousRoyal),
|
||||
Artist => nameof(IRibbonSetCommon3.RibbonArtist),
|
||||
Footprint => nameof(IRibbonSetCommon4.RibbonFootprint),
|
||||
Record => nameof(IRibbonSetCommon4.RibbonRecord),
|
||||
Legend => nameof(IRibbonSetCommon4.RibbonLegend),
|
||||
Country => nameof(IRibbonSetEvent3.RibbonCountry),
|
||||
National => nameof(IRibbonSetEvent3.RibbonNational),
|
||||
Earth => nameof(IRibbonSetEvent3.RibbonEarth),
|
||||
World => nameof(IRibbonSetEvent4.RibbonWorld),
|
||||
Classic => nameof(IRibbonSetEvent4.RibbonClassic),
|
||||
Premier => nameof(IRibbonSetEvent4.RibbonPremier),
|
||||
Event => nameof(IRibbonSetEvent4.RibbonEvent),
|
||||
Birthday => nameof(IRibbonSetEvent4.RibbonBirthday),
|
||||
Special => nameof(IRibbonSetEvent4.RibbonSpecial),
|
||||
Souvenir => nameof(IRibbonSetEvent4.RibbonSouvenir),
|
||||
Wishing => nameof(IRibbonSetEvent4.RibbonWishing),
|
||||
ChampionBattle => nameof(IRibbonSetEvent3.RibbonChampionBattle),
|
||||
ChampionRegional => nameof(IRibbonSetEvent3.RibbonChampionRegional),
|
||||
ChampionNational => nameof(IRibbonSetEvent3.RibbonChampionNational),
|
||||
ChampionWorld => nameof(IRibbonSetEvent4.RibbonChampionWorld),
|
||||
CountMemoryContest => nameof(IRibbonSetCommon6.RibbonCountMemoryContest),
|
||||
CountMemoryBattle => nameof(IRibbonSetCommon6.RibbonCountMemoryBattle),
|
||||
ChampionG6Hoenn => nameof(IRibbonSetCommon6.RibbonChampionG6Hoenn),
|
||||
ContestStar => nameof(IRibbonSetCommon6.RibbonContestStar),
|
||||
MasterCoolness => nameof(IRibbonSetCommon6.RibbonMasterCoolness),
|
||||
MasterBeauty => nameof(IRibbonSetCommon6.RibbonMasterBeauty),
|
||||
MasterCuteness => nameof(IRibbonSetCommon6.RibbonMasterCuteness),
|
||||
MasterCleverness => nameof(IRibbonSetCommon6.RibbonMasterCleverness),
|
||||
MasterToughness => nameof(IRibbonSetCommon6.RibbonMasterToughness),
|
||||
ChampionAlola => nameof(IRibbonSetCommon7.RibbonChampionAlola),
|
||||
BattleRoyale => nameof(IRibbonSetCommon7.RibbonBattleRoyale),
|
||||
BattleTreeGreat => nameof(IRibbonSetCommon7.RibbonBattleTreeGreat),
|
||||
BattleTreeMaster => nameof(IRibbonSetCommon7.RibbonBattleTreeMaster),
|
||||
ChampionGalar => nameof(IRibbonSetCommon8.RibbonChampionGalar),
|
||||
TowerMaster => nameof(IRibbonSetCommon8.RibbonTowerMaster),
|
||||
MasterRank => nameof(IRibbonSetCommon8.RibbonMasterRank),
|
||||
MarkLunchtime => nameof(IRibbonSetMark8.RibbonMarkLunchtime),
|
||||
MarkSleepyTime => nameof(IRibbonSetMark8.RibbonMarkSleepyTime),
|
||||
MarkDusk => nameof(IRibbonSetMark8.RibbonMarkDusk),
|
||||
MarkDawn => nameof(IRibbonSetMark8.RibbonMarkDawn),
|
||||
MarkCloudy => nameof(IRibbonSetMark8.RibbonMarkCloudy),
|
||||
MarkRainy => nameof(IRibbonSetMark8.RibbonMarkRainy),
|
||||
MarkStormy => nameof(IRibbonSetMark8.RibbonMarkStormy),
|
||||
MarkSnowy => nameof(IRibbonSetMark8.RibbonMarkSnowy),
|
||||
MarkBlizzard => nameof(IRibbonSetMark8.RibbonMarkBlizzard),
|
||||
MarkDry => nameof(IRibbonSetMark8.RibbonMarkDry),
|
||||
MarkSandstorm => nameof(IRibbonSetMark8.RibbonMarkSandstorm),
|
||||
MarkMisty => nameof(IRibbonSetMark8.RibbonMarkMisty),
|
||||
MarkDestiny => nameof(IRibbonSetMark8.RibbonMarkDestiny),
|
||||
MarkFishing => nameof(IRibbonSetMark8.RibbonMarkFishing),
|
||||
MarkCurry => nameof(IRibbonSetMark8.RibbonMarkCurry),
|
||||
MarkUncommon => nameof(IRibbonSetMark8.RibbonMarkUncommon),
|
||||
MarkRare => nameof(IRibbonSetMark8.RibbonMarkRare),
|
||||
MarkRowdy => nameof(IRibbonSetMark8.RibbonMarkRowdy),
|
||||
MarkAbsentMinded => nameof(IRibbonSetMark8.RibbonMarkAbsentMinded),
|
||||
MarkJittery => nameof(IRibbonSetMark8.RibbonMarkJittery),
|
||||
MarkExcited => nameof(IRibbonSetMark8.RibbonMarkExcited),
|
||||
MarkCharismatic => nameof(IRibbonSetMark8.RibbonMarkCharismatic),
|
||||
MarkCalmness => nameof(IRibbonSetMark8.RibbonMarkCalmness),
|
||||
MarkIntense => nameof(IRibbonSetMark8.RibbonMarkIntense),
|
||||
MarkZonedOut => nameof(IRibbonSetMark8.RibbonMarkZonedOut),
|
||||
MarkJoyful => nameof(IRibbonSetMark8.RibbonMarkJoyful),
|
||||
MarkAngry => nameof(IRibbonSetMark8.RibbonMarkAngry),
|
||||
MarkSmiley => nameof(IRibbonSetMark8.RibbonMarkSmiley),
|
||||
MarkTeary => nameof(IRibbonSetMark8.RibbonMarkTeary),
|
||||
MarkUpbeat => nameof(IRibbonSetMark8.RibbonMarkUpbeat),
|
||||
MarkPeeved => nameof(IRibbonSetMark8.RibbonMarkPeeved),
|
||||
MarkIntellectual => nameof(IRibbonSetMark8.RibbonMarkIntellectual),
|
||||
MarkFerocious => nameof(IRibbonSetMark8.RibbonMarkFerocious),
|
||||
MarkCrafty => nameof(IRibbonSetMark8.RibbonMarkCrafty),
|
||||
MarkScowling => nameof(IRibbonSetMark8.RibbonMarkScowling),
|
||||
MarkKindly => nameof(IRibbonSetMark8.RibbonMarkKindly),
|
||||
MarkFlustered => nameof(IRibbonSetMark8.RibbonMarkFlustered),
|
||||
MarkPumpedUp => nameof(IRibbonSetMark8.RibbonMarkPumpedUp),
|
||||
MarkZeroEnergy => nameof(IRibbonSetMark8.RibbonMarkZeroEnergy),
|
||||
MarkPrideful => nameof(IRibbonSetMark8.RibbonMarkPrideful),
|
||||
MarkUnsure => nameof(IRibbonSetMark8.RibbonMarkUnsure),
|
||||
MarkHumble => nameof(IRibbonSetMark8.RibbonMarkHumble),
|
||||
MarkThorny => nameof(IRibbonSetMark8.RibbonMarkThorny),
|
||||
MarkVigor => nameof(IRibbonSetMark8.RibbonMarkVigor),
|
||||
MarkSlump => nameof(IRibbonSetMark8.RibbonMarkSlump),
|
||||
Pioneer => nameof(IRibbonSetCommon8.RibbonPioneer),
|
||||
TwinklingStar => nameof(IRibbonSetCommon8.RibbonTwinklingStar),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(r), r, null),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user