diff --git a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownParsing.cs b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownParsing.cs index aabd21e67..0dbe345ce 100644 --- a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownParsing.cs +++ b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownParsing.cs @@ -74,7 +74,7 @@ public static string GetStringFromForm(byte form, GameStrings strings, ushort sp if (form == 0) return string.Empty; - var result = FormConverter.GetStringFromForm(form, strings, species, genderForms, context); + var result = FormConverter.GetStringFromForm(species, form, strings, genderForms, context); if (result.Length == 0) return string.Empty; diff --git a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs index 22f13cb5d..505a318c9 100644 --- a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs +++ b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs @@ -561,7 +561,7 @@ private void PushToken(BattleTemplateToken token, List result, in Battle result.Add(cfg.Push(token, Friendship)); break; case BattleTemplateToken.IVs: - var maxIV = Context.Generation < 3 ? 15 : 31; + var maxIV = Context.IsEraGameBoy ? 15 : 31; if (!IVs.ContainsAnyExcept(maxIV)) break; // skip if all IVs are maxed var nameIVs = cfg.GetStatDisplay(settings.StatsIVs); @@ -1028,7 +1028,7 @@ private ReadOnlySpan ParseLineMove(ReadOnlySpan line, GameStrings st return hiddenPowerName; HiddenPowerType = (sbyte)hpVal; - var maxIV = Context.Generation < 3 ? 15 : 31; + var maxIV = Context.IsEraGameBoy ? 15 : 31; if (IVs.ContainsAnyExcept(maxIV)) { if (!HiddenPower.SetIVsForType(hpVal, IVs, Context)) diff --git a/PKHeX.Core/Editing/Database/TrainerDatabase.cs b/PKHeX.Core/Editing/Database/TrainerDatabase.cs index 389f03620..b09fbdda7 100644 --- a/PKHeX.Core/Editing/Database/TrainerDatabase.cs +++ b/PKHeX.Core/Editing/Database/TrainerDatabase.cs @@ -86,14 +86,14 @@ public ReadOnlySpan GetTrainers(GameVersion version) } /// - /// Fetches an appropriate trainer based on the requested . + /// Fetches an appropriate trainer based on the requested . /// - /// Generation the trainer should inhabit + /// Generation the trainer should inhabit /// Language to request for /// Null if no trainer found for this version. - public ITrainerInfo? GetTrainerFromGen(byte generation, LanguageID? lang = null) + public ITrainerInfo? GetTrainerFromContext(EntityContext context, LanguageID? lang = null) { - var possible = Database.Where(z => z.Key.Generation == generation).ToList(); + var possible = Database.Where(z => z.Key.Context == context).ToList(); if (possible.Count == 0) return null; diff --git a/PKHeX.Core/Editing/HiddenPower.cs b/PKHeX.Core/Editing/HiddenPower.cs index 72563e69a..28bbf6dbe 100644 --- a/PKHeX.Core/Editing/HiddenPower.cs +++ b/PKHeX.Core/Editing/HiddenPower.cs @@ -15,7 +15,7 @@ public static class HiddenPower /// Generation format public static int GetType(ReadOnlySpan IVs, EntityContext context) { - if (context.Generation <= 2) + if (context.IsEraGameBoy) return GetTypeGB(IVs); return GetType(IVs); } @@ -153,7 +153,7 @@ public static ushort SetTypeGB(int hiddenPowerType, ushort current) /// True if the Hidden Power of the is obtained, with or without modifications public static bool SetIVsForType(int hiddenPowerType, Span IVs, EntityContext context) { - if (context.Generation <= 2) + if (context.IsEraGameBoy) return SetTypeGB(hiddenPowerType, IVs); return SetIVsForType(hiddenPowerType, IVs); } @@ -238,7 +238,7 @@ private static int GetFlawedBitCount(ReadOnlySpan ivs, int bitValue) /// Generation specific format public static void SetIVs(int type, Span ivs, EntityContext context = Latest.Context) { - if (context.Generation <= 2) + if (context.IsEraGameBoy) { ivs[1] = (ivs[1] & 0b1100) | (type >> 2); ivs[2] = (ivs[2] & 0b1100) | (type & 3); diff --git a/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs b/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs index a05dc6b19..b38d3a57e 100644 --- a/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs +++ b/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs @@ -28,7 +28,7 @@ public FilteredGameDataSource(SaveFile sav, GameDataSource source, bool HaX = fa Items = []; } - var gamelist = GameUtil.GetVersionsWithinRange(sav, sav.Generation).ToList(); + var gamelist = GameUtil.GetVersionsWithinRange(sav, sav.Context).ToList(); Games = Source.VersionDataSource.Where(g => gamelist.Contains((GameVersion)g.Value) || g.Value == 0).ToList(); Languages = Source.LanguageDataSource(sav.Generation, sav.Context); diff --git a/PKHeX.Core/Game/GameUtil.cs b/PKHeX.Core/Game/GameUtil.cs index 81d5686f0..66b0c012a 100644 --- a/PKHeX.Core/Game/GameUtil.cs +++ b/PKHeX.Core/Game/GameUtil.cs @@ -252,23 +252,23 @@ public bool Contains(GameVersion g2) } /// - /// List of possible values within the provided . + /// List of possible values within the provided . /// - /// Generation to look within + /// Generation to look within /// Entity version - public static GameVersion[] GetVersionsInGeneration(byte generation, GameVersion version) + public static GameVersion[] GetVersionsInGeneration(EntityContext context, GameVersion version) { - if (Gen7b.Contains(version)) + if (context is EntityContext.Gen7b) return [GO, GP, GE]; - return Array.FindAll(GameVersions, z => z.Generation == generation); + return Array.FindAll(GameVersions, z => z.Context == context); } /// /// List of possible values within the provided criteria. /// /// Criteria for retrieving versions - /// Generation format minimum (necessary for the CXD/Gen4 swap etc.) - public static IEnumerable GetVersionsWithinRange(IGameValueLimit obj, byte generation = 0) + /// Generation format minimum (necessary for the CXD/Gen4 swap etc.) + public static IEnumerable GetVersionsWithinRange(IGameValueLimit obj, EntityContext context = 0) { var max = obj.MaxGameID; if (max == Legal.MaxGameID_7b) // edge case @@ -277,14 +277,14 @@ public static IEnumerable GetVersionsWithinRange(IGameValueLimit ob .Where(version => obj.MinGameID <= version && version <= max); if (max != BATREV) versions = versions.Where(static version => version != BATREV); - if (generation == 0) + if (context == 0) return versions; - if (max == Legal.MaxGameID_7 && generation == 7) + if (max == Legal.MaxGameID_7 && context == EntityContext.Gen7) versions = versions.Where(static version => version != GO); // HOME allows up-reach to Gen9 - if (generation >= 8) - generation = 9; - return versions.Where(version => version.Generation <= generation); + if (context.IsEraHOME) + return versions; + return versions.Where(version => version.Generation <= context.Generation); } } diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs index 4e5e3203b..23d46642e 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs @@ -141,7 +141,7 @@ private static bool VerifySecondaryChecks(PKM pk, LegalInfo info, PeekEnumerator } else if (pk is PK1 pk1) { - var hasGen2 = MoveInfo.IsAnyFromGeneration(2, info.Moves); + var hasGen2 = MoveInfo.IsAnyFromGeneration(EntityContext.Gen2, info.Moves); if (hasGen2) { if (!ParseSettings.AllowGen1Tradeback) diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterMutation.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterMutation.cs index dc7c4b839..1fc97518f 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterMutation.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterMutation.cs @@ -34,10 +34,9 @@ public static class EncounterMutationUtil /// Destination level public static EncounterMutation GetSuggested(EntityContext targetContext, byte level) { - var gen = targetContext.Generation; - if (gen < 6) + if (targetContext.IsEraPre3DS) return EncounterMutation.None; - if (gen < 8) + if (targetContext.IsEraPreSwitch) { if (targetContext is EntityContext.Gen7b) return level != 100 ? EncounterMutation.None : EncounterMutation.CanMaxIndividualStat; diff --git a/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs index 342d7b3bc..f35cb4536 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs @@ -37,7 +37,7 @@ public static IEnumerable GenerateEncounters(PKM pk, ITrainerInf yield break; OptimizeCriteria(pk, info); - var vers = versions.Length >= 1 ? versions : GameUtil.GetVersionsWithinRange(pk, pk.Format); + var vers = versions.Length >= 1 ? versions : GameUtil.GetVersionsWithinRange(pk, pk.Context); foreach (var version in vers) { var encounters = GenerateVersionEncounters(pk, moves, version); @@ -63,12 +63,12 @@ public static void OptimizeCriteria(PKM pk, ITrainerID32ReadOnly info) /// Gets possible encounters that allow all moves requested to be learned. /// /// Rough Pokémon data which contains the requested species, gender, and form. - /// Specific generation to iterate versions for. + /// Specific generation to iterate versions for. /// Moves that the resulting must be able to learn. /// A consumable list of possible encounters. - public static IEnumerable GenerateEncounter(PKM pk, byte generation, ReadOnlyMemory moves) + public static IEnumerable GenerateEncounter(PKM pk, EntityContext context, ReadOnlyMemory moves) { - var vers = GameUtil.GetVersionsInGeneration(generation, pk.Version); + var vers = GameUtil.GetVersionsInGeneration(context, pk.Version); return GenerateEncounters(pk, moves, vers); } @@ -84,7 +84,7 @@ public static IEnumerable GenerateEncounters(PKM pk, ReadOnlyMem if (!IsSane(pk, moves.Span)) yield break; - var vers = versions.Length != 0 ? versions : GameUtil.GetVersionsWithinRange(pk, pk.Format); + var vers = versions.Length != 0 ? versions : GameUtil.GetVersionsWithinRange(pk, pk.Context); foreach (var version in vers) { foreach (var enc in GenerateVersionEncounters(pk, moves, version)) @@ -382,7 +382,7 @@ private static bool IsSane(ReadOnlySpan chain, IEncounterTemplate e return true; if (enc is IEncounterFormRandom { IsRandomUnspecificForm: true } or { Species: (ushort)Species.Unown }) return true; - if (enc is EncounterStatic7 {IsTotem: true} && evo.Form == 0 && current.Generation > 7) // totems get form wiped + if (enc is EncounterStatic7 {IsTotem: true} && evo.Form == 0 && current != EntityContext.Gen7) // totems get form wiped return true; break; } diff --git a/PKHeX.Core/Legality/Formatting/BaseLegalityFormatter.cs b/PKHeX.Core/Legality/Formatting/BaseLegalityFormatter.cs index e675a04f5..124a887be 100644 --- a/PKHeX.Core/Legality/Formatting/BaseLegalityFormatter.cs +++ b/PKHeX.Core/Legality/Formatting/BaseLegalityFormatter.cs @@ -43,7 +43,7 @@ private static void GetLegalityReportLines(in LegalityLocalizationContext la, Li var info = l.Info; var pk = l.Entity; - LegalityFormatting.AddMoves(la, info.Moves, lines, pk.Format, false); + LegalityFormatting.AddMoves(la, info.Moves, lines, pk.Context, false); if (pk.Format >= 6) LegalityFormatting.AddRelearn(la, info.Relearn, lines, false); LegalityFormatting.AddSecondaryChecksInvalid(la, l.Results, lines); @@ -66,10 +66,9 @@ private static List GetVerboseLegalityReportLines(in LegalityLocalizatio var pk = l.Entity; int initialCount = lines.Count; - var format = pk.Format; - LegalityFormatting.AddMoves(la, info.Moves, lines, format, true); + LegalityFormatting.AddMoves(la, info.Moves, lines, pk.Context, true); - if (format >= 6) + if (pk.Format >= 6) LegalityFormatting.AddRelearn(la, info.Relearn, lines, true); if (lines.Count != initialCount) // move info added, break for next section diff --git a/PKHeX.Core/Legality/Formatting/LegalityFormatting.cs b/PKHeX.Core/Legality/Formatting/LegalityFormatting.cs index b0a9816f2..49393e808 100644 --- a/PKHeX.Core/Legality/Formatting/LegalityFormatting.cs +++ b/PKHeX.Core/Legality/Formatting/LegalityFormatting.cs @@ -66,7 +66,7 @@ public static void AddRelearn(LegalityLocalizationContext la, ReadOnlySpan moves, List lines, in byte currentFormat, bool state) + public static void AddMoves(LegalityLocalizationContext la, ReadOnlySpan moves, List lines, in EntityContext currentFormat, bool state) { for (int i = 0; i < moves.Length; i++) { diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup1.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup1.cs index 767cd44e2..4752a9ead 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup1.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup1.cs @@ -9,6 +9,7 @@ public sealed class LearnGroup1 : ILearnGroup { public static readonly LearnGroup1 Instance = new(); private const byte Generation = 1; + private const EntityContext Context = EntityContext.Gen1; public ushort MaxMoveID => Legal.MaxMoveID_1; public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => pk.Context switch @@ -45,7 +46,7 @@ private static void FlagEvolutionSlots(Span result, ReadOnlySpan result, ReadOnlySpan level && species2 < species) return true; @@ -170,19 +171,19 @@ private static void Check(Span result, ReadOnlySpan current, for (int i = result.Length - 1; i >= 0; i--) { ref var entry = ref result[i]; - if (entry is { Valid: true, Generation: > 2 }) + if (entry is { Valid: true, Context: not (EntityContext.Gen1 or EntityContext.Gen2) }) continue; var move = current[i]; var chk = yw.GetCanLearn(pk, yp, evo, move, types); if (chk != default && GetIsPreferable(entry, chk, stage)) { - entry = new(chk, (byte)stage, Generation); + entry = new(chk, (byte)stage, Context); continue; } chk = rb.GetCanLearn(pk, rp, evo, move, types); if (chk != default && GetIsPreferable(entry, chk, stage)) - entry = new(chk, (byte)stage, Generation); + entry = new(chk, (byte)stage, Context); } } diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup2.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup2.cs index 674843b0b..46abc4e2f 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup2.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup2.cs @@ -8,14 +8,14 @@ namespace PKHeX.Core; public sealed class LearnGroup2 : ILearnGroup { public static readonly LearnGroup2 Instance = new(); - private const byte Generation = 2; + private const EntityContext Context = EntityContext.Gen2; public ushort MaxMoveID => Legal.MaxMoveID_2; public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => pk.Context switch { - EntityContext.Gen2 when enc.Generation == 1 => LearnGroup1.Instance, + EntityContext.Gen2 when enc.Context == EntityContext.Gen1 => LearnGroup1.Instance, EntityContext.Gen1 => null, - _ => enc.Generation != 1 && !pk.Korean && history.HasVisitedGen1 ? LearnGroup1.Instance : null, + _ => enc.Context != EntityContext.Gen1 && !pk.Korean && history.HasVisitedGen1 ? LearnGroup1.Instance : null, }; public bool HasVisited(PKM pk, EvolutionHistory history) => history.HasVisitedGen2; @@ -23,7 +23,7 @@ public sealed class LearnGroup2 : ILearnGroup public bool Check(Span result, ReadOnlySpan current, PKM pk, EvolutionHistory history, IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) { - if (enc.Generation == Generation && types.HasFlag(MoveSourceType.Encounter)) + if (enc.Context == Context && types.HasFlag(MoveSourceType.Encounter)) CheckEncounterMoves(pk, result, current, enc); var evos = history.Gen2; @@ -55,7 +55,7 @@ public sealed class LearnGroup2 : ILearnGroup if (!move.IsParsed) continue; var method = move.Info.Method; - if ((vc1 && move.Generation == 2) || method is LearnMethod.Initial || method.IsEggSource) + if ((vc1 && move.Context == EntityContext.Gen2) || method is LearnMethod.Initial || method.IsEggSource) result[i] = MoveResult.Unobtainable(); } @@ -116,14 +116,14 @@ private static void Check(Span result, ReadOnlySpan current, for (int i = result.Length - 1; i >= 0; i--) { ref var entry = ref result[i]; - if (entry is { Valid: true, Generation: > 2 }) + if (entry is { Valid: true, Context: not (EntityContext.Gen1 or EntityContext.Gen2) }) continue; var move = current[i]; var chk = gs.GetCanLearn(pk, gp, evo, move, types); if (chk != default && GetIsPreferable(entry, chk, stage)) { - entry = new(chk, (byte)stage, Generation); + entry = new(chk, (byte)stage, Context); continue; } @@ -132,13 +132,13 @@ private static void Check(Span result, ReadOnlySpan current, chk = c.GetCanLearn(pk, cp, evo, move, types); if (chk != default && GetIsPreferable(entry, chk, stage)) - entry = new(chk, (byte)stage, Generation); + entry = new(chk, (byte)stage, Context); if (stad2) { chk = LearnSource2Stadium.Instance.GetCanRelearn(evo, move, types); if (chk != default && GetIsPreferable(entry, chk, stage)) - entry = new(chk, (byte)stage, Generation); + entry = new(chk, (byte)stage, Context); } } } @@ -168,7 +168,7 @@ private static bool GetIsPreferable(in MoveResult entry, in MoveLearnInfo chk, i public void GetAllMoves(Span result, PKM pk, EvolutionHistory history, IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) { - if (types.HasFlag(MoveSourceType.Encounter) && enc.Generation == Generation) + if (types.HasFlag(MoveSourceType.Encounter) && enc.Context == Context) FlagEncounterMoves(pk, enc, result); foreach (var evo in history.Gen2) diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup3.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup3.cs index 28f144101..310c8f68f 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup3.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup3.cs @@ -8,7 +8,7 @@ namespace PKHeX.Core; public sealed class LearnGroup3 : ILearnGroup { public static readonly LearnGroup3 Instance = new(); - private const byte Generation = 3; + private const EntityContext Context = EntityContext.Gen3; public ushort MaxMoveID => Legal.MaxMoveID_3; public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => null; // Gen3 is the end of the line! @@ -21,7 +21,7 @@ public sealed class LearnGroup3 : ILearnGroup for (var i = 0; i < evos.Length; i++) Check(result, current, pk, evos[i], i, types); - if (types.HasFlag(MoveSourceType.Encounter) && enc is EncounterEgg3 { Generation: Generation } egg) + if (types.HasFlag(MoveSourceType.Encounter) && enc is EncounterEgg3 { Context: Context } egg) CheckEncounterMoves(result, current, egg); if (types.HasFlag(MoveSourceType.LevelUp) && enc.Species is (int)Species.Nincada && evos is [{ Species: (int)Species.Shedinja }, _]) @@ -61,7 +61,7 @@ private static void CheckNincadaMoves(Span result, ReadOnlySpan result, ReadOnlySpan current, var chk = e.GetCanLearn(pk, ep, evo, move, types); if (chk != default) { - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); continue; } chk = rs.GetCanLearn(pk, rp, evo, move, types & (MoveSourceType.LevelUp | MoveSourceType.AllTutors)); if (chk != default) { - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); continue; } chk = fr.GetCanLearn(pk, fp, evo, move, types & (MoveSourceType.LevelUp | MoveSourceType.AllTutors)); if (chk != default) { - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); continue; } chk = lg.GetCanLearn(pk, lp, evo, move, types & MoveSourceType.LevelUp); // Tutors same as FR if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } public void GetAllMoves(Span result, PKM pk, EvolutionHistory history, IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) { - if (types.HasFlag(MoveSourceType.Encounter) && enc.Generation == Generation) + if (types.HasFlag(MoveSourceType.Encounter) && enc.Context == Context) FlagEncounterMoves(enc, result); var evos = history.Gen3; diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup4.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup4.cs index 282d5c958..9c6d0ce6e 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup4.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup4.cs @@ -8,10 +8,10 @@ namespace PKHeX.Core; public sealed class LearnGroup4 : ILearnGroup { public static readonly LearnGroup4 Instance = new(); - private const byte Generation = 4; + private const EntityContext Context = EntityContext.Gen4; public ushort MaxMoveID => Legal.MaxMoveID_4; - public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => enc.Generation is Generation ? null : LearnGroup3.Instance; + public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => enc.Context is EntityContext.Gen4 ? null : LearnGroup3.Instance; public bool HasVisited(PKM pk, EvolutionHistory history) => history.HasVisitedGen4; public bool Check(Span result, ReadOnlySpan current, PKM pk, EvolutionHistory history, @@ -53,7 +53,7 @@ private static void CheckNincadaMoves(Span result, ReadOnlySpan result, ReadOnlySpan var chk = hgss.GetCanLearn(pk, hgss_pi, evo, move); if (chk != default) { - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); continue; } chk = pt.GetCanLearn(pk, pt_pi, evo, move, MoveSourceType.LevelUp | MoveSourceType.AllMachines); if (chk != default) { - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); continue; } chk = dp.GetCanLearn(pk, pt_pi, evo, move, MoveSourceType.LevelUp); if (chk != default) { - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } } public void GetAllMoves(Span result, PKM pk, EvolutionHistory history, IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) { - if (types.HasFlag(MoveSourceType.Encounter) && enc.Generation == Generation) + if (types.HasFlag(MoveSourceType.Encounter) && enc.Context == Context) FlagEncounterMoves(enc, result); var evos = history.Gen4; diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup5.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup5.cs index beaa1fceb..14e6a60b6 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup5.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup5.cs @@ -8,10 +8,10 @@ namespace PKHeX.Core; public sealed class LearnGroup5 : ILearnGroup { public static readonly LearnGroup5 Instance = new(); - private const byte Generation = 5; + private const EntityContext Context = EntityContext.Gen5; public ushort MaxMoveID => Legal.MaxMoveID_5; - public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => enc.Generation is Generation ? null : LearnGroup4.Instance; + public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => enc.Context is EntityContext.Gen5 ? null : LearnGroup4.Instance; public bool HasVisited(PKM pk, EvolutionHistory history) => history.HasVisitedGen5; public bool Check(Span result, ReadOnlySpan current, PKM pk, EvolutionHistory history, @@ -86,7 +86,7 @@ private static void CheckInternal(Span result, ReadOnlySpan var move = current[i]; var chk = b2w2.GetCanLearn(pk, b2w2_pi, evo, move, types, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); if (bw_pi is null) continue; @@ -94,13 +94,13 @@ private static void CheckInternal(Span result, ReadOnlySpan // B2/W2 is the same besides some level up moves. chk = LearnSource5BW.Instance.GetCanLearn(pk, bw_pi, evo, move, types & MoveSourceType.LevelUp, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } public void GetAllMoves(Span result, PKM pk, EvolutionHistory history, IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) { - if (types.HasFlag(MoveSourceType.Encounter) && enc.Generation == Generation) + if (types.HasFlag(MoveSourceType.Encounter) && enc.Context == Context) FlagEncounterMoves(enc, result); foreach (var evo in history.Gen5) diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup6.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup6.cs index f80620f05..55a424b9d 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup6.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup6.cs @@ -9,9 +9,10 @@ public sealed class LearnGroup6 : ILearnGroup { public static readonly LearnGroup6 Instance = new(); private const byte Generation = 6; + private const EntityContext Context = EntityContext.Gen6; public ushort MaxMoveID => Legal.MaxMoveID_6_AO; - public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => enc.Generation is Generation ? null : LearnGroup5.Instance; + public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => enc.Context is EntityContext.Gen6 ? null : LearnGroup5.Instance; public bool HasVisited(PKM pk, EvolutionHistory history) => history.HasVisitedGen6; public bool Check(Span result, ReadOnlySpan current, PKM pk, EvolutionHistory history, IEncounterTemplate enc, @@ -64,7 +65,7 @@ private static void CheckDexNavMoves(Span result, ReadOnlySpan result, ReadOnlySpan curr var chk = ao.GetCanLearn(pk, ao_pi, evo, move, types, option); if (chk != default) { - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); continue; } chk = xy.GetCanLearn(pk, xy_pi, evo, move, types & MoveSourceType.LevelUp, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } @@ -163,13 +164,13 @@ private static void CheckBoth(Span result, ReadOnlySpan curr var move = current[i]; var chk = game.GetCanLearn(pk, pi, evo, move, types, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } public void GetAllMoves(Span result, PKM pk, EvolutionHistory history, IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) { - if (types.HasFlag(MoveSourceType.Encounter) && enc.Generation == Generation) + if (types.HasFlag(MoveSourceType.Encounter) && enc.Context == Context) FlagEncounterMoves(enc, result); var mode = GetCheckMode(enc, pk); diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup7.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup7.cs index 442f7ce66..a7bd9626b 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup7.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup7.cs @@ -1,4 +1,5 @@ using System; +using static PKHeX.Core.EntityContext; namespace PKHeX.Core; @@ -8,14 +9,15 @@ namespace PKHeX.Core; public sealed class LearnGroup7 : ILearnGroup { public static readonly LearnGroup7 Instance = new(); + private const EntityContext Context = Gen7; private const byte Generation = 7; public ushort MaxMoveID => Legal.MaxMoveID_7_USUM; - public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => enc.Generation switch + public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => enc.Context switch { - 1 => LearnGroup1.Instance, - 2 => LearnGroup2.Instance, - (3 or 4 or 5 or 6) => LearnGroup6.Instance, + Gen1 => LearnGroup1.Instance, + Gen2 => LearnGroup2.Instance, + (Gen3 or Gen4 or Gen5 or Gen6) => LearnGroup6.Instance, _ => null, }; @@ -58,7 +60,7 @@ private static void CheckEncounterMoves(Span result, ReadOnlySpan result, ReadOnlySpan curr var chk = uu.GetCanLearn(pk, uu_pi, evo, move, types, option); if (chk != default) { - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); continue; } @@ -127,7 +129,7 @@ private static void CheckBoth(Span result, ReadOnlySpan curr continue; chk = sm.GetCanLearn(pk, uu_pi, evo, move, types & MoveSourceType.LevelUp, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } @@ -145,13 +147,13 @@ private static void CheckSingle(Span result, ReadOnlySpan cu var move = current[i]; var chk = game.GetCanLearn(pk, pi, evo, move, types, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } public void GetAllMoves(Span result, PKM pk, EvolutionHistory history, IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) { - if (types.HasFlag(MoveSourceType.Encounter) && enc.Generation == Generation) + if (types.HasFlag(MoveSourceType.Encounter) && enc.Context == Context) FlagEncounterMoves(enc, result); var mode = GetCheckMode(enc, pk); diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup7b.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup7b.cs index 9cc249eaf..dcaf9811a 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup7b.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup7b.cs @@ -8,7 +8,7 @@ namespace PKHeX.Core; public sealed class LearnGroup7b : ILearnGroup { public static readonly LearnGroup7b Instance = new(); - private const byte Generation = 7; + private const EntityContext Context = EntityContext.Gen7b; public ushort MaxMoveID => Legal.MaxMoveID_7b; public ILearnGroup? GetPrevious(PKM pk, EvolutionHistory history, IEncounterTemplate enc, LearnOption option) => null; @@ -38,13 +38,13 @@ private static void Check(Span result, ReadOnlySpan current, var move = current[i]; var chk = game.GetCanLearn(pk, pi, evo, move); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } public void GetAllMoves(Span result, PKM pk, EvolutionHistory history, IEncounterTemplate enc, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) { - if (types.HasFlag(MoveSourceType.Encounter) && enc.Generation == Generation) + if (types.HasFlag(MoveSourceType.Encounter) && enc.Context == Context) FlagEncounterMoves(enc, result); foreach (var evo in history.Gen7b) diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8.cs index 6115694dc..ed091462b 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8.cs @@ -128,7 +128,7 @@ private static void CheckInternal(Span result, ReadOnlySpan var move = current[i]; var chk = game.GetCanLearn(pk, pi, evo, move, type, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8a.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8a.cs index 6d86158d6..7af432530 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8a.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8a.cs @@ -45,7 +45,7 @@ private static void Check(Span result, ReadOnlySpan current, var move = current[i]; var chk = game.GetCanLearn(pk, pi, evo, move); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8b.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8b.cs index 5e3fbfb1e..5225e0c90 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8b.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup8b.cs @@ -87,7 +87,7 @@ private static void CheckInternal(Span result, ReadOnlySpan var move = current[i]; var chk = game.GetCanLearn(pk, pi, evo, move, type, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9.cs index 5a98ddbab..f88ebd1d5 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9.cs @@ -109,7 +109,7 @@ private static void CheckInternal(Span result, ReadOnlySpan var move = current[i]; var chk = game.GetCanLearn(pk, pi, evo, move, type, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9a.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9a.cs index d5009ad42..d9fcd5cc0 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9a.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup9a.cs @@ -66,7 +66,7 @@ private static void CheckInternal(Span result, ReadOnlySpan var move = current[i]; var chk = game.GetCanLearn(pk, pi, evo, move, type, option); if (chk != default) - result[i] = new(chk, (byte)stage, Generation); + result[i] = new(chk, (byte)stage, Context); } } diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroupHOME.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroupHOME.cs index 4a2a2db5c..f3e40c78b 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroupHOME.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroupHOME.cs @@ -123,7 +123,7 @@ private static bool CleanPurge(Span result, ReadOnlySpan cur for (int i = 0; i < result.Length; i++) { ref var r = ref result[i]; - if (!r.Valid || r.Generation == 0) + if (!r.Valid || r.Context == 0) continue; if (r.Info.Environment == local.Environment) @@ -146,7 +146,7 @@ private static bool CleanPurge(Span result, ReadOnlySpan cur // Most games do not have a Learn Source for Volt Tackle besides it being specially inserted for Egg Encounters. if (!valid && move is not (ushort)Move.VoltTackle) { - if (r.Generation >= 8 || local is not LearnSource8SWSH) + if (r.Context.IsEraHOME || local is not LearnSource8SWSH) r = default; } } diff --git a/PKHeX.Core/Legality/LearnSource/LearnEnvironment.cs b/PKHeX.Core/Legality/LearnSource/LearnEnvironment.cs index d05ddd6b1..887d6a947 100644 --- a/PKHeX.Core/Legality/LearnSource/LearnEnvironment.cs +++ b/PKHeX.Core/Legality/LearnSource/LearnEnvironment.cs @@ -2,6 +2,7 @@ namespace PKHeX.Core; using static LearnEnvironment; +using static EntityContext; /// /// Indicates the group of game(s) that the move was learned in. @@ -36,9 +37,9 @@ public static class LearnEnvironmentExtensions extension(LearnEnvironment value) { /// - /// Indicates whether the is specified (not ), and thus worth indicating. + /// Indicates whether the is specified (not ), and thus worth indicating. /// - public bool IsSpecified => value is not None; + public bool IsSpecified => value is not LearnEnvironment.None; /// /// Gets the generation number [1-n] for the given . @@ -57,6 +58,24 @@ public static class LearnEnvironmentExtensions _ => 0, }; + public EntityContext Context => value switch + { + RB or YW => Gen1, + GS or C or Stadium2 => Gen2, + RS or E or FR or LG => Gen3, + DP or Pt or HGSS => Gen4, + BW or B2W2 => Gen5, + XY or ORAS => Gen6, + SM or USUM => Gen7, + GG => Gen7b, + SWSH => Gen8, + PLA => Gen8a, + BDSP => Gen8b, + SV => Gen9, + ZA => Gen9a, + _ => 0, + }; + /// /// Retrieves the evolution criteria for the given from the provided . /// diff --git a/PKHeX.Core/Legality/LearnSource/MoveResult.cs b/PKHeX.Core/Legality/LearnSource/MoveResult.cs index 135f99dcd..70df9f1be 100644 --- a/PKHeX.Core/Legality/LearnSource/MoveResult.cs +++ b/PKHeX.Core/Legality/LearnSource/MoveResult.cs @@ -8,26 +8,32 @@ namespace PKHeX.Core; /// /// Info about the game it was learned in. /// Evolution stage index within the evolution list it existed in. -/// Rough indicator of generation the was. +/// Rough indicator of generation the was. /// Optional value used when the move is not legal, to indicate that another move ID should have been in that move slot instead. -public readonly record struct MoveResult(MoveLearnInfo Info, byte EvoStage = 0, byte Generation = 0, ushort Expect = 0) +public readonly record struct MoveResult(MoveLearnInfo Info, byte EvoStage = 0, EntityContext Context = 0, ushort Expect = 0) { public bool IsParsed => this != default; public bool Valid => Info.Method.IsValid; - internal MoveResult(LearnMethod method, LearnEnvironment game) : this(new MoveLearnInfo(method, game), Generation: game.Generation) { } + internal MoveResult(LearnMethod method, LearnEnvironment game) : this(new MoveLearnInfo(method, game), Context: game.Context) { } private MoveResult(LearnMethod method) : this(new MoveLearnInfo(method, LearnEnvironment.None)) { } public string Summary(in LegalityLocalizationContext ctx) { var sb = new StringBuilder(48); + Append(ctx, sb); + return sb.ToString(); + } + + public void Append(in LegalityLocalizationContext ctx, StringBuilder sb) + { Info.Summarize(sb, ctx.Settings.Moves); if (Info.Method.HasExpectedMove()) { var name = ctx.GetMoveName(Expect); var str = ctx.Settings.Lines.MoveFExpectSingle_0; sb.Append(' ').AppendFormat(str, name); - return sb.ToString(); + return; } var la = ctx.Analysis; @@ -36,14 +42,13 @@ public string Summary(in LegalityLocalizationContext ctx) var detail = GetDetail(history); if (detail.Species == 0) - return sb.ToString(); + return; if (detail.Species == current.Species && detail.Form == current.Form) - return sb.ToString(); + return; sb.Append(' ').Append(ctx.GetSpeciesName(detail.Species)); if (detail.Form != current.Form) - sb.Append('-').Append(detail.Form); - return sb.ToString(); + sb.Append('-').Append(ctx.GetFormName(detail.Species, detail.Form, Info.Environment.Context)); } private EvoCriteria GetDetail(EvolutionHistory history) diff --git a/PKHeX.Core/Legality/LegalityAnalysis.cs b/PKHeX.Core/Legality/LegalityAnalysis.cs index a02c8b238..2fcea81a5 100644 --- a/PKHeX.Core/Legality/LegalityAnalysis.cs +++ b/PKHeX.Core/Legality/LegalityAnalysis.cs @@ -199,7 +199,7 @@ private void ParsePK1() Level.Verify(this); Level.VerifyG1(this); Trainer.VerifyOTGB(this); - MiscValues.VerifyMiscG1(this); + MiscValues.VerifyMiscG12(this); MovePP.Verify(this); if (Entity.Format == 2) Item.Verify(this); @@ -332,7 +332,6 @@ private void UpdateChecks() return; HyperTraining.Verify(this); - MiscValues.VerifyVersionEvolution(this); Trash.Verify(this); if (format < 8) diff --git a/PKHeX.Core/Legality/Localization/LegalityLocalizationContext.cs b/PKHeX.Core/Legality/Localization/LegalityLocalizationContext.cs index 8fdaa0d6f..916bec268 100644 --- a/PKHeX.Core/Legality/Localization/LegalityLocalizationContext.cs +++ b/PKHeX.Core/Legality/Localization/LegalityLocalizationContext.cs @@ -42,6 +42,7 @@ public static LegalityLocalizationContext Create(LegalityAnalysis la, string lan public string GetConsoleRegion3DS(int index) => GetSafe(Strings.console3ds, index); public string GetRibbonName(RibbonIndex index) => Strings.Ribbons.GetNameSafe($"Ribbon{index}", out var result) ? result : index.ToString(); public string GetLanguageName(int index) => GetSafe(Strings.languageNames, index); + public string GetFormName(ushort species, byte form, EntityContext context) => FormConverter.GetStringFromForm(species, form, Strings, context); private static string GetSafe(ReadOnlySpan arr, int index) { @@ -142,12 +143,12 @@ private string GetMemory(CheckResult chk, string template, LegalityCheckResultCo >= MAX => throw new ArgumentOutOfRangeException(nameof(code), code, null), }; - public string FormatMove(in MoveResult move, int index, byte currentFormat) + public string FormatMove(in MoveResult move, int index, EntityContext current) { var result = Format(move, index, Settings.Moves.FormatMove); - var gen = move.Generation; - if (currentFormat != gen && gen != 0) - result += $" [Gen{gen}]"; + var original = move.Context; + if (current != original && original != 0) + result += $" [{original}]"; return result; } diff --git a/PKHeX.Core/Legality/Restrictions/GBRestrictions.cs b/PKHeX.Core/Legality/Restrictions/GBRestrictions.cs index b807a05cd..4e741e875 100644 --- a/PKHeX.Core/Legality/Restrictions/GBRestrictions.cs +++ b/PKHeX.Core/Legality/Restrictions/GBRestrictions.cs @@ -198,7 +198,7 @@ public static TimeCapsuleEvaluation IsTimeCapsuleTransferred(PK1 pk, ReadOnlySpa if (rate == 0) return Transferred12; - if (MoveInfo.IsAnyFromGeneration(2, moves)) + if (MoveInfo.IsAnyFromGeneration(EntityContext.Gen2, moves)) { if (pk is {CatchRate: not 0} && !ItemConverter.IsCatchRateHeldItem(pk.CatchRate)) return BadCatchRate; diff --git a/PKHeX.Core/Legality/Restrictions/Memories/Memories.cs b/PKHeX.Core/Legality/Restrictions/Memories/Memories.cs index 00c2e1222..d75fba7f8 100644 --- a/PKHeX.Core/Legality/Restrictions/Memories/Memories.cs +++ b/PKHeX.Core/Legality/Restrictions/Memories/Memories.cs @@ -33,9 +33,9 @@ public static MemoryArgType GetMemoryArgType(byte memory, int memoryGen) return (MemoryArgType)type; } - public static MemoryContext GetContext(EntityContext context) => context.Generation switch + public static MemoryContext GetContext(EntityContext context) => context switch { - <=7 => MemoryContext6.Instance, + EntityContext.Gen6 or EntityContext.Gen7 => MemoryContext6.Instance, _ => MemoryContext8.Instance, }; diff --git a/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilter.cs b/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilter.cs index f30e09530..4239eef3b 100644 --- a/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilter.cs +++ b/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilter.cs @@ -128,9 +128,9 @@ private static bool IsFilteredLookBack(ReadOnlySpan message, EntityContext return true; } - var generation = original.Generation; - if (generation > 7 || original is EntityContext.Gen7b) + if (original.IsEraHOME || original is EntityContext.Gen7b) { + // Already checked above -- done. type = WordFilterType.None; return false; } @@ -141,7 +141,7 @@ private static bool IsFilteredLookBack(ReadOnlySpan message, EntityContext return true; } - if (generation == 5 && WordFilter5.IsFiltered(message, out regMatch)) + if (original == EntityContext.Gen5 && WordFilter5.IsFiltered(message, out regMatch)) { type = WordFilterType.Gen5; return true; diff --git a/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilterType.cs b/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilterType.cs index 34c156739..b865dd780 100644 --- a/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilterType.cs +++ b/PKHeX.Core/Legality/Restrictions/WordFilter/WordFilterType.cs @@ -42,10 +42,10 @@ public static class WordFilterTypeExtensions public static WordFilterType GetName(EntityContext type) => type.Console switch { GameConsole.NX => WordFilterType.NintendoSwitch, - _ => type.Generation switch + _ => type switch { - 5 => WordFilterType.Gen5, - 6 or 7 => WordFilterType.Nintendo3DS, + EntityContext.Gen5 => WordFilterType.Gen5, + EntityContext.Gen6 or EntityContext.Gen7 => WordFilterType.Nintendo3DS, _ => WordFilterType.None, }, }; diff --git a/PKHeX.Core/Legality/Tables/FormInfo.cs b/PKHeX.Core/Legality/Tables/FormInfo.cs index 5683aa05b..629cad685 100644 --- a/PKHeX.Core/Legality/Tables/FormInfo.cs +++ b/PKHeX.Core/Legality/Tables/FormInfo.cs @@ -145,7 +145,7 @@ public static bool IsFormChangeable(ushort species, byte oldForm, byte newForm, { if (origin == EntityContext.Gen5) return true; // B/W or B2/W2 change via seasons - if (current.Generation >= 8) + if (current.IsEraHOME) return true; // Via S/V change via in-game province on startup. } return false; diff --git a/PKHeX.Core/Legality/Verifiers/Egg/EggVerifier.cs b/PKHeX.Core/Legality/Verifiers/Egg/EggVerifier.cs new file mode 100644 index 000000000..835e3079d --- /dev/null +++ b/PKHeX.Core/Legality/Verifiers/Egg/EggVerifier.cs @@ -0,0 +1,77 @@ +using static PKHeX.Core.LegalityCheckResultCode; +using static PKHeX.Core.CheckIdentifier; + +namespace PKHeX.Core; + +internal sealed class EggVerifier : Verifier +{ + protected override CheckIdentifier Identifier => Misc; + + public override void Verify(LegalityAnalysis data) + { + var pk = data.Entity; + if (pk.IsEgg) + Verify(data, pk); + } + + internal void Verify(LegalityAnalysis data, PKM pk) + { + VerifyCommon(data, pk); + + // No egg have contest stats from the encounter. + if (pk is IContestStatsReadOnly s && s.HasContestStats()) + data.AddLine(GetInvalid(Egg, EggContest)); + + // Cannot transfer eggs across contexts (must be hatched). + var e = data.EncounterOriginal; + if (e.Context != pk.Context) + data.AddLine(GetInvalid(Egg, TransferEggVersion)); + + switch (pk) + { + // Side Game: No Eggs + case SK2 or CK3 or XK3 or BK4 or RK4 when e.Context == pk.Context: + data.AddLine(GetInvalid(Egg, TransferEggVersion)); + break; + + // All Eggs are Japanese and flagged specially for localized string + case PK3 when pk.Language != 1: + data.AddLine(GetInvalid(Egg, OTLanguageShouldBe_0, (byte)LanguageID.Japanese)); + break; + } + + if (pk is IHomeTrack { HasTracker: true }) + data.AddLine(GetInvalid(TransferTrackerShouldBeZero)); + } + + internal void VerifyCommon(LegalityAnalysis data, PKM pk) + { + var enc = data.EncounterMatch; + if (!EggStateLegality.GetIsEggHatchCyclesValid(pk, enc)) + data.AddLine(GetInvalid(Egg, EggHatchCycles)); + + if (pk.Format >= 6 && enc is IEncounterEgg && !MovesMatchRelearn(pk)) + data.AddLine(GetInvalid(Egg, MovesShouldMatchRelearnMoves)); + + if (pk is ITechRecord record) + { + if (record.GetMoveRecordFlagAny()) + data.AddLine(GetInvalid(Egg, EggRelearnFlags)); + if (pk.StatNature != pk.Nature) + data.AddLine(GetInvalid(Egg, EggNature)); + } + } + + private static bool MovesMatchRelearn(PKM pk) + { + if (pk.Move1 != pk.RelearnMove1) + return false; + if (pk.Move2 != pk.RelearnMove2) + return false; + if (pk.Move3 != pk.RelearnMove3) + return false; + if (pk.Move4 != pk.RelearnMove4) + return false; + return true; + } +} diff --git a/PKHeX.Core/Legality/Verifiers/LevelVerifier.cs b/PKHeX.Core/Legality/Verifiers/LevelVerifier.cs index 36c65c6ba..9655d2349 100644 --- a/PKHeX.Core/Legality/Verifiers/LevelVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/LevelVerifier.cs @@ -124,9 +124,9 @@ private static bool IsTradeEvolutionRequired(LegalityAnalysis data, IEncounterTe var moves = data.Info.Moves; // Gen2 stuff can be traded between Gen2 games holding an Everstone, assuming it hasn't been transferred to Gen1 for special moves. if (enc.Generation == 2) - return MoveInfo.IsAnyFromGeneration(1, moves); + return MoveInfo.IsAnyFromGeneration(EntityContext.Gen1, moves); // Gen1 stuff can only be un-evolved if it was never traded from the OT. - if (MoveInfo.IsAnyFromGeneration(2, moves)) + if (MoveInfo.IsAnyFromGeneration(EntityContext.Gen2, moves)) return true; // traded to Gen2 for special moves if (pk.Format != 1) return true; // traded to Gen2 (current state) diff --git a/PKHeX.Core/Legality/Verifiers/TransferVerifier.cs b/PKHeX.Core/Legality/Verifiers/TransferVerifier.cs index 45a31778b..884c49572 100644 --- a/PKHeX.Core/Legality/Verifiers/TransferVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/TransferVerifier.cs @@ -200,9 +200,9 @@ public void VerifyVCEncounter(PKM pk, IEncounterTemplate original, EncounterTran // Flag Moves that cannot be transferred if (original is EncounterStatic2 { IsDizzyPunchEgg: true }) // Dizzy Punch Gifts - FlagIncompatibleTransferMove(pk, data.Info.Moves, 146, 2); // can't have Dizzy Punch at all + FlagIncompatibleTransferMove(pk, data.Info.Moves, 146, EntityContext.Gen2); // can't have Dizzy Punch at all - bool checkShiny = pk.VC2 || original.Generation == 2 || MoveInfo.IsAnyFromGeneration(2, data.Info.Moves); + bool checkShiny = pk.VC2 || original.Generation == 2 || MoveInfo.IsAnyFromGeneration(EntityContext.Gen2, data.Info.Moves); if (!checkShiny) return; @@ -220,13 +220,13 @@ public void VerifyVCEncounter(PKM pk, IEncounterTemplate original, EncounterTran } } - private static void FlagIncompatibleTransferMove(PKM pk, Span parse, ushort move, byte generation) + private static void FlagIncompatibleTransferMove(PKM pk, Span parse, ushort move, EntityContext context) { int index = pk.GetMoveIndex(move); if (index < 0) return; // doesn't have move - if (parse[index].Generation == generation) // not obtained from a future gen + if (parse[index].Context == context) // not obtained from a future gen parse[index] = MoveResult.Unobtainable(0); } } diff --git a/PKHeX.Core/Moves/MoveInfo.cs b/PKHeX.Core/Moves/MoveInfo.cs index 53f9583a2..fd5d66a04 100644 --- a/PKHeX.Core/Moves/MoveInfo.cs +++ b/PKHeX.Core/Moves/MoveInfo.cs @@ -243,11 +243,11 @@ private static byte GetType(ushort move, ReadOnlySpan types) return types[move]; } - public static bool IsAnyFromGeneration(byte generation, ReadOnlySpan moves) + public static bool IsAnyFromGeneration(EntityContext context, ReadOnlySpan moves) { foreach (var move in moves) { - if (move.Generation == generation) + if (move.Context == context) return true; } return false; diff --git a/PKHeX.Core/MysteryGifts/MysteryUtil.cs b/PKHeX.Core/MysteryGifts/MysteryUtil.cs index 3cb101e45..556b82b25 100644 --- a/PKHeX.Core/MysteryGifts/MysteryUtil.cs +++ b/PKHeX.Core/MysteryGifts/MysteryUtil.cs @@ -61,7 +61,7 @@ public string GetTitleFromIndex(GameStrings strings) { args[0] = strings.Species[gift.Species]; // 1: category (e.g. "Victory Pokémon" for Victini) - args[2] = FormConverter.GetStringFromForm(gift.Form, strings, gift.Species, GameInfo.GenderSymbolASCII, gift.Context); + args[2] = FormConverter.GetStringFromForm(gift.Species, gift.Form, strings, GameInfo.GenderSymbolASCII, gift.Context); args[3] = gift.OriginalTrainerName; args[4] = strings.Move[gift.Moves.Move1]; args[5] = strings.Move[gift.Moves.Move2]; diff --git a/PKHeX.Core/PKM/Interfaces/IFormArgument.cs b/PKHeX.Core/PKM/Interfaces/IFormArgument.cs index be7164e94..f59dfa4bf 100644 --- a/PKHeX.Core/PKM/Interfaces/IFormArgument.cs +++ b/PKHeX.Core/PKM/Interfaces/IFormArgument.cs @@ -114,7 +114,7 @@ public static void ChangeFormArgument(this IFormArgument f, ushort species, byte var max = GetFormArgumentMax(species, form, context); f.FormArgumentRemain = (byte)value; - if (value == max || (value == 0 && species is (int)Hoopa && form == 1 && context.Generation >= 8)) + if (value == max || (value == 0 && species is (int)Hoopa && form == 1 && context.IsEraHOME)) { f.FormArgumentElapsed = f.FormArgumentMaximum = 0; return; @@ -132,31 +132,27 @@ public static void ChangeFormArgument(this IFormArgument f, ushort species, byte /// Entity Species /// Entity Form /// Context to check with. - public static uint GetFormArgumentMax(ushort species, byte form, EntityContext context) + public static uint GetFormArgumentMax(ushort species, byte form, EntityContext context) => species switch { - var gen = context.Generation; - return species switch - { - (int)Furfrou when form != 0 => 5, - (int)Hoopa when form == 1 => 3, - (int)Yamask when form == 1 => 9999, - (int)Runerigus when form == 0 => 9999, - (int)Alcremie => (uint)AlcremieDecoration.Ribbon, - (int)Qwilfish when form == 1 && gen >= 8 => 9999, - (int)Overqwil => 9999, // 20 - (int)Stantler or (int)Wyrdeer when gen >= 8 => 9999, - (int)Basculin when form == 2 => 9999, // 294 - (int)Basculegion => 9999, // 294 - (int)Primeape or (int)Annihilape when gen >= 8 => 9999, - (int)Bisharp or (int)Kingambit when gen >= 8 => 9999, - (int)Gimmighoul => 998, - (int)Gholdengo => 999, - (int)Koraidon or (int)Miraidon => 1, - (int)Farfetchd when form == 1 && gen >= 8 => 9999, - (int)Sirfetchd when gen >= 8 => 9999, - _ => 0, - }; - } + (int)Furfrou when form != 0 => 5, + (int)Hoopa when form == 1 => 3, + (int)Yamask when form == 1 => 9999, + (int)Runerigus when form == 0 => 9999, + (int)Alcremie => (uint)AlcremieDecoration.Ribbon, + (int)Qwilfish when form == 1 && context.IsEraHOME => 9999, + (int)Overqwil => 9999, // 20 + (int)Stantler or (int)Wyrdeer when context.IsEraHOME => 9999, + (int)Basculin when form == 2 => 9999, // 294 + (int)Basculegion => 9999, // 294 + (int)Primeape or (int)Annihilape when context.IsEraHOME => 9999, + (int)Bisharp or (int)Kingambit when context.IsEraHOME => 9999, + (int)Gimmighoul => 998, + (int)Gholdengo => 999, + (int)Koraidon or (int)Miraidon => 1, + (int)Farfetchd when form == 1 && context.IsEraHOME => 9999, + (int)Sirfetchd when context.IsEraHOME => 9999, + _ => 0, + }; /// /// Gets the minimum value the value can be to satisfy an evolution requirement. diff --git a/PKHeX.Core/PKM/Searching/SearchSettings.cs b/PKHeX.Core/PKM/Searching/SearchSettings.cs index 4a02cb79e..de3b98fe3 100644 --- a/PKHeX.Core/PKM/Searching/SearchSettings.cs +++ b/PKHeX.Core/PKM/Searching/SearchSettings.cs @@ -225,16 +225,16 @@ private bool FilterResultEgg(PKM pk) public ReadOnlyMemory GetVersions(SaveFile sav, GameVersion fallback) { - if (Version > 0) + if (Version.IsValidSavedVersion()) return new[] {Version}; - return Generation switch + return Context switch { - 1 when !ParseSettings.AllowGen1Tradeback => [RD, BU, GN, YW], - 2 when sav is SAV2 {Korean: true} => [GD, SI], - 1 or 2 => [RD, BU, GN, YW, /* */ GD, SI, C], + EntityContext.Gen1 when !ParseSettings.AllowGen1Tradeback => [RD, BU, GN, YW], + EntityContext.Gen2 when sav is SAV2 {Korean: true} => [GD, SI], + EntityContext.Gen1 or EntityContext.Gen2 => [RD, BU, GN, YW, /* */ GD, SI, C], - _ when fallback.Generation == Generation => GameUtil.GetVersionsWithinRange(sav, Generation).ToArray(), + _ when fallback.Context == Context => GameUtil.GetVersionsWithinRange(sav, Context).ToArray(), _ => GameUtil.GameVersions, }; } diff --git a/PKHeX.Core/PKM/Searching/SearchUtil.cs b/PKHeX.Core/PKM/Searching/SearchUtil.cs index 98d4b7826..91aade4fd 100644 --- a/PKHeX.Core/PKM/Searching/SearchUtil.cs +++ b/PKHeX.Core/PKM/Searching/SearchUtil.cs @@ -30,10 +30,9 @@ public static class SearchUtil private static bool CanReachContext(PKM pk, EntityContext context) { - var generation = context.Generation; - if (generation <= 2) + if (context.IsEraGameBoy) return pk.Format <= 2; // 1-2 can reach 1-2 - if (generation <= 6) + if (context.IsEraPre3DS) return pk.Format >= 3; // 3-6 can reach 3-6 return true; // 7+ can reach all contexts } diff --git a/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs b/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs index 2535c197f..5df6dda1c 100644 --- a/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs +++ b/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs @@ -11,6 +11,10 @@ namespace PKHeX.Core; /// public static class FormConverter { + /// + public static string[] GetFormList(ushort species, IReadOnlyList types, IReadOnlyList forms, EntityContext context) + => GetFormList(species, types, forms, GameInfo.GenderSymbolUnicode, context); + /// /// Gets a list of forms that the species can have. /// @@ -1122,19 +1126,22 @@ public static bool IsCosplayPikachu(ReadOnlySpan formName, ReadOnlySpan /// Converts a Form ID to string. /// + /// Species ID the form belongs to /// Form to get the form name of /// Localized string source to fetch with - /// Species ID the form belongs to /// List of genders names /// Format the form name should appear in - public static string GetStringFromForm(byte form, GameStrings strings, ushort species, IReadOnlyList genders, EntityContext context) + public static string GetStringFromForm(ushort species, byte form, GameStrings strings, IReadOnlyList genders, EntityContext context) { var forms = GetFormList(species, strings.Types, strings.forms, genders, context); var result = form >= forms.Length ? string.Empty : forms[form]; return result; } -} + /// + public static string GetStringFromForm(ushort species, byte form, GameStrings strings, EntityContext context) + => GetStringFromForm(species, form, strings, GameInfo.GenderSymbolUnicode, context); +} public sealed record MegaFormNames { public required string Regular { get; init; } diff --git a/PKHeX.Core/PKM/Util/EntityContext.cs b/PKHeX.Core/PKM/Util/EntityContext.cs index f6dc09e08..7712c2bd3 100644 --- a/PKHeX.Core/PKM/Util/EntityContext.cs +++ b/PKHeX.Core/PKM/Util/EntityContext.cs @@ -104,6 +104,12 @@ public static class EntityContextExtensions _ => throw new ArgumentOutOfRangeException(nameof(value), value, null), }; + public bool IsEraGameBoy => value is Gen1 or Gen2; + public bool IsEraPre3DS => value.Generation is (>= 1 and <= 5); + public bool IsEraPreSwitch => value.Generation is (>= 1 and <= 7); + public bool IsEraHOME => value.Generation >= 8; + public bool IsSquareShinyDifferentiated => value is Gen8; + /// /// Determines whether Mega Pokémon forms exist in the specified . /// diff --git a/PKHeX.Core/PKM/Util/EntityFileExtension.cs b/PKHeX.Core/PKM/Util/EntityFileExtension.cs index edd0a270b..3c33e6b1c 100644 --- a/PKHeX.Core/PKM/Util/EntityFileExtension.cs +++ b/PKHeX.Core/PKM/Util/EntityFileExtension.cs @@ -95,8 +95,6 @@ private static int GetFormatFromExtension(char last, EntityContext prefer) { if (last is >= '1' and <= '9') return last - '0'; - if (prefer.Generation <= 7 && last == 'x') - return 6; return (int)prefer; } diff --git a/PKHeX.Core/Saves/Substructures/Gen8/LA/MyItem8a.cs b/PKHeX.Core/Saves/Substructures/Gen8/LA/MyItem8a.cs index 6cdf1a974..536b004a6 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/LA/MyItem8a.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/LA/MyItem8a.cs @@ -1,5 +1,3 @@ -using System; - namespace PKHeX.Core; /// diff --git a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan4.cs b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan4.cs index 1ce245f7d..f28c02148 100644 --- a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan4.cs +++ b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan4.cs @@ -65,7 +65,7 @@ private void SetRegionFlag(int region, int index, bool value) public static string[] GetFormNames4Dex(ushort species) { - string[] formNames = FormConverter.GetFormList(species, GameInfo.Strings.types, GameInfo.Strings.forms, [], EntityContext.Gen4); + string[] formNames = FormConverter.GetFormList(species, GameInfo.Strings.types, GameInfo.Strings.forms, EntityContext.Gen4); if (species == (int)Species.Pichu) formNames = [MALE, FEMALE, formNames[1]]; // Spiky return formNames; diff --git a/PKHeX.Core/Saves/Util/Detection/SaveFileType.cs b/PKHeX.Core/Saves/Util/Detection/SaveFileType.cs index 1e4b2628f..d64fb556b 100644 --- a/PKHeX.Core/Saves/Util/Detection/SaveFileType.cs +++ b/PKHeX.Core/Saves/Util/Detection/SaveFileType.cs @@ -114,7 +114,5 @@ public static class SaveFileTypeExtensions Bulk7 => EntityContext.Gen7, _ => throw new ArgumentOutOfRangeException(nameof(type), type, null), }; - - public byte Generation => type.Context.Generation; } } diff --git a/PKHeX.Drawing.Misc/Util/WallpaperUtil.cs b/PKHeX.Drawing.Misc/Util/WallpaperUtil.cs index ad9a30a60..c2e05cd92 100644 --- a/PKHeX.Drawing.Misc/Util/WallpaperUtil.cs +++ b/PKHeX.Drawing.Misc/Util/WallpaperUtil.cs @@ -70,32 +70,32 @@ public static string GetWallpaperResourceName(GameVersion version, int index) SaveFileType.LGPE => string.Empty, - _ => type.Generation switch + _ => type.Context switch { - 3 => "rs", - 4 => "dp", - 5 => "bw", - 6 or 7 => "xy", + EntityContext.Gen3 => "rs", + EntityContext.Gen4 => "dp", + EntityContext.Gen5 => "bw", + EntityContext.Gen6 or EntityContext.Gen7 => "xy", // roughly equivalent, only use X/Y's because they don't force checker-boxes. _ => string.Empty, }, }; - private static string GetResourceSuffix(GameVersion version, int index) => version.Generation switch + private static string GetResourceSuffix(GameVersion version, int index) => version.Context switch { - 3 when version == E => "e", - 3 when FRLG.Contains(version) && index > 12 => "frlg", - 3 => "rs", + EntityContext.Gen3 when version == E => "e", + EntityContext.Gen3 when FRLG.Contains(version) && index > 12 => "frlg", + EntityContext.Gen3 => "rs", - 4 when index <= 16 => "dp", - 4 when version == Pt => "pt", - 4 when HGSS.Contains(version) => "hgss", + EntityContext.Gen4 when index <= 16 => "dp", + EntityContext.Gen4 when version == Pt => "pt", + EntityContext.Gen4 when HGSS.Contains(version) => "hgss", - 5 => B2W2.Contains(version) && index > 16 ? "b2w2" : "bw", - 6 => ORAS.Contains(version) && index > 16 ? "ao" : "xy", - 7 when !GG.Contains(version) => "xy", - 8 when !SWSH.Contains(version) => "bdsp", - 8 => "swsh", - 9 => "sv", + EntityContext.Gen5 => B2W2.Contains(version) && index > 16 ? "b2w2" : "bw", + EntityContext.Gen6 => ORAS.Contains(version) && index > 16 ? "ao" : "xy", + EntityContext.Gen7 => "xy", // roughly equivalent, only use X/Y's because they don't force checker-boxes. + EntityContext.Gen8b => "bdsp", + EntityContext.Gen8 => "swsh", + EntityContext.Gen9 => "sv", _ => string.Empty, }; } diff --git a/PKHeX.WinForms/Controls/PKM Editor/ContestStat.cs b/PKHeX.WinForms/Controls/PKM Editor/ContestStat.cs index c20a0c780..792fb36e4 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/ContestStat.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/ContestStat.cs @@ -64,7 +64,7 @@ public void ToggleInterface(object o, EntityContext context) } Visible = TabStop = true; - bool smart = context.Generation < 6; + bool smart = context.IsEraPre3DS; Label_Smart.Visible = smart; // show "Smart" for Gen3-5 Label_Clever.Visible = !smart; // show "Clever" for Gen6+ } diff --git a/PKHeX.WinForms/Controls/Slots/SummaryPreviewer.cs b/PKHeX.WinForms/Controls/Slots/SummaryPreviewer.cs index 0819b2ef7..b21724301 100644 --- a/PKHeX.WinForms/Controls/Slots/SummaryPreviewer.cs +++ b/PKHeX.WinForms/Controls/Slots/SummaryPreviewer.cs @@ -178,7 +178,7 @@ public static string AppendLegalityHint(in LegalityLocalizationContext la, strin var chk = analysis.Info.Moves[i]; if (chk.Valid) continue; - var hint = la.FormatMove(chk, i, la.Analysis.Info.Entity.Format); + var hint = la.FormatMove(chk, i, la.Analysis.Info.Entity.Context); return Join(line, hint); } @@ -187,7 +187,7 @@ public static string AppendLegalityHint(in LegalityLocalizationContext la, strin var chk = analysis.Info.Relearn[i]; if (chk.Valid) continue; - var hint = la.FormatMove(chk, i, la.Analysis.Info.Entity.Format); + var hint = la.FormatMove(chk, i, la.Analysis.Info.Entity.Context); return Join(line, hint); } diff --git a/PKHeX.WinForms/Subforms/PKM Editors/Text.cs b/PKHeX.WinForms/Subforms/PKM Editors/Text.cs index da0c91921..4ffee417e 100644 --- a/PKHeX.WinForms/Subforms/PKM Editors/Text.cs +++ b/PKHeX.WinForms/Subforms/PKM Editors/Text.cs @@ -229,7 +229,7 @@ private static NumericUpDown GetNUD(byte min, byte max, bool hex) => new() { EntityContext.Gen5 => SpecialCharsGen5, EntityContext.Gen6 or EntityContext.Gen7 or EntityContext.Gen7b => SpecialCharsGen67, - _ when context.Generation >= 8 => SpecialCharsGen8, + _ when !context.IsEraPreSwitch => SpecialCharsGen8, _ => [], // Undocumented };