using System.Collections.Generic; using System.Linq; namespace PKHeX.Core { /// /// Logic for applying ribbons. /// public static class RibbonApplicator { private static List GetAllRibbonNames(PKM pkm) => RibbonInfo.GetRibbonInfo(pkm).Select(z => z.Name).ToList(); /// /// Gets a list of valid ribbons for the . /// /// Entity to fetch the list for. /// All ribbon names. /// List of all valid ribbon names. public static IReadOnlyList GetValidRibbons(PKM pkm, IList allRibbons) { var pk = pkm.Clone(); return SetAllValidRibbons(allRibbons, pk); } /// /// Gets a list of valid ribbons for the . /// /// Entity to fetch the list for. /// List of all valid ribbon names. public static IReadOnlyList GetValidRibbons(PKM pkm) { var names = GetAllRibbonNames(pkm); return GetValidRibbons(pkm, names); } /// /// Gets a list of valid ribbons for the that can be removed. /// /// Entity to fetch the list for. /// All ribbon names. /// List of all removable ribbon names. public static IReadOnlyList GetRemovableRibbons(PKM pkm, IList allRibbons) { var pk = pkm.Clone(); return RemoveAllValidRibbons(allRibbons, pk); } /// /// Gets a list of valid ribbons for the that can be removed. /// /// Entity to fetch the list for. /// List of all removable ribbon names. public static IReadOnlyList GetRemovableRibbons(PKM pkm) { var names = GetAllRibbonNames(pkm); return GetRemovableRibbons(pkm, names); } /// /// Sets all valid ribbons to the . /// /// Entity to set ribbons for. /// True if any ribbons were applied. public static bool SetAllValidRibbons(PKM pkm) { var ribNames = GetAllRibbonNames(pkm); ribNames.RemoveAll(z => z.StartsWith("RibbonMark")); // until marking legality is handled return SetAllValidRibbons(pkm, ribNames); } /// /// Sets all valid ribbons to the . /// /// Entity to set ribbons for. /// Ribbon names to try setting. /// True if any ribbons were applied. public static bool SetAllValidRibbons(PKM pkm, List ribNames) { var list = SetAllValidRibbons(ribNames, pkm); return list.Count != 0; } private static IReadOnlyList SetAllValidRibbons(IList allRibbons, PKM pk) { var la = new LegalityAnalysis(pk); var valid = new List(); while (TryApplyAllRibbons(pk, la, allRibbons, valid) != 0) { // Repeat the operation until no more ribbons are set. } return valid; } /// /// Sets all valid ribbons to the . /// /// Entity to set ribbons for. /// True if any ribbons were removed. public static bool RemoveAllValidRibbons(PKM pkm) { var ribNames = GetAllRibbonNames(pkm); return RemoveAllValidRibbons(pkm, ribNames); } /// /// Sets all valid ribbons to the . /// /// Entity to set ribbons for. /// Ribbon names to try setting. /// True if any ribbons were removed. public static bool RemoveAllValidRibbons(PKM pkm, List ribNames) { var list = RemoveAllValidRibbons(ribNames, pkm); return list.Count != 0; } private static IReadOnlyList RemoveAllValidRibbons(IList allRibbons, PKM pk) { var la = new LegalityAnalysis(pk); var valid = new List(); while (TryRemoveAllRibbons(pk, la, allRibbons, valid) != 0) { // Repeat the operation until no more ribbons are set. } return valid; } private static int TryApplyAllRibbons(PKM pk, LegalityAnalysis la, IList allRibbons, ICollection valid) { int applied = 0; for (int i = 0; i < allRibbons.Count;) { 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 allRibbons, ICollection 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); LegalityAnalysis.Ribbon.Verify(la); return la.Results.All(z => z.Valid); } private static bool TryApplyRibbon(PKM pk, LegalityAnalysis la, string rib) { SetRibbonValue(pk, rib, 1); LegalityAnalysis.Ribbon.Verify(la); return la.Results.All(z => z.Valid); } 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")) ReflectUtil.SetValue(pk, rib, value * 4); else ReflectUtil.SetValue(pk, rib, value != 0); break; } } } }