using System; using static PKHeX.Core.LegalityCheckResultCode; namespace PKHeX.Core; /// /// Value object that contains the context for localization of legality checks. /// public readonly ref struct LegalityLocalizationContext { public required LegalityAnalysis Analysis { get; init; } public required LegalityLocalizationSet Settings { get; init; } public GameStrings Strings => Settings.Strings; /// /// Creates a complete with proper localization initialization. /// /// Legality analysis /// Export settings /// Fully initialized localization context public static LegalityLocalizationContext Create(LegalityAnalysis la, LegalityLocalizationSet settings) => new() { Analysis = la, Settings = settings, }; /// /// Creates a complete using the specified language. /// /// Legality analysis /// Language code /// Fully initialized localization context public static LegalityLocalizationContext Create(LegalityAnalysis la, string language = GameLanguage.DefaultLanguage) => Create(la, LegalityLocalizationSet.GetLocalization(language)); public string GetRibbonMessage(LegalityCheckResultCode code) => RibbonVerifier.GetMessage(Analysis, Strings.Ribbons, code); public string GetStatName(int displayIndex) => GetSafe(Settings.General.StatNames, displayIndex); public string GetMoveName(ushort move) => GetSafe(Strings.movelist, move); public string GetItemName(ushort item) => GetSafe(Strings.itemlist, item); public string GetSpeciesName(ushort species) => GetSafe(Strings.specieslist, species); 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) { if ((uint)index >= arr.Length) return string.Empty; return arr[index]; } public string GetTrainer(int index) => index switch { 0 => Settings.General.OriginalTrainer, 1 => Settings.General.HandlingTrainer, _ => throw new ArgumentOutOfRangeException(nameof(index), $"Invalid Trainer argument: {index}"), }; /// /// Converts a to its corresponding localized string, /// applying formatting with the provided argument if needed. /// /// Raw check value for formatting the string. /// Include Identifier /// The localized string from , with formatting applied if needed /// Thrown when the enum value doesn't have a corresponding string public string Humanize(in CheckResult chk, bool verbose = false) { var str = GetInternalString(chk); var format = Settings.Lines.F0_1; if (verbose) str = string.Format(format, chk.Identifier.ToString(), str); return string.Format(format, Settings.Description(chk.Judgement), str); } private string GetInternalString(CheckResult chk) { var code = chk.Result; if (code is External) return ExternalLegalityCheck.Localize(chk, Settings, Analysis); var template = code.GetTemplate(Settings.Lines); if (code < FirstWithArgument) return template; if (code.IsArgument) return string.Format(template, chk.Argument); if (code.IsArgument2) return string.Format(template, chk.Argument, chk.Argument2); if (code.IsMove) return string.Format(template, GetMoveName(chk.Argument)); if (code.IsItem) return string.Format(template, GetItemName(chk.Argument)); if (code.IsLanguage) return string.Format(template, GetLanguageName(chk.Argument), GetLanguageName(Analysis.Entity.Language)); if (code.IsMemory) return GetMemory(chk, template, code); // Complex codes may require additional context or arguments. return GetComplex(chk, template, code); } private string GetMemory(CheckResult chk, string template, LegalityCheckResultCode code) { if (code < FirstMemoryWithValue) return string.Format(template, GetTrainer(chk.Argument)); if (code is MemoryArgBadItem_H1) return string.Format(template, GetTrainer(chk.Argument), GetSpeciesName(chk.Argument2)); if (code is MemoryArgBadMove_H1) return string.Format(template, GetTrainer(chk.Argument), GetMoveName(chk.Argument2)); if (code is MemoryArgBadSpecies_H1) return string.Format(template, GetTrainer(chk.Argument), GetSpeciesName(chk.Argument2)); return string.Format(template, GetTrainer(chk.Argument), chk.Argument2); } private string GetComplex(CheckResult chk, string format, LegalityCheckResultCode code) => code switch { < FirstComplex => format, // why are you even here? RibbonsInvalid_0 => string.Format(format, GetRibbonMessage(code)), RibbonsMissing_0 => string.Format(format, GetRibbonMessage(code)), WordFilterFlaggedPattern_01 => string.Format(format, WordFilter.GetPattern((WordFilterType)chk.Argument, chk.Argument2), (WordFilterType)chk.Argument), WordFilterInvalidCharacter_0 => string.Format(format, chk.Argument, chk.Argument.ToString("X4")), AwakenedStatGEQ_01 => string.Format(format, chk.Argument, GetStatName(chk.Argument2)), GanbaruStatLEQ_01 => string.Format(format, chk.Argument, GetStatName(chk.Argument2)), OTLanguageCannotTransferToConsoleRegion_0 => string.Format(format, GetConsoleRegion3DS(chk.Argument)), EncTradeShouldHaveEvolvedToSpecies_0 => string.Format(format, GetSpeciesName(chk.Argument)), MoveEvoFCombination_0 => string.Format(format, GetSpeciesName(chk.Argument)), HintEvolvesToSpecies_0 => string.Format(format, GetSpeciesName(chk.Argument)), RibbonMarkingInvalid_0 => string.Format(format, GetRibbonName((RibbonIndex)chk.Argument)), RibbonMarkingMissing_0 => string.Format(format, GetRibbonName((RibbonIndex)chk.Argument)), RibbonMarkingAffixed_0 => string.Format(format, GetRibbonName((RibbonIndex)chk.Argument)), StoredSlotSourceInvalid_0 => string.Format(format, (StorageSlotSource)chk.Argument), HintEvolvesToRareForm_0 => string.Format(format, chk.Argument == 1), FormInvalidRangeLEQ_0F => string.Format(format, chk.Argument, Analysis.Entity.Form), OTLanguageShouldBe_0or1 => string.Format(format, GetLanguageName(chk.Argument), GetLanguageName(chk.Argument2), GetLanguageName(Analysis.Entity.Language)), G6SuperTrainBagHitsInvalid_012 => string.Format(format, (Analysis.Entity as PK6)?.TrainingBagHits ?? 0, chk.Argument, chk.Argument2), >= MAX => throw new ArgumentOutOfRangeException(nameof(code), code, null), }; public string FormatMove(in MoveResult move, int index, EntityContext current) { var result = Format(move, index, Settings.Moves.FormatMove); var original = move.Context; if (current != original && original != 0) result += $" [{original}]"; return result; } public string FormatRelearn(in MoveResult move, int index) => Format(move, index, Settings.Moves.FormatRelearn); private string Format(in MoveResult move, int index, string format) => string.Format(format, Settings.Description(move.Judgement), index, move.Summary(this)); }