diff --git a/PKHeX.Core/Editing/Bulk/BatchEditing.cs b/PKHeX.Core/Editing/Bulk/BatchEditing.cs index 8a20e3862..530148bca 100644 --- a/PKHeX.Core/Editing/Bulk/BatchEditing.cs +++ b/PKHeX.Core/Editing/Bulk/BatchEditing.cs @@ -79,7 +79,7 @@ public static bool TryGetHasProperty(PKM pk, string name, out PropertyInfo pi) /// Property Name to fetch the type for /// Type index (within . Leave empty (0) for a nonspecific format. /// Short name of the property's type. - public static string GetPropertyType(string propertyName, int typeIndex = 0) + public static string? GetPropertyType(string propertyName, int typeIndex = 0) { if (CustomProperties.Contains(propertyName)) return "Custom"; @@ -164,6 +164,8 @@ public static bool IsFilterMatch(IEnumerable filters, object return false; try { + if (pi == null) + continue; if (pi.IsValueEqual(obj, cmd.PropertyValue) == cmd.Evaluator) continue; } @@ -248,7 +250,7 @@ private static ModifyResult SetPKMProperty(StringInstruction cmd, PKMInfo info, if (cmd.PropertyValue == CONST_SUGGEST) return SetSuggestedPKMProperty(cmd.PropertyName, info); if (cmd.PropertyValue == CONST_RAND && cmd.PropertyName == nameof(PKM.Moves)) - return SetMoves(pk, pk.GetMoveSet(true, info.Legality)); + return SetMoves(pk, pk.GetMoveSet(info.Legality, true)); if (SetComplexProperty(pk, cmd)) return ModifyResult.Modified; @@ -321,7 +323,7 @@ private static bool IsIdentifierFiltered(StringInstruction cmd, PKM pk) if (cmd.PropertyName != IdentifierContains) return false; - bool result = pk.Identifier.Contains(cmd.PropertyValue); + bool result = pk.Identifier?.Contains(cmd.PropertyValue) ?? false; return result == cmd.Evaluator; } @@ -451,7 +453,7 @@ private static bool SetComplexProperty(PKM pk, StringInstruction cmd) else if (cmd.PropertyName == nameof(PKM.PID) && cmd.PropertyValue == CONST_SHINY) pk.SetShiny(); else if (cmd.PropertyName == nameof(PKM.Species) && cmd.PropertyValue == "0") - pk.Data = new byte[pk.Data.Length]; + Array.Clear(pk.Data, 0, pk.Data.Length); else if (cmd.PropertyName.StartsWith("IV") && cmd.PropertyValue == CONST_RAND) SetRandomIVs(pk, cmd); else if (cmd.PropertyName == nameof(PKM.IsNicknamed) && string.Equals(cmd.PropertyValue, "false", StringComparison.OrdinalIgnoreCase)) diff --git a/PKHeX.Core/Editing/Bulk/PKMInfo.cs b/PKHeX.Core/Editing/Bulk/PKMInfo.cs index 5852ba6a5..f1e8a1845 100644 --- a/PKHeX.Core/Editing/Bulk/PKMInfo.cs +++ b/PKHeX.Core/Editing/Bulk/PKMInfo.cs @@ -10,11 +10,11 @@ internal sealed class PKMInfo internal PKM pkm { get; } internal PKMInfo(PKM pk) { pkm = pk; } - private LegalityAnalysis la; - internal LegalityAnalysis Legality => la ?? (la = new LegalityAnalysis(pkm)); + private LegalityAnalysis? la; + internal LegalityAnalysis Legality => la ??= new LegalityAnalysis(pkm); public bool Legal => Legality.Valid; internal IReadOnlyList SuggestedRelearn => Legality.GetSuggestedRelearn(); - internal EncounterStatic SuggestedEncounter => Legality.GetSuggestedMetInfo(); + internal EncounterStatic? SuggestedEncounter => Legality.GetSuggestedMetInfo(); } } \ No newline at end of file diff --git a/PKHeX.Core/Editing/Bulk/StringInstruction.cs b/PKHeX.Core/Editing/Bulk/StringInstruction.cs index 108c02077..ea352fd6d 100644 --- a/PKHeX.Core/Editing/Bulk/StringInstruction.cs +++ b/PKHeX.Core/Editing/Bulk/StringInstruction.cs @@ -20,6 +20,12 @@ public sealed class StringInstruction public string PropertyValue { get; private set; } public bool Evaluator { get; private set; } + public StringInstruction(string name, string value) + { + PropertyName = name; + PropertyValue = value; + } + public void SetScreenedValue(string[] arr) { int index = Array.IndexOf(arr, PropertyValue); @@ -72,7 +78,7 @@ public static IEnumerable GetFilters(IEnumerable line let eval = line[0] == Require let split = line.Substring(1).Split(SplitInstruction) where split.Length == 2 && !string.IsNullOrWhiteSpace(split[0]) - select new StringInstruction { PropertyName = split[0], PropertyValue = split[1], Evaluator = eval }; + select new StringInstruction(split[0], split[1]) { Evaluator = eval }; } public static IEnumerable GetInstructions(IEnumerable lines) @@ -81,7 +87,7 @@ public static IEnumerable GetInstructions(IEnumerable return from line in raw select line.Split(SplitInstruction) into split where split.Length == 2 - select new StringInstruction { PropertyName = split[0], PropertyValue = split[1] }; + select new StringInstruction(split[0], split[1]); } /// diff --git a/PKHeX.Core/Editing/Bulk/StringInstructionSet.cs b/PKHeX.Core/Editing/Bulk/StringInstructionSet.cs index 2f07b0ec1..80810d500 100644 --- a/PKHeX.Core/Editing/Bulk/StringInstructionSet.cs +++ b/PKHeX.Core/Editing/Bulk/StringInstructionSet.cs @@ -13,23 +13,26 @@ public sealed class StringInstructionSet private const string SetSeparator = ";"; + public StringInstructionSet(IList filters, IList instructions) + { + Filters = filters; + Instructions = instructions; + } + + public StringInstructionSet(ICollection set) + { + Filters = StringInstruction.GetFilters(set).ToList(); + Instructions = StringInstruction.GetInstructions(set).ToList(); + } + public static IEnumerable GetBatchSets(IList lines) { int start = 0; while (start < lines.Count) { var list = lines.Skip(start).TakeWhile(_ => !lines[start++].StartsWith(SetSeparator)).ToList(); - yield return GetBatchSet(list); + yield return new StringInstructionSet(list); } } - - private static StringInstructionSet GetBatchSet(ICollection set) - { - return new StringInstructionSet - { - Filters = StringInstruction.GetFilters(set).ToList(), - Instructions = StringInstruction.GetInstructions(set).ToList(), - }; - } } } diff --git a/PKHeX.Core/Editing/CommonEdits.cs b/PKHeX.Core/Editing/CommonEdits.cs index a74a69edd..0f7b04f4c 100644 --- a/PKHeX.Core/Editing/CommonEdits.cs +++ b/PKHeX.Core/Editing/CommonEdits.cs @@ -597,6 +597,18 @@ public static void MaximizeLevel(this PKM pkm) pb.ResetCP(); } + /// + /// Gets a moveset for the provided data. + /// + /// PKM to generate for + /// Full movepool & shuffling + /// 4 moves + public static int[] GetMoveSet(this PKM pkm, bool random = false) + { + var la = new LegalityAnalysis(pkm); + return pkm.GetMoveSet(la, random); + } + /// /// Gets a moveset for the provided data. /// @@ -604,10 +616,8 @@ public static void MaximizeLevel(this PKM pkm) /// Full movepool & shuffling /// Precomputed optional /// 4 moves - public static int[] GetMoveSet(this PKM pkm, bool random = false, LegalityAnalysis la = null) + public static int[] GetMoveSet(this PKM pkm, LegalityAnalysis la, bool random = false) { - if (la == null) - la = new LegalityAnalysis(pkm); int[] m = la.GetSuggestedMoves(tm: random, tutor: random, reminder: random); if (m == null) return pkm.Moves; diff --git a/PKHeX.Core/Editing/HiddenPower.cs b/PKHeX.Core/Editing/HiddenPower.cs index 88eb00295..c30ceba33 100644 --- a/PKHeX.Core/Editing/HiddenPower.cs +++ b/PKHeX.Core/Editing/HiddenPower.cs @@ -85,7 +85,7 @@ public static bool SetIVsForType(int hpVal, int[] IVs) return true; // no mods necessary // Required HP type doesn't match IVs. Make currently-flawless IVs flawed. - int[] best = GetSuggestedHiddenPowerIVs(hpVal, IVs); + int[]? best = GetSuggestedHiddenPowerIVs(hpVal, IVs); if (best == null) return false; // can't force hidden power? @@ -95,12 +95,12 @@ public static bool SetIVsForType(int hpVal, int[] IVs) return true; } - private static int[] GetSuggestedHiddenPowerIVs(int hpVal, int[] IVs) + private static int[]? GetSuggestedHiddenPowerIVs(int hpVal, int[] IVs) { var flawless = IVs.Select((v, i) => v == 31 ? i : -1).Where(v => v != -1).ToArray(); var permutations = GetPermutations(flawless, flawless.Length); int flawedCount = 0; - int[] best = null; + int[]? best = null; foreach (var permute in permutations) { var ivs = (int[])IVs.Clone(); diff --git a/PKHeX.Core/Editing/PKM/PKMSummary.cs b/PKHeX.Core/Editing/PKM/PKMSummary.cs index 25868aa3a..fc794c7c8 100644 --- a/PKHeX.Core/Editing/PKM/PKMSummary.cs +++ b/PKHeX.Core/Editing/PKM/PKMSummary.cs @@ -13,7 +13,7 @@ public class PKMSummary // do NOT seal, allow inheritance private readonly ushort[] Stats; protected readonly PKM pkm; // protected for children generating extra properties - public string Position => pkm.Identifier; + public string? Position => pkm.Identifier; public string Nickname => pkm.Nickname; public string Species => Get(Strings.specieslist, pkm.Species); public string Nature => Get(Strings.natures, pkm.Nature); @@ -124,6 +124,6 @@ protected PKMSummary(PKM p, GameStrings strings) /// Array of strings /// Index to fetch /// Null if array is null - private static string Get(IReadOnlyList arr, int val) => (uint)val < arr?.Count ? arr[val] : null; + private static string Get(IReadOnlyList arr, int val) => (uint)val < arr?.Count ? arr[val] : string.Empty; } } \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/BoxManipBase.cs b/PKHeX.Core/Editing/Saves/BoxManipBase.cs new file mode 100644 index 000000000..d1eb48db9 --- /dev/null +++ b/PKHeX.Core/Editing/Saves/BoxManipBase.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using PKHeX.Core.Searching; + +namespace PKHeX.Core +{ + public abstract class BoxManipBase : IBoxManip + { + protected BoxManipBase(BoxManipType type, Func usable) + { + Type = type; + Usable = usable; + } + + public BoxManipType Type { get; } + public Func Usable { get; } + + public abstract string GetPrompt(bool all); + public abstract string GetFail(bool all); + public abstract string GetSuccess(bool all); + public abstract int Execute(SaveFile SAV, BoxManipParam param); + + public static readonly IReadOnlyList SortCommon = new List + { + new BoxManipSort(BoxManipType.SortSpecies, PKMSorting.OrderBySpecies), + new BoxManipSort(BoxManipType.SortSpeciesReverse, PKMSorting.OrderByDescendingSpecies), + new BoxManipSort(BoxManipType.SortLevel, PKMSorting.OrderByLevel), + new BoxManipSort(BoxManipType.SortLevelReverse, PKMSorting.OrderByDescendingLevel), + new BoxManipSort(BoxManipType.SortDate, PKMSorting.OrderByDateObtained, s => s.Generation >= 4), + new BoxManipSort(BoxManipType.SortName, list => list.OrderBySpeciesName(GameInfo.Strings.Species)), + new BoxManipSort(BoxManipType.SortFavorite, list => list.OrderByCustom(pk => pk is PB7 pb7 && pb7.Favorite), s => s is SAV7b), + new BoxManipSortComplex(BoxManipType.SortParty, (list, sav) => list.OrderByCustom(pk => ((SAV7b)sav).Blocks.Storage.GetPartyIndex(pk.Box - 1, pk.Slot - 1)), s => s is SAV7b), + new BoxManipSort(BoxManipType.SortShiny, list => list.OrderByCustom(pk => !pk.IsShiny)), + new BoxManipSort(BoxManipType.SortRandom, list => list.OrderByCustom(_ => Util.Rand32())), + }; + + public static readonly IReadOnlyList SortAdvanced = new List + { + new BoxManipSort(BoxManipType.SortUsage, PKMSorting.OrderByUsage, s => s.Generation >= 3), + new BoxManipSort(BoxManipType.SortPotential, list => list.OrderByCustom(pk => (pk.MaxIV * 6) - pk.IVTotal)), + new BoxManipSort(BoxManipType.SortTraining, list => list.OrderByCustom(pk => (pk.MaxEV * 6) - pk.EVTotal)), + new BoxManipSortComplex(BoxManipType.SortOwner, (list, sav) => list.OrderByOwnership(sav)), + new BoxManipSort(BoxManipType.SortType, list => list.OrderByCustom(pk => pk.PersonalInfo.Type1, pk => pk.PersonalInfo.Type2)), + new BoxManipSort(BoxManipType.SortVersion, list => list.OrderByCustom(pk => pk.GenNumber, pk => pk.Version, pk => pk.Met_Location), s => s.Generation >= 3), + new BoxManipSort(BoxManipType.SortBST, list => list.OrderByCustom(pk => pk.PersonalInfo.BST)), + new BoxManipSort(BoxManipType.SortCP, list => list.OrderByCustom(pk => pk is PB7 pb7 ? pb7.Stat_CP : 0), s => s is SAV7b), + new BoxManipSort(BoxManipType.SortLegal, list => list.OrderByCustom(pk => !new LegalityAnalysis(pk).Valid)), + new BoxManipSort(BoxManipType.SortEncounterType, list => list.OrderByCustom(pk => new LegalityAnalysis(pk).Info?.EncounterMatch.GetEncounterTypeName() ?? string.Empty)), + }; + + public static readonly IReadOnlyList ClearCommon = new List + { + new BoxManipClear(BoxManipType.DeleteAll, _ => true), + new BoxManipClear(BoxManipType.DeleteEggs, pk => pk.IsEgg, s => s.Generation >= 2), + new BoxManipClearComplex(BoxManipType.DeletePastGen, (pk, sav) => pk.GenNumber != sav.Generation, s => s.Generation >= 4), + new BoxManipClearComplex(BoxManipType.DeleteForeign, (pk, sav) => !sav.IsOriginalHandler(pk, pk.Format > 2)), + new BoxManipClear(BoxManipType.DeleteUntrained, pk => pk.EVTotal == 0), + new BoxManipClear(BoxManipType.DeleteItemless, pk => pk.HeldItem == 0), + new BoxManipClear(BoxManipType.DeleteIllegal, pk => !new LegalityAnalysis(pk).Valid), + new BoxManipClearDuplicate(BoxManipType.DeleteClones, pk => SearchUtil.GetCloneDetectMethod(CloneDetectionMethod.HashDetails)(pk)), + }; + + public static readonly IReadOnlyList ModifyCommon = new List + { + new BoxManipModify(BoxManipType.ModifyHatchEggs, pk => pk.ForceHatchPKM(), s => s.Generation >= 2), + new BoxManipModify(BoxManipType.ModifyMaxFriendship, pk => pk.MaximizeFriendship()), + new BoxManipModify(BoxManipType.ModifyMaxLevel, pk => pk.MaximizeLevel()), + new BoxManipModify(BoxManipType.ModifyResetMoves, pk => pk.SetMoves(pk.GetMoveSet()), s => s.Generation >= 3), + new BoxManipModify(BoxManipType.ModifyRandomMoves, pk => pk.SetMoves(pk.GetMoveSet(true))), + new BoxManipModify(BoxManipType.ModifyHyperTrain,pk => pk.SetSuggestedHyperTrainingData(), s => s.Generation >= 7), + new BoxManipModify(BoxManipType.ModifyRemoveNicknames, pk => pk.SetDefaultNickname()), + new BoxManipModify(BoxManipType.ModifyRemoveItem, pk => pk.HeldItem = 0, s => s.Generation >= 2), + }; + } +} \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/BoxManipClear.cs b/PKHeX.Core/Editing/Saves/BoxManipClear.cs index 158452db2..e8b5820b6 100644 --- a/PKHeX.Core/Editing/Saves/BoxManipClear.cs +++ b/PKHeX.Core/Editing/Saves/BoxManipClear.cs @@ -1,78 +1,21 @@ using System; -using System.Collections.Generic; -using PKHeX.Core.Searching; namespace PKHeX.Core { - public class BoxManipClear : IBoxManip + public sealed class BoxManipClear : BoxManipBase { - public BoxManipType Type { get; protected set; } - public Func Usable { get; set; } + private readonly Func Criteria; + public BoxManipClear(BoxManipType type, Func criteria) : this(type, criteria, _ => true) { } + public BoxManipClear(BoxManipType type, Func criteria, Func usable) : base(type, usable) => Criteria = criteria; - public string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxClearAll : MessageStrings.MsgSaveBoxClearCurrent; - public string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxClearAllFailBattle : MessageStrings.MsgSaveBoxClearCurrentFailBattle; - public string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxClearAllSuccess : MessageStrings.MsgSaveBoxClearCurrentSuccess; - - protected Func CriteriaSimple { private get; set; } - protected Func CriteriaSAV { private get; set; } - - public virtual int Execute(SaveFile SAV, BoxManipParam param) - { - bool Method(PKM p) => param.Reverse ^ (CriteriaSAV?.Invoke(p, SAV) ?? CriteriaSimple?.Invoke(p) ?? true); - return SAV.ClearBoxes(param.Start, param.Stop, Method); - } - - protected BoxManipClear() { } - - private BoxManipClear(BoxManipType type, Func criteria, Func usable = null) - { - Type = type; - CriteriaSimple = criteria; - Usable = usable; - } - - private BoxManipClear(BoxManipType type, Func criteria, Func usable = null) - { - Type = type; - CriteriaSAV = criteria; - Usable = usable; - } - - public static readonly IReadOnlyList Common = new List - { - new BoxManipClear(BoxManipType.DeleteAll, _ => true), - new BoxManipClear(BoxManipType.DeleteEggs, pk => pk.IsEgg, s => s.Generation >= 2), - new BoxManipClear(BoxManipType.DeletePastGen, (pk, sav) => pk.GenNumber != sav.Generation, s => s.Generation >= 4), - new BoxManipClear(BoxManipType.DeleteForeign, (pk, sav) => !sav.IsOriginalHandler(pk, pk.Format > 2)), - new BoxManipClear(BoxManipType.DeleteUntrained, pk => pk.EVTotal == 0), - new BoxManipClear(BoxManipType.DeleteItemless, pk => pk.HeldItem == 0), - new BoxManipClear(BoxManipType.DeleteIllegal, pk => !new LegalityAnalysis(pk).Valid), - new BoxManipClearDuplicate(BoxManipType.DeleteClones, pk => SearchUtil.GetCloneDetectMethod(CloneDetectionMethod.HashDetails)(pk)), - }; - } - - public sealed class BoxManipClearDuplicate : BoxManipClear - { - private readonly HashSet HashSet = new HashSet(); + public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxClearAll : MessageStrings.MsgSaveBoxClearCurrent; + public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxClearAllFailBattle : MessageStrings.MsgSaveBoxClearCurrentFailBattle; + public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxClearAllSuccess : MessageStrings.MsgSaveBoxClearCurrentSuccess; public override int Execute(SaveFile SAV, BoxManipParam param) { - HashSet.Clear(); - return base.Execute(SAV, param); - } - - public BoxManipClearDuplicate(BoxManipType type, Func criteria, Func usable = null) - { - Type = type; - Usable = usable; - CriteriaSimple = pk => - { - var result = criteria(pk); - if (HashSet.Contains(result)) - return true; - HashSet.Add(result); - return false; - }; + bool Method(PKM p) => param.Reverse ^ Criteria(p); + return SAV.ClearBoxes(param.Start, param.Stop, Method); } } } \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/BoxManipClearComplex.cs b/PKHeX.Core/Editing/Saves/BoxManipClearComplex.cs new file mode 100644 index 000000000..fcd264fb7 --- /dev/null +++ b/PKHeX.Core/Editing/Saves/BoxManipClearComplex.cs @@ -0,0 +1,21 @@ +using System; + +namespace PKHeX.Core +{ + public sealed class BoxManipClearComplex : BoxManipBase + { + private readonly Func Criteria; + public BoxManipClearComplex(BoxManipType type, Func criteria) : this(type, criteria, _ => true) { } + public BoxManipClearComplex(BoxManipType type, Func criteria, Func usable) : base(type, usable) => Criteria = criteria; + + public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxClearAll : MessageStrings.MsgSaveBoxClearCurrent; + public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxClearAllFailBattle : MessageStrings.MsgSaveBoxClearCurrentFailBattle; + public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxClearAllSuccess : MessageStrings.MsgSaveBoxClearCurrentSuccess; + + public override int Execute(SaveFile SAV, BoxManipParam param) + { + bool Method(PKM p) => param.Reverse ^ Criteria(p, SAV); + return SAV.ClearBoxes(param.Start, param.Stop, Method); + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/BoxManipClearDuplicate.cs b/PKHeX.Core/Editing/Saves/BoxManipClearDuplicate.cs new file mode 100644 index 000000000..69069376b --- /dev/null +++ b/PKHeX.Core/Editing/Saves/BoxManipClearDuplicate.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public sealed class BoxManipClearDuplicate : BoxManipBase + { + private readonly HashSet HashSet = new HashSet(); + private readonly Func Criteria; + public BoxManipClearDuplicate(BoxManipType type, Func criteria) : this(type, criteria, _ => true) { } + + public BoxManipClearDuplicate(BoxManipType type, Func criteria, Func usable) : base(type, usable) + { + Criteria = pk => + { + var result = criteria(pk); + if (HashSet.Contains(result)) + return true; + HashSet.Add(result); + return false; + }; + } + + public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxClearAll : MessageStrings.MsgSaveBoxClearCurrent; + public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxClearAllFailBattle : MessageStrings.MsgSaveBoxClearCurrentFailBattle; + public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxClearAllSuccess : MessageStrings.MsgSaveBoxClearCurrentSuccess; + + public override int Execute(SaveFile SAV, BoxManipParam param) + { + HashSet.Clear(); + bool Method(PKM p) => param.Reverse ^ Criteria(p); + return SAV.ClearBoxes(param.Start, param.Stop, Method); + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/BoxManipModify.cs b/PKHeX.Core/Editing/Saves/BoxManipModify.cs index 1e0cedf82..358fe66c9 100644 --- a/PKHeX.Core/Editing/Saves/BoxManipModify.cs +++ b/PKHeX.Core/Editing/Saves/BoxManipModify.cs @@ -1,50 +1,17 @@ using System; -using System.Collections.Generic; namespace PKHeX.Core { - public sealed class BoxManipModify : IBoxManip + public sealed class BoxManipModify : BoxManipBase { - public BoxManipType Type { get; } - public Func Usable { get; set; } - - public string GetPrompt(bool all) => null; - public string GetFail(bool all) => null; - public string GetSuccess(bool all) => null; - private readonly Action Action; - private readonly Action ActionComplex; + public BoxManipModify(BoxManipType type, Action action) : this(type, action, _ => true) { } + public BoxManipModify(BoxManipType type, Action action, Func usable) : base(type, usable) => Action = action; - public int Execute(SaveFile SAV, BoxManipParam param) - { - var method = Action ?? (px => ActionComplex(px, SAV)); - return SAV.ModifyBoxes(method, param.Start, param.Stop); - } + public override string GetPrompt(bool all) => string.Empty; + public override string GetFail(bool all) => string.Empty; + public override string GetSuccess(bool all) => string.Empty; - private BoxManipModify(BoxManipType type, Action action, Func usable = null) - { - Type = type; - Action = action; - Usable = usable; - } - - private BoxManipModify(BoxManipType type, Action action, Func usable = null) - { - Type = type; - ActionComplex = action; - Usable = usable; - } - - public static readonly IReadOnlyList Common = new List - { - new BoxManipModify(BoxManipType.ModifyHatchEggs, pk => pk.ForceHatchPKM(), s => s.Generation >= 2), - new BoxManipModify(BoxManipType.ModifyMaxFriendship, pk => pk.MaximizeFriendship()), - new BoxManipModify(BoxManipType.ModifyMaxLevel, pk => pk.MaximizeLevel()), - new BoxManipModify(BoxManipType.ModifyResetMoves, pk => pk.SetMoves(pk.GetMoveSet()), s => s.Generation >= 3), - new BoxManipModify(BoxManipType.ModifyRandomMoves, pk => pk.SetMoves(pk.GetMoveSet(true))), - new BoxManipModify(BoxManipType.ModifyHyperTrain,pk => pk.SetSuggestedHyperTrainingData(), s => s.Generation >= 7), - new BoxManipModify(BoxManipType.ModifyRemoveNicknames, pk => pk.SetDefaultNickname()), - new BoxManipModify(BoxManipType.ModifyRemoveItem, pk => pk.HeldItem = 0, s => s.Generation >= 2), - }; + public override int Execute(SaveFile SAV, BoxManipParam param) => SAV.ModifyBoxes(Action, param.Start, param.Stop); } } \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/BoxManipModifyComplex.cs b/PKHeX.Core/Editing/Saves/BoxManipModifyComplex.cs new file mode 100644 index 000000000..d22a14175 --- /dev/null +++ b/PKHeX.Core/Editing/Saves/BoxManipModifyComplex.cs @@ -0,0 +1,17 @@ +using System; + +namespace PKHeX.Core +{ + public sealed class BoxManipModifyComplex : BoxManipBase + { + private readonly Action Action; + public BoxManipModifyComplex(BoxManipType type, Action action) : this(type, action, _ => true) { } + public BoxManipModifyComplex(BoxManipType type, Action action, Func usable) : base(type, usable) => Action = action; + + public override string GetPrompt(bool all) => string.Empty; + public override string GetFail(bool all) => string.Empty; + public override string GetSuccess(bool all) => string.Empty; + + public override int Execute(SaveFile SAV, BoxManipParam param) => SAV.ModifyBoxes(pk => Action(pk, SAV), param.Start, param.Stop); + } +} \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/BoxManipSort.cs b/PKHeX.Core/Editing/Saves/BoxManipSort.cs index 3e9878296..8cfddb04f 100644 --- a/PKHeX.Core/Editing/Saves/BoxManipSort.cs +++ b/PKHeX.Core/Editing/Saves/BoxManipSort.cs @@ -3,64 +3,20 @@ namespace PKHeX.Core { - public sealed class BoxManipSort : IBoxManip + public sealed class BoxManipSort : BoxManipBase { - public BoxManipType Type { get; } - public Func Usable { get; set; } + private readonly Func, IEnumerable> Sorter; + public BoxManipSort(BoxManipType type, Func, IEnumerable> sorter) : this(type, sorter, _ => true) { } + public BoxManipSort(BoxManipType type, Func, IEnumerable> sorter, Func usable) : base(type, usable) => Sorter = sorter; - public string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxSortAll : MessageStrings.MsgSaveBoxSortCurrent; - public string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxSortAllFailBattle: MessageStrings.MsgSaveBoxSortCurrentFailBattle; - public string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxSortAllSuccess : MessageStrings.MsgSaveBoxSortCurrentSuccess; + public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxSortAll : MessageStrings.MsgSaveBoxSortCurrent; + public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxSortAllFailBattle: MessageStrings.MsgSaveBoxSortCurrentFailBattle; + public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxSortAllSuccess : MessageStrings.MsgSaveBoxSortCurrentSuccess; - private readonly Func, IEnumerable> SorterSimple; - private readonly Func, SaveFile, IEnumerable> SorterComplex; - - public int Execute(SaveFile SAV, BoxManipParam param) + public override int Execute(SaveFile SAV, BoxManipParam param) { - IEnumerable Method(IEnumerable p) => SorterSimple != null ? SorterSimple(p) : SorterComplex(p, SAV); + IEnumerable Method(IEnumerable p) => Sorter(p); return SAV.SortBoxes(param.Start, param.Stop, Method, param.Reverse); } - - private BoxManipSort(BoxManipType type, Func, IEnumerable> sorter, Func usable = null) - { - Type = type; - SorterSimple = sorter; - Usable = usable; - } - - private BoxManipSort(BoxManipType type, Func, SaveFile, IEnumerable> sorter, Func usable = null) - { - Type = type; - SorterComplex = sorter; - Usable = usable; - } - - public static readonly IReadOnlyList Common = new List - { - new BoxManipSort(BoxManipType.SortSpecies, PKMSorting.OrderBySpecies), - new BoxManipSort(BoxManipType.SortSpeciesReverse, PKMSorting.OrderByDescendingSpecies), - new BoxManipSort(BoxManipType.SortLevel, PKMSorting.OrderByLevel), - new BoxManipSort(BoxManipType.SortLevelReverse, PKMSorting.OrderByDescendingLevel), - new BoxManipSort(BoxManipType.SortDate, PKMSorting.OrderByDateObtained, s => s.Generation >= 4), - new BoxManipSort(BoxManipType.SortName, list => list.OrderBySpeciesName(GameInfo.Strings.Species)), - new BoxManipSort(BoxManipType.SortFavorite, list => list.OrderByCustom(pk => !(pk as PB7)?.Favorite), s => s is SAV7b), - new BoxManipSort(BoxManipType.SortParty, (list, sav) => list.OrderByCustom(pk => ((SAV7b)sav).Storage.GetPartyIndex(pk.Box - 1, pk.Slot - 1)), s => s is SAV7b), - new BoxManipSort(BoxManipType.SortShiny, list => list.OrderByCustom(pk => !pk.IsShiny)), - new BoxManipSort(BoxManipType.SortRandom, list => list.OrderByCustom(_ => Util.Rand32())), - }; - - public static readonly IReadOnlyList Advanced = new List - { - new BoxManipSort(BoxManipType.SortUsage, PKMSorting.OrderByUsage, s => s.Generation >= 3), - new BoxManipSort(BoxManipType.SortPotential, list => list.OrderByCustom(pk => (pk.MaxIV * 6) - pk.IVTotal)), - new BoxManipSort(BoxManipType.SortTraining, list => list.OrderByCustom(pk => (pk.MaxEV * 6) - pk.EVTotal)), - new BoxManipSort(BoxManipType.SortOwner, (list, sav) => list.OrderByOwnership(sav)), - new BoxManipSort(BoxManipType.SortType, list => list.OrderByCustom(pk => pk.PersonalInfo.Type1, pk => pk.PersonalInfo.Type2)), - new BoxManipSort(BoxManipType.SortVersion, list => list.OrderByCustom(pk => pk.GenNumber, pk => pk.Version, pk => pk.Met_Location), s => s.Generation >= 3), - new BoxManipSort(BoxManipType.SortBST, list => list.OrderByCustom(pk => pk.PersonalInfo.BST)), - new BoxManipSort(BoxManipType.SortCP, list => list.OrderByCustom(pk => (pk as PB7)?.Stat_CP), s => s is SAV7b), - new BoxManipSort(BoxManipType.SortLegal, list => list.OrderByCustom(pk => !new LegalityAnalysis(pk).Valid)), - new BoxManipSort(BoxManipType.SortEncounterType, list => list.OrderByCustom(pk => new LegalityAnalysis(pk).Info?.EncounterMatch.GetEncounterTypeName())), - }; } } \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/BoxManipSortComplex.cs b/PKHeX.Core/Editing/Saves/BoxManipSortComplex.cs new file mode 100644 index 000000000..330a418a2 --- /dev/null +++ b/PKHeX.Core/Editing/Saves/BoxManipSortComplex.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public sealed class BoxManipSortComplex : BoxManipBase + { + private readonly Func, SaveFile, IEnumerable> Sorter; + public BoxManipSortComplex(BoxManipType type, Func, SaveFile, IEnumerable> sorter) : this(type, sorter, _ => true) { } + public BoxManipSortComplex(BoxManipType type, Func, SaveFile, IEnumerable> sorter, Func usable) : base(type, usable) => Sorter = sorter; + + public override string GetPrompt(bool all) => all ? MessageStrings.MsgSaveBoxSortAll : MessageStrings.MsgSaveBoxSortCurrent; + public override string GetFail(bool all) => all ? MessageStrings.MsgSaveBoxSortAllFailBattle : MessageStrings.MsgSaveBoxSortCurrentFailBattle; + public override string GetSuccess(bool all) => all ? MessageStrings.MsgSaveBoxSortAllSuccess : MessageStrings.MsgSaveBoxSortCurrentSuccess; + + public override int Execute(SaveFile SAV, BoxManipParam param) + { + IEnumerable Method(IEnumerable p) => Sorter(p, SAV); + return SAV.SortBoxes(param.Start, param.Stop, Method, param.Reverse); + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/BoxManipUtil.cs b/PKHeX.Core/Editing/Saves/BoxManipUtil.cs index e29eed50e..5afb27d9b 100644 --- a/PKHeX.Core/Editing/Saves/BoxManipUtil.cs +++ b/PKHeX.Core/Editing/Saves/BoxManipUtil.cs @@ -10,10 +10,10 @@ public static class BoxManipUtil /// public static readonly IReadOnlyList[] ManipCategories = { - BoxManipClear.Common, - BoxManipSort.Common, - BoxManipSort.Advanced, - BoxManipModify.Common, + BoxManipBase.ClearCommon, + BoxManipBase.SortCommon, + BoxManipBase.SortAdvanced, + BoxManipBase.ModifyCommon, }; public static readonly string[] ManipCategoryNames = @@ -36,7 +36,7 @@ public static class BoxManipUtil /// /// Manipulation type. /// Category Name - public static string GetManipCategoryName(this BoxManipType type) + public static string? GetManipCategoryName(this BoxManipType type) { for (int i = 0; i < ManipCategories.Length; i++) { @@ -51,7 +51,7 @@ public static string GetManipCategoryName(this BoxManipType type) /// /// Manipulation type. /// Category Name - public static string GetManipCategoryName(this IBoxManip manip) + public static string? GetManipCategoryName(this IBoxManip manip) { for (int i = 0; i < ManipCategories.Length; i++) { diff --git a/PKHeX.Core/Editing/Saves/BoxManipulator.cs b/PKHeX.Core/Editing/Saves/BoxManipulator.cs index 16c197528..a0e1eaf79 100644 --- a/PKHeX.Core/Editing/Saves/BoxManipulator.cs +++ b/PKHeX.Core/Editing/Saves/BoxManipulator.cs @@ -14,7 +14,7 @@ public abstract class BoxManipulator /// True if operation succeeded, false if no changes made. public bool Execute(IBoxManip manip, int box, bool allBoxes, bool reverse = false) { - bool usable = manip.Usable?.Invoke(SAV) ?? true; + bool usable = manip.Usable.Invoke(SAV); if (!usable) return false; diff --git a/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWork.cs b/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWork.cs index 0a2cbe978..89998fec8 100644 --- a/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWork.cs +++ b/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWork.cs @@ -7,7 +7,7 @@ namespace PKHeX.Core /// Event number storage for more complex logic events. /// /// - public sealed class EventWork : EventVar + public sealed class EventWork : EventVar where T : struct { public T Value; public readonly IList Options = new List { new EventWorkVal() }; diff --git a/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWorkDiff.cs b/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWorkDiff.cs index 063f9081f..5b8149cf8 100644 --- a/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWorkDiff.cs +++ b/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWorkDiff.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Linq; using static PKHeX.Core.MessageStrings; @@ -10,7 +11,7 @@ namespace PKHeX.Core /// public class EventBlockDiff { - public string Message { get; private set; } + public string Message { get; protected set; } = string.Empty; public readonly List SetFlags = new List(); public readonly List ClearedFlags = new List(); public readonly List WorkDiff = new List(); @@ -24,6 +25,11 @@ public EventBlockDiff(string f1, string f2) return; var s1 = SaveUtil.GetVariantSAV(f1); var s2 = SaveUtil.GetVariantSAV(f2); + if (s1 == null || s2 == null || s1.GetType() != s2.GetType()) + { + Message = MsgSaveDifferentTypes; + return; + } Diff(s1, s2); } @@ -83,7 +89,7 @@ protected virtual void Diff(SaveFile s1, SaveFile s2) public sealed class EventWorkDiff7b : EventBlockDiff { public readonly List WorkChanged = new List(); - private SaveFile S1; + private SaveFile? S1; public EventWorkDiff7b(string f1, string f2) { @@ -91,6 +97,11 @@ public EventWorkDiff7b(string f1, string f2) return; var s1 = SaveUtil.GetVariantSAV(f1); var s2 = SaveUtil.GetVariantSAV(f2); + if (s1 == null || s2 == null || s1.GetType() != s2.GetType()) + { + Message = MsgSaveDifferentTypes; + return; + } Diff(s1, s2); } @@ -101,14 +112,16 @@ protected override void Diff(SaveFile s1, SaveFile s2) if (!SanityCheckSaveInfo(s1, s2)) return; - EventWorkUtil.DiffSavesFlag(((SAV7b)s1).EventWork, ((SAV7b)s2).EventWork, SetFlags, ClearedFlags); - EventWorkUtil.DiffSavesWork(((SAV7b)s1).EventWork, ((SAV7b)s2).EventWork, WorkChanged, WorkDiff); + EventWorkUtil.DiffSavesFlag(((SAV7b)s1).Blocks.EventWork, ((SAV7b)s2).Blocks.EventWork, SetFlags, ClearedFlags); + EventWorkUtil.DiffSavesWork(((SAV7b)s1).Blocks.EventWork, ((SAV7b)s2).Blocks.EventWork, WorkChanged, WorkDiff); S1 = s1; } - public List Summarize() + public IReadOnlyList Summarize() { - var ew = ((SAV7b)S1).EventWork; + if (S1 == null) + return Array.Empty(); + var ew = ((SAV7b)S1).Blocks.EventWork; var fOn = SetFlags.Select(z => new { Type = ew.GetFlagType(z, out var subIndex), Index = subIndex, Raw = z }) .Select(z => $"{z.Raw:0000}\t{true }\t{z.Index:0000}\t{z.Type}").ToArray(); diff --git a/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWorkUtil.cs b/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWorkUtil.cs index c3941cf5a..aa0568623 100644 --- a/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWorkUtil.cs +++ b/PKHeX.Core/Editing/Saves/Editors/EventWork/EventWorkUtil.cs @@ -103,7 +103,7 @@ public static void DiffSavesWork(IEventWork before, IEventWork after, L { var b = before.GetWork(i); var a = after.GetWork(i); - if (b.Equals(a)) + if (b is null || b.Equals(a)) continue; changed.Add(i); diff --git a/PKHeX.Core/Editing/Saves/Editors/EventWork/SplitEventEditor.cs b/PKHeX.Core/Editing/Saves/Editors/EventWork/SplitEventEditor.cs index 2dd12d6d9..84fb4e4be 100644 --- a/PKHeX.Core/Editing/Saves/Editors/EventWork/SplitEventEditor.cs +++ b/PKHeX.Core/Editing/Saves/Editors/EventWork/SplitEventEditor.cs @@ -7,7 +7,7 @@ namespace PKHeX.Core /// Editor object that unpacks into flags & work groups, and handles value get/set operations. /// /// - public sealed class SplitEventEditor + public sealed class SplitEventEditor where T : struct { public readonly IList Work; public readonly IList Flag; diff --git a/PKHeX.Core/Editing/Saves/Editors/SaveDataEditor.cs b/PKHeX.Core/Editing/Saves/Editors/SaveDataEditor.cs index 0c4b465b8..45af7f6de 100644 --- a/PKHeX.Core/Editing/Saves/Editors/SaveDataEditor.cs +++ b/PKHeX.Core/Editing/Saves/Editors/SaveDataEditor.cs @@ -1,4 +1,7 @@ -namespace PKHeX.Core +using System; +using System.Collections.Generic; + +namespace PKHeX.Core { /// /// Environment for editing a @@ -8,13 +11,77 @@ public sealed class SaveDataEditor { public readonly SaveFile SAV; public readonly SlotEditor Slots; + public readonly IPKMView PKMEditor; - public IPKMView PKMEditor { get; set; } + public SaveDataEditor() : this(FakeSaveFile.Default) { } public SaveDataEditor(SaveFile sav) { SAV = sav; Slots = new SlotEditor(sav); + PKMEditor = new FakePKMEditor(SAV.BlankPKM); + } + + public SaveDataEditor(SaveFile sav, IPKMView editor) + { + SAV = sav; + Slots = new SlotEditor(sav); + PKMEditor = editor; } } + + /// + /// Fakes the interface interactions. + /// + public sealed class FakePKMEditor : IPKMView + { + public FakePKMEditor(PKM template) => Data = template; + + public PKM Data { get; private set; } + public bool Unicode => true; + public bool HaX => false; + public bool ChangingFields { get; set; } + public bool EditsComplete => true; + + public PKM PreparePKM(bool click = true) => Data; + public void PopulateFields(PKM pk, bool focus = true, bool skipConversionCheck = false) => Data = pk; + } + + public sealed class FakeSaveFile : SaveFile + { + public static readonly FakeSaveFile Default = new FakeSaveFile(); + protected override string BAKText => "Fake Save File"; + public override SaveFile Clone() => this; + public override string Filter => string.Empty; + public override string Extension => string.Empty; + public override bool ChecksumsValid => true; + public override string ChecksumInfo => string.Empty; + public override int Generation => PKX.Generation; + public override string GetString(byte[] data, int offset, int length) => string.Empty; + public override byte[] SetString(string value, int maxLength, int PadToSize = 0, ushort PadWith = 0) => Array.Empty(); + public override PersonalTable Personal => PKX.Personal; + public override int MaxEV => 0; + public override IReadOnlyList HeldItems => Legal.HeldItems_GG; + public override int GetBoxOffset(int box) => -1; + public override string GetBoxName(int box) => $"Box {box:00}"; + public override void SetBoxName(int box, string value) { } + public override int OTLength => 5; + public override int NickLength => 5; + public override int MaxMoveID => 5; + public override int MaxSpeciesID => 1; + public override int MaxItemID => 5; + public override int MaxBallID => 5; + public override int MaxGameID => 5; + public override int MaxAbilityID => 0; + public override int BoxCount => 1; + public override int GetPartyOffset(int slot) => -1; + protected override void SetChecksums() { } + + public override Type PKMType => typeof(PKM); + protected override PKM GetPKM(byte[] data) => BlankPKM; + protected override byte[] DecryptPKM(byte[] data) => data; + public override PKM BlankPKM => new PK7(); + public override int SIZE_STORED => 0; + protected override int SIZE_PARTY => 0; + } } \ No newline at end of file diff --git a/PKHeX.Core/Editing/Saves/IBoxManip.cs b/PKHeX.Core/Editing/Saves/IBoxManip.cs index a6e13804c..153a66087 100644 --- a/PKHeX.Core/Editing/Saves/IBoxManip.cs +++ b/PKHeX.Core/Editing/Saves/IBoxManip.cs @@ -5,7 +5,7 @@ namespace PKHeX.Core public interface IBoxManip { BoxManipType Type { get; } - Func Usable { get; set; } + Func Usable { get; } string GetPrompt(bool all); string GetFail(bool all); diff --git a/PKHeX.Core/Editing/Saves/Slots/Extensions.cs b/PKHeX.Core/Editing/Saves/Slots/Extensions.cs index 5553fcdd5..c33716b4e 100644 --- a/PKHeX.Core/Editing/Saves/Slots/Extensions.cs +++ b/PKHeX.Core/Editing/Saves/Slots/Extensions.cs @@ -119,7 +119,7 @@ private static List GetExtraSlots7(SAV7 sav, bool all) { var list = new List { - new SlotInfoMisc(0, sav.GTS) {Type = StorageSlotType.GTS}, + new SlotInfoMisc(0, sav.AllBlocks[07].Offset) {Type = StorageSlotType.GTS}, new SlotInfoMisc(0, sav.GetFusedSlotOffset(0)) {Type = StorageSlotType.Fused} }; if (sav is SAV7USUM) diff --git a/PKHeX.Core/Editing/Saves/Slots/SlotChangelog.cs b/PKHeX.Core/Editing/Saves/Slots/SlotChangelog.cs index 291a42e84..372147fa7 100644 --- a/PKHeX.Core/Editing/Saves/Slots/SlotChangelog.cs +++ b/PKHeX.Core/Editing/Saves/Slots/SlotChangelog.cs @@ -24,9 +24,6 @@ public void AddNewChange(ISlotInfo info) public ISlotInfo Undo() { - if (!CanUndo) - return null; - var change = UndoStack.Pop(); var revert = GetReversion(change.Info, SAV); AddRedo(revert); @@ -36,9 +33,6 @@ public ISlotInfo Undo() public ISlotInfo Redo() { - if (!CanRedo) - return null; - var change = RedoStack.Pop(); var revert = GetReversion(change.Info, SAV); AddUndo(revert); diff --git a/PKHeX.Core/Editing/Saves/Slots/SlotEditor.cs b/PKHeX.Core/Editing/Saves/Slots/SlotEditor.cs index 6d8e3bba4..ed5e7b3ad 100644 --- a/PKHeX.Core/Editing/Saves/Slots/SlotEditor.cs +++ b/PKHeX.Core/Editing/Saves/Slots/SlotEditor.cs @@ -100,12 +100,16 @@ private PKM DeleteSlot(ISlotInfo slot) public void Undo() { + if (!Changelog.CanUndo) + return; var slot = Changelog.Undo(); NotifySlotChanged(slot, SlotTouchType.Set, slot.Read(SAV)); } public void Redo() { + if (!Changelog.CanRedo) + return; var slot = Changelog.Redo(); NotifySlotChanged(slot, SlotTouchType.Set, slot.Read(SAV)); } diff --git a/PKHeX.Core/Editing/Saves/Slots/SlotPublisher.cs b/PKHeX.Core/Editing/Saves/Slots/SlotPublisher.cs index 13ecb7f8f..094c57e84 100644 --- a/PKHeX.Core/Editing/Saves/Slots/SlotPublisher.cs +++ b/PKHeX.Core/Editing/Saves/Slots/SlotPublisher.cs @@ -12,9 +12,9 @@ public sealed class SlotPublisher /// public List> Subscribers { get; } = new List>(); - public ISlotInfo Previous { get; private set; } + public ISlotInfo? Previous { get; private set; } public SlotTouchType PreviousType { get; private set; } = SlotTouchType.None; - public PKM PreviousPKM { get; private set; } + public PKM? PreviousPKM { get; private set; } /// /// Notifies all with the latest slot change details. @@ -33,13 +33,18 @@ public void NotifySlotChanged(ISlotInfo slot, SlotTouchType type, PKM pkm) private void ResetView(ISlotViewer sub, ISlotInfo slot, SlotTouchType type, PKM pkm) { - if (PreviousPKM != null) + if (Previous != null) sub.NotifySlotOld(Previous); if (!(slot is SlotInfoBox b) || sub.ViewIndex == b.Box) sub.NotifySlotChanged(slot, type, pkm); } - public void ResetView(ISlotViewer sub) => ResetView(sub, Previous, PreviousType, PreviousPKM); + public void ResetView(ISlotViewer sub) + { + if (Previous == null || PreviousPKM == null) + return; + ResetView(sub, Previous, PreviousType, PreviousPKM); + } } } diff --git a/PKHeX.Core/Editing/Saves/Slots/SlotViewInfo.cs b/PKHeX.Core/Editing/Saves/Slots/SlotViewInfo.cs index b4abde962..7d8f79944 100644 --- a/PKHeX.Core/Editing/Saves/Slots/SlotViewInfo.cs +++ b/PKHeX.Core/Editing/Saves/Slots/SlotViewInfo.cs @@ -6,11 +6,17 @@ namespace PKHeX.Core /// public sealed class SlotViewInfo { - public ISlotInfo Slot; - public ISlotViewer View; + public readonly ISlotInfo Slot; + public readonly ISlotViewer View; public PKM ReadCurrent() => Slot.Read(View.SAV); public bool CanWriteTo() => Slot.CanWriteTo(View.SAV); public WriteBlockedMessage CanWriteTo(PKM pkm) => Slot.CanWriteTo(View.SAV, pkm); + + public SlotViewInfo(ISlotInfo slot, ISlotViewer view) + { + Slot = slot; + View = view; + } } } \ No newline at end of file diff --git a/PKHeX.Core/Editing/ShowdownSet.cs b/PKHeX.Core/Editing/ShowdownSet.cs index 9532eb907..b23dcc0dd 100644 --- a/PKHeX.Core/Editing/ShowdownSet.cs +++ b/PKHeX.Core/Editing/ShowdownSet.cs @@ -257,7 +257,7 @@ private string LocalizedText(int lang) return GetText(strings); } - private string GetText(GameStrings strings = null) + private string GetText(GameStrings? strings = null) { if (Species <= 0 || Species > MAX_SPECIES) return string.Empty; diff --git a/PKHeX.Core/Game/GameStrings/GameDataSource.cs b/PKHeX.Core/Game/GameStrings/GameDataSource.cs index 03dfe425c..820a24a17 100644 --- a/PKHeX.Core/Game/GameStrings/GameDataSource.cs +++ b/PKHeX.Core/Game/GameStrings/GameDataSource.cs @@ -30,7 +30,17 @@ public GameDataSource(GameStrings s) LegalMoveDataSource = HaXMoveDataSource.Where(m => !Legal.Z_Moves.Contains(m.Value)).ToList(); VersionDataSource = GetVersionList(s); - InitializeMetSources(); + + MetGen2 = CreateGen2(s); + MetGen3 = CreateGen3(s); + MetGen3CXD = CreateGen3CXD(s); + MetGen4 = CreateGen4(s); + MetGen5 = CreateGen5(s); + MetGen6 = CreateGen6(s); + MetGen7 = CreateGen7(s); + MetGen7GG = CreateGen7GG(s); + MetGen8 = CreateGen8(s); + Memories = new MemoryStrings(s); } @@ -46,17 +56,17 @@ public GameDataSource(GameStrings s) public readonly IReadOnlyList HaXMoveDataSource; public readonly IReadOnlyList EncounterTypeDataSource; - private IReadOnlyList MetGen2 { get; set; } - private IReadOnlyList MetGen3 { get; set; } - private IReadOnlyList MetGen3CXD { get; set; } - private IReadOnlyList MetGen4 { get; set; } - private IReadOnlyList MetGen5 { get; set; } - private IReadOnlyList MetGen6 { get; set; } - private IReadOnlyList MetGen7 { get; set; } - private IReadOnlyList MetGen7GG { get; set; } - private IReadOnlyList MetGen8 { get; set; } + private readonly IReadOnlyList MetGen2; + private readonly IReadOnlyList MetGen3; + private readonly IReadOnlyList MetGen3CXD; + private readonly IReadOnlyList MetGen4; + private readonly IReadOnlyList MetGen5; + private readonly IReadOnlyList MetGen6; + private readonly IReadOnlyList MetGen7; + private readonly IReadOnlyList MetGen7GG; + private readonly IReadOnlyList MetGen8; - private IReadOnlyList GetVersionList(GameStrings s) + private static IReadOnlyList GetVersionList(GameStrings s) { var list = s.gamelist; var ver = Util.GetCBList(list, @@ -72,95 +82,102 @@ private IReadOnlyList GetVersionList(GameStrings s) return ver; } - private void InitializeMetSources() + private List CreateGen2(GameStrings s) { - var s = Source; - // Gen 2 - { - var met_list = Util.GetCBList(s.metGSC_00000, Enumerable.Range(0, 0x5F).ToArray()); - Util.AddCBWithOffset(met_list, s.metGSC_00000, 00000, 0x7E, 0x7F); - MetGen2 = met_list; - } - // Gen 3 - { - var met_list = Util.GetCBList(s.metRSEFRLG_00000, Enumerable.Range(0, 213).ToArray()); - Util.AddCBWithOffset(met_list, s.metRSEFRLG_00000, 00000, 253, 254, 255); - MetGen3 = met_list; - - MetGen3CXD = Util.GetCBList(s.metCXD_00000, Enumerable.Range(0, s.metCXD_00000.Length).ToArray()).Where(c => c.Text.Length > 0).ToList(); - } - // Gen 4 - { - var met_list = Util.GetCBList(s.metHGSS_00000, 0); - Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Locations.Daycare4); - Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Locations.LinkTrade4); - Util.AddCBWithOffset(met_list, s.metHGSS_03000, 3000, Locations.Ranger4); - Util.AddCBWithOffset(met_list, s.metHGSS_00000, 0000, Legal.Met_HGSS_0); - Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Legal.Met_HGSS_2); - Util.AddCBWithOffset(met_list, s.metHGSS_03000, 3000, Legal.Met_HGSS_3); - MetGen4 = met_list; - } - // Gen 5 - { - var met_list = Util.GetCBList(s.metBW2_00000, 0); - Util.AddCBWithOffset(met_list, s.metBW2_60000, 60001, Locations.Daycare5); - Util.AddCBWithOffset(met_list, s.metBW2_30000, 30001, Locations.LinkTrade5); - Util.AddCBWithOffset(met_list, s.metBW2_00000, 00000, Legal.Met_BW2_0); - Util.AddCBWithOffset(met_list, s.metBW2_30000, 30001, Legal.Met_BW2_3); - Util.AddCBWithOffset(met_list, s.metBW2_40000, 40001, Legal.Met_BW2_4); - Util.AddCBWithOffset(met_list, s.metBW2_60000, 60001, Legal.Met_BW2_6); - MetGen5 = met_list; - } - // Gen 6 - { - var met_list = Util.GetCBList(s.metXY_00000, 0); - Util.AddCBWithOffset(met_list, s.metXY_60000, 60001, Locations.Daycare5); - Util.AddCBWithOffset(met_list, s.metXY_30000, 30001, Locations.LinkTrade6); - Util.AddCBWithOffset(met_list, s.metXY_00000, 00000, Legal.Met_XY_0); - Util.AddCBWithOffset(met_list, s.metXY_30000, 30001, Legal.Met_XY_3); - Util.AddCBWithOffset(met_list, s.metXY_40000, 40001, Legal.Met_XY_4); - Util.AddCBWithOffset(met_list, s.metXY_60000, 60001, Legal.Met_XY_6); - MetGen6 = met_list; - } - // Gen 7 - { - var met_list = Util.GetCBList(s.metSM_00000, 0); - Util.AddCBWithOffset(met_list, s.metSM_60000, 60001, Locations.Daycare5); - Util.AddCBWithOffset(met_list, s.metSM_30000, 30001, Locations.LinkTrade6); - Util.AddCBWithOffset(met_list, s.metSM_00000, 00000, Legal.Met_SM_0); - Util.AddCBWithOffset(met_list, s.metSM_30000, 30001, Legal.Met_SM_3); - Util.AddCBWithOffset(met_list, s.metSM_40000, 40001, Legal.Met_SM_4); - Util.AddCBWithOffset(met_list, s.metSM_60000, 60001, Legal.Met_SM_6); - MetGen7 = met_list; - } - // Gen 7 GG - { - var met_list = Util.GetCBList(s.metGG_00000, 0); - Util.AddCBWithOffset(met_list, s.metGG_60000, 60001, 60002); - Util.AddCBWithOffset(met_list, s.metGG_30000, 30001, Locations.LinkTrade6); - Util.AddCBWithOffset(met_list, s.metGG_00000, 00000, Legal.Met_GG_0); - Util.AddCBWithOffset(met_list, s.metGG_30000, 30001, Legal.Met_GG_3); - Util.AddCBWithOffset(met_list, s.metGG_40000, 40001, Legal.Met_GG_4); - Util.AddCBWithOffset(met_list, s.metGG_60000, 60001, Legal.Met_GG_6); - MetGen7GG = met_list; - } - // Gen 8 - { - var met_list = Util.GetCBList(s.metSWSH_00000, 0); - Util.AddCBWithOffset(met_list, s.metSWSH_60000, 60001, 60002); - Util.AddCBWithOffset(met_list, s.metSWSH_30000, 30001, Locations.LinkTrade6); - Util.AddCBWithOffset(met_list, s.metSWSH_00000, 00000, Legal.Met_SWSH_0); - Util.AddCBWithOffset(met_list, s.metSWSH_30000, 30001, Legal.Met_SWSH_3); - Util.AddCBWithOffset(met_list, s.metSWSH_40000, 40001, Legal.Met_SWSH_4); - Util.AddCBWithOffset(met_list, s.metSWSH_60000, 60001, Legal.Met_SWSH_6); - MetGen8 = met_list; - } + var met_list = Util.GetCBList(s.metGSC_00000, Enumerable.Range(0, 0x5F).ToArray()); + Util.AddCBWithOffset(met_list, s.metGSC_00000, 00000, 0x7E, 0x7F); + return met_list; } - public IReadOnlyList GetItemDataSource(GameVersion game, int generation, int MaxItemID, IEnumerable allowed = null, bool HaX = false) + private List CreateGen3(GameStrings s) + { + var met_list = Util.GetCBList(s.metRSEFRLG_00000, Enumerable.Range(0, 213).ToArray()); + Util.AddCBWithOffset(met_list, s.metRSEFRLG_00000, 00000, 253, 254, 255); + return met_list; + } + + + private static List CreateGen3CXD(GameStrings s) + { + return Util.GetCBList(s.metCXD_00000, Enumerable.Range(0, s.metCXD_00000.Length).ToArray()).Where(c => c.Text.Length > 0).ToList(); + } + + private static List CreateGen4(GameStrings s) + { + var met_list = Util.GetCBList(s.metHGSS_00000, 0); + Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Locations.Daycare4); + Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Locations.LinkTrade4); + Util.AddCBWithOffset(met_list, s.metHGSS_03000, 3000, Locations.Ranger4); + Util.AddCBWithOffset(met_list, s.metHGSS_00000, 0000, Legal.Met_HGSS_0); + Util.AddCBWithOffset(met_list, s.metHGSS_02000, 2000, Legal.Met_HGSS_2); + Util.AddCBWithOffset(met_list, s.metHGSS_03000, 3000, Legal.Met_HGSS_3); + return met_list; + } + private static List CreateGen5(GameStrings s) + { + var met_list = Util.GetCBList(s.metBW2_00000, 0); + Util.AddCBWithOffset(met_list, s.metBW2_60000, 60001, Locations.Daycare5); + Util.AddCBWithOffset(met_list, s.metBW2_30000, 30001, Locations.LinkTrade5); + Util.AddCBWithOffset(met_list, s.metBW2_00000, 00000, Legal.Met_BW2_0); + Util.AddCBWithOffset(met_list, s.metBW2_30000, 30001, Legal.Met_BW2_3); + Util.AddCBWithOffset(met_list, s.metBW2_40000, 40001, Legal.Met_BW2_4); + Util.AddCBWithOffset(met_list, s.metBW2_60000, 60001, Legal.Met_BW2_6); + return met_list; + } + + private static List CreateGen6(GameStrings s) + { + var met_list = Util.GetCBList(s.metXY_00000, 0); + Util.AddCBWithOffset(met_list, s.metXY_60000, 60001, Locations.Daycare5); + Util.AddCBWithOffset(met_list, s.metXY_30000, 30001, Locations.LinkTrade6); + Util.AddCBWithOffset(met_list, s.metXY_00000, 00000, Legal.Met_XY_0); + Util.AddCBWithOffset(met_list, s.metXY_30000, 30001, Legal.Met_XY_3); + Util.AddCBWithOffset(met_list, s.metXY_40000, 40001, Legal.Met_XY_4); + Util.AddCBWithOffset(met_list, s.metXY_60000, 60001, Legal.Met_XY_6); + return met_list; + } + + private static List CreateGen7(GameStrings s) + { + var met_list = Util.GetCBList(s.metSM_00000, 0); + Util.AddCBWithOffset(met_list, s.metSM_60000, 60001, Locations.Daycare5); + Util.AddCBWithOffset(met_list, s.metSM_30000, 30001, Locations.LinkTrade6); + Util.AddCBWithOffset(met_list, s.metSM_00000, 00000, Legal.Met_SM_0); + Util.AddCBWithOffset(met_list, s.metSM_30000, 30001, Legal.Met_SM_3); + Util.AddCBWithOffset(met_list, s.metSM_40000, 40001, Legal.Met_SM_4); + Util.AddCBWithOffset(met_list, s.metSM_60000, 60001, Legal.Met_SM_6); + return met_list; + } + + private static List CreateGen7GG(GameStrings s) + { + var met_list = Util.GetCBList(s.metGG_00000, 0); + Util.AddCBWithOffset(met_list, s.metGG_60000, 60001, 60002); + Util.AddCBWithOffset(met_list, s.metGG_30000, 30001, Locations.LinkTrade6); + Util.AddCBWithOffset(met_list, s.metGG_00000, 00000, Legal.Met_GG_0); + Util.AddCBWithOffset(met_list, s.metGG_30000, 30001, Legal.Met_GG_3); + Util.AddCBWithOffset(met_list, s.metGG_40000, 40001, Legal.Met_GG_4); + Util.AddCBWithOffset(met_list, s.metGG_60000, 60001, Legal.Met_GG_6); + return met_list; + } + + private static List CreateGen8(GameStrings s) + { + var met_list = Util.GetCBList(s.metSWSH_00000, 0); + Util.AddCBWithOffset(met_list, s.metSWSH_60000, 60001, 60002); + Util.AddCBWithOffset(met_list, s.metSWSH_30000, 30001, Locations.LinkTrade6); + Util.AddCBWithOffset(met_list, s.metSWSH_00000, 00000, Legal.Met_SWSH_0); + Util.AddCBWithOffset(met_list, s.metSWSH_30000, 30001, Legal.Met_SWSH_3); + Util.AddCBWithOffset(met_list, s.metSWSH_40000, 40001, Legal.Met_SWSH_4); + Util.AddCBWithOffset(met_list, s.metSWSH_60000, 60001, Legal.Met_SWSH_6); + return met_list; + } + + public IReadOnlyList GetItemDataSource(GameVersion game, int generation, int MaxItemID, IEnumerable? allowed = null, bool HaX = false) { var items = Source.GetItemStrings(generation, game); - return Util.GetCBList(items, (allowed == null || HaX ? Enumerable.Range(0, MaxItemID) : allowed.Select(i => (int)i)).ToArray()); + var range = (allowed == null || HaX ? Enumerable.Range(0, MaxItemID) : allowed.Select(i => (int) i)).ToArray(); + return Util.GetCBList(items, range); } /// diff --git a/PKHeX.Core/Game/GameStrings/GameInfo.cs b/PKHeX.Core/Game/GameStrings/GameInfo.cs index 36b9eeac6..b475594b3 100644 --- a/PKHeX.Core/Game/GameStrings/GameInfo.cs +++ b/PKHeX.Core/Game/GameStrings/GameInfo.cs @@ -22,22 +22,17 @@ public static GameStrings GetStrings(string lang) public static GameStrings GetStrings(int index) { - return Languages[index] ?? (Languages[index] = new GameStrings(GameLanguage.Language2Char(index))); + return Languages[index] ??= new GameStrings(GameLanguage.Language2Char(index)); } public static GameStrings Strings { get => _strings; - set - { - _strings = value; - Sources = new GameDataSource(_strings); - FilteredSources = null; - } + set => Sources = new GameDataSource(_strings = value); } - public static GameDataSource Sources { get; set; } - public static FilteredGameDataSource FilteredSources { get; set; } + public static GameDataSource Sources { get; private set; } = new GameDataSource(_strings); + public static FilteredGameDataSource FilteredSources { get; set; } = new FilteredGameDataSource(FakeSaveFile.Default, Sources, false); public static string GetVersionName(GameVersion version) { diff --git a/PKHeX.Core/Legality/Analysis.cs b/PKHeX.Core/Legality/Analysis.cs index 5b4435345..08316e627 100644 --- a/PKHeX.Core/Legality/Analysis.cs +++ b/PKHeX.Core/Legality/Analysis.cs @@ -22,7 +22,7 @@ public partial class LegalityAnalysis /// public IReadOnlyList Results => Parse; - private IEncounterable EncounterOriginalGB; + private IEncounterable? EncounterOriginalGB; /// /// Matched encounter data for the . @@ -52,7 +52,7 @@ public partial class LegalityAnalysis /// /// Contains various data reused for multiple checks. /// - public LegalInfo Info { get; private set; } + public readonly LegalInfo Info; /// /// Creates a report message with optional verbosity for in-depth analysis. @@ -85,7 +85,7 @@ private IEnumerable AllSuggestedRelearnMoves } } - private int[] _allSuggestedMoves, _allSuggestedRelearnMoves; + private int[]? _allSuggestedMoves, _allSuggestedRelearnMoves; public int[] AllSuggestedMovesAndRelearn => AllSuggestedMoves.Concat(AllSuggestedRelearnMoves).ToArray(); private string EncounterName @@ -97,7 +97,7 @@ private string EncounterName } } - private string EncounterLocation + private string? EncounterLocation { get { @@ -111,15 +111,22 @@ private string EncounterLocation /// /// Input data to check /// specific personal data - public LegalityAnalysis(PKM pk, PersonalTable table = null) + public LegalityAnalysis(PKM pk, PersonalTable? table = null) { pkm = pk; + PersonalInfo = table?.GetFormeEntry(pkm.Species, pkm.AltForm) ?? pkm.PersonalInfo; + + if (pkm.Format <= 2) // prior to storing GameVersion + pkm.TradebackStatus = GBRestrictions.GetTradebackStatusInitial(pkm); + #if SUPPRESS try #endif { - PersonalInfo = table?.GetFormeEntry(pkm.Species, pkm.AltForm) ?? pkm.PersonalInfo; - ParseLegality(); + Info = EncounterFinder.FindVerifiedEncounter(pkm); + if (!pkm.IsOriginValid) + AddLine(Severity.Invalid, LEncConditionBadSpecies, CheckIdentifier.GameOrigin); + GetParseMethod()(); if (Parse.Count == 0) return; @@ -134,6 +141,7 @@ public LegalityAnalysis(PKM pk, PersonalTable table = null) #if SUPPRESS catch (Exception e) { + Info = new LegalInfo(pkm); System.Diagnostics.Debug.WriteLine(e.Message); Valid = false; AddLine(Severity.Invalid, L_AError, CheckIdentifier.Misc); @@ -143,33 +151,33 @@ public LegalityAnalysis(PKM pk, PersonalTable table = null) Parsed = true; } - private void ParseLegality() + private Action GetParseMethod() { - if (!pkm.IsOriginValid) - AddLine(Severity.Invalid, LEncConditionBadSpecies, CheckIdentifier.GameOrigin); - if (pkm.Format <= 2) // prior to storing GameVersion - { - ParsePK1(); - return; - } - switch (pkm.GenNumber) - { - case 3: ParsePK3(); return; - case 4: ParsePK4(); return; - case 5: ParsePK5(); return; - case 6: ParsePK6(); return; + return ParsePK1; - case 1: case 2: - case 7: ParsePK7(); return; + int gen = pkm.GenNumber; + if (gen <= 0) + gen = pkm.Format; + return gen switch + { + 3 => ParsePK3, + 4 => ParsePK4, + 5 => ParsePK5, + 6 => ParsePK6, - case 8: ParsePK8(); return; - } + 1 => ParsePK7, + 2 => ParsePK7, + 7 => ParsePK7, + + 8 => (Action)ParsePK8, + + _ => throw new Exception() + }; } private void ParsePK1() { - pkm.TradebackStatus = GBRestrictions.GetTradebackStatusInitial(pkm); UpdateInfo(); if (pkm.TradebackStatus == TradebackType.Any && Info.Generation != pkm.Format) pkm.TradebackStatus = TradebackType.WasTradeback; // Example: GSC Pokemon with only possible encounters in RBY, like the legendary birds @@ -267,7 +275,6 @@ private void UpdateVCTransferInfo() private void UpdateInfo() { - Info = EncounterFinder.FindVerifiedEncounter(pkm); Parse.AddRange(Info.Parse); } @@ -385,7 +392,11 @@ private string GetVerboseLegalityReport() lines.Add(string.Format(L_F0_1, "Location", loc)); if (pkm.VC) lines.Add(string.Format(L_F0_1, nameof(GameVersion), Info.Game)); - var pidiv = Info.PIDIV ?? MethodFinder.Analyze(pkm); + + if (!Info.PIDParsed) + Info.PIDIV = MethodFinder.Analyze(pkm); + + var pidiv = Info.PIDIV; if (pidiv != null) { if (!pidiv.NoSeed) @@ -456,6 +467,6 @@ public int[] GetSuggestedMoves(bool tm, bool tutor, bool reminder) /// /// Gets an object containing met data properties that might be legal. /// - public EncounterStatic GetSuggestedMetInfo() => EncounterSuggestion.GetSuggestedMetInfo(pkm); + public EncounterStatic? GetSuggestedMetInfo() => EncounterSuggestion.GetSuggestedMetInfo(pkm); } } diff --git a/PKHeX.Core/Legality/Areas/EncounterArea.cs b/PKHeX.Core/Legality/Areas/EncounterArea.cs index cdf599584..8df1a3846 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea.cs @@ -10,7 +10,7 @@ namespace PKHeX.Core public abstract class EncounterArea { public int Location; - public EncounterSlot[] Slots; + public EncounterSlot[] Slots = Array.Empty(); /// /// Gets the encounter areas for species with same level range and same slot type at same location diff --git a/PKHeX.Core/Legality/Areas/EncounterArea6AO.cs b/PKHeX.Core/Legality/Areas/EncounterArea6AO.cs index 48bf90cb4..4cac70cf4 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea6AO.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea6AO.cs @@ -27,7 +27,7 @@ protected override IEnumerable GetMatchFromEvoLevel(PKM pkm, IEnu protected override IEnumerable GetFilteredSlots(PKM pkm, IEnumerable slots, int minLevel) { - EncounterSlot slotMax = null; + EncounterSlot? slotMax = null; foreach (EncounterSlot s in slots) { if (Legal.WildForms.Contains(pkm.Species) && s.Form != pkm.AltForm) diff --git a/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs b/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs index 5b0cad7e1..375c3a368 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs @@ -11,7 +11,7 @@ public sealed class EncounterArea6XY : EncounterArea32 { protected override IEnumerable GetFilteredSlots(PKM pkm, IEnumerable slots, int minLevel) { - EncounterSlot slotMax = null; + EncounterSlot? slotMax = null; void CachePressureSlot(EncounterSlot s) { if (slotMax == null || s.LevelMax > slotMax.LevelMax) diff --git a/PKHeX.Core/Legality/Areas/EncounterArea7.cs b/PKHeX.Core/Legality/Areas/EncounterArea7.cs index 7b5ce030e..13cf72792 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea7.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea7.cs @@ -21,7 +21,7 @@ protected override IEnumerable GetFilteredSlots(PKM pkm, IEnumera yield break; } - EncounterSlot slotMax = null; + EncounterSlot? slotMax = null; void CachePressureSlot(EncounterSlot s) { if (slotMax != null && s.LevelMax > slotMax.LevelMax) diff --git a/PKHeX.Core/Legality/Areas/TreesArea.cs b/PKHeX.Core/Legality/Areas/TreesArea.cs index defc6a331..1ba43ad4c 100644 --- a/PKHeX.Core/Legality/Areas/TreesArea.cs +++ b/PKHeX.Core/Legality/Areas/TreesArea.cs @@ -30,26 +30,19 @@ private static int[][] GenerateTrainersTreeIndex() internal static TreesArea[] GetArray(byte[][] entries) => entries.Select(z => new TreesArea(z)).ToArray(); - public int Location { get; private set; } - private TreeEncounterAvailable[] TrainerModerateEncounterTree { get; set; } - private TreeEncounterAvailable[] TrainerLowEncounterTree { get; set; } - private int[] ValidTreeIndex { get; set; } - private int[] InvalidTreeIndex { get; set; } - private TreeCoordinates[] ValidTrees { get; set; } - private TreeCoordinates[] InvalidTrees { get; set; } + public readonly int Location; + private readonly TreeEncounterAvailable[] TrainerModerateEncounterTree; + private readonly TreeEncounterAvailable[] TrainerLowEncounterTree; + private readonly int[] ValidTreeIndex; + private readonly int[] InvalidTreeIndex; + private readonly TreeCoordinates[] ValidTrees; + private readonly TreeCoordinates[] InvalidTrees; public TreeEncounterAvailable[] GetTrees(SlotType t) => t == SlotType.Headbutt ? TrainerModerateEncounterTree : TrainerLowEncounterTree; private TreesArea(byte[] entry) - { - ReadAreaRawData(entry); - GenerateAreaTreeIndex(); - GenerateAreaTrainerEncounters(); - } - - private void ReadAreaRawData(byte[] entry) { // Coordinates of trees were obtained with the program G2Map // ValidTrees are those accessible by the player @@ -64,18 +57,12 @@ private void ReadAreaRawData(byte[] entry) ofs++; for (int i = 0; i < InvalidTrees.Length; i++, ofs += 2) InvalidTrees[i] = new TreeCoordinates(entry[ofs], entry[ofs + 1]); - } - private void GenerateAreaTreeIndex() - { // For legality purposes, only the tree index is needed. // Group the trees data by their index; trees that share indexes are indistinguishable from one another ValidTreeIndex = ValidTrees.Select(t => t.Index).Distinct().OrderBy(i => i).ToArray(); InvalidTreeIndex = InvalidTrees.Select(t => t.Index).Distinct().OrderBy(i => i).Except(ValidTreeIndex).ToArray(); - } - private void GenerateAreaTrainerEncounters() - { // Check for every trainer pivot index if there are trees with moderate encounter and low encounter available in the area TrainerModerateEncounterTree = new TreeEncounterAvailable[PivotCount]; TrainerLowEncounterTree = new TreeEncounterAvailable[PivotCount]; diff --git a/PKHeX.Core/Legality/Core.cs b/PKHeX.Core/Legality/Core.cs index 7a492f3fa..cc010dcbe 100644 --- a/PKHeX.Core/Legality/Core.cs +++ b/PKHeX.Core/Legality/Core.cs @@ -16,56 +16,59 @@ public static partial class Legal public static string EReaderBerryDisplayName => string.Format(LegalityCheckStrings.L_XEnigmaBerry_0, Util.ToTitleCase(EReaderBerryName.ToLower())); // Gen 1 - internal static readonly Learnset[] LevelUpRB = Learnset1.GetArray(Util.GetBinaryResource("lvlmove_rb.pkl"), MaxSpeciesID_1); - internal static readonly Learnset[] LevelUpY = Learnset1.GetArray(Util.GetBinaryResource("lvlmove_y.pkl"), MaxSpeciesID_1); + internal static readonly Learnset[] LevelUpRB = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_rb.pkl"), MaxSpeciesID_1); + internal static readonly Learnset[] LevelUpY = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_y.pkl"), MaxSpeciesID_1); // Gen 2 internal static readonly EggMoves[] EggMovesGS = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_gs.pkl"), MaxSpeciesID_2); - internal static readonly Learnset[] LevelUpGS = Learnset1.GetArray(Util.GetBinaryResource("lvlmove_gs.pkl"), MaxSpeciesID_2); + internal static readonly Learnset[] LevelUpGS = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_gs.pkl"), MaxSpeciesID_2); internal static readonly EggMoves[] EggMovesC = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_c.pkl"), MaxSpeciesID_2); - internal static readonly Learnset[] LevelUpC = Learnset1.GetArray(Util.GetBinaryResource("lvlmove_c.pkl"), MaxSpeciesID_2); + internal static readonly Learnset[] LevelUpC = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_c.pkl"), MaxSpeciesID_2); // Gen 3 - internal static readonly Learnset[] LevelUpE = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_e.pkl"), "em")); - internal static readonly Learnset[] LevelUpRS = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_rs.pkl"), "rs")); - internal static readonly Learnset[] LevelUpFR = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_fr.pkl"), "fr")); - internal static readonly Learnset[] LevelUpLG = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_lg.pkl"), "lg")); - internal static readonly EggMoves[] EggMovesRS = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_rs.pkl"), "rs")); + internal static readonly Learnset[] LevelUpE = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_e.pkl"), "em")); + internal static readonly Learnset[] LevelUpRS = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_rs.pkl"), "rs")); + internal static readonly Learnset[] LevelUpFR = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_fr.pkl"), "fr")); + internal static readonly Learnset[] LevelUpLG = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_lg.pkl"), "lg")); + internal static readonly EggMoves6[] EggMovesRS = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_rs.pkl"), "rs")); // Gen 4 - internal static readonly Learnset[] LevelUpDP = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_dp.pkl"), "dp")); - internal static readonly Learnset[] LevelUpPt = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_pt.pkl"), "pt")); - internal static readonly Learnset[] LevelUpHGSS = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_hgss.pkl"), "hs")); - internal static readonly EggMoves[] EggMovesDPPt = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_dppt.pkl"), "dp")); - internal static readonly EggMoves[] EggMovesHGSS = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_hgss.pkl"), "hs")); + internal static readonly Learnset[] LevelUpDP = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_dp.pkl"), "dp")); + internal static readonly Learnset[] LevelUpPt = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_pt.pkl"), "pt")); + internal static readonly Learnset[] LevelUpHGSS = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_hgss.pkl"), "hs")); + internal static readonly EggMoves6[] EggMovesDPPt = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_dppt.pkl"), "dp")); + internal static readonly EggMoves6[] EggMovesHGSS = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_hgss.pkl"), "hs")); // Gen 5 - internal static readonly Learnset[] LevelUpBW = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_bw.pkl"), "51")); - internal static readonly Learnset[] LevelUpB2W2 = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_b2w2.pkl"), "52")); - internal static readonly EggMoves[] EggMovesBW = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_bw.pkl"), "bw")); + internal static readonly Learnset[] LevelUpBW = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_bw.pkl"), "51")); + internal static readonly Learnset[] LevelUpB2W2 = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_b2w2.pkl"), "52")); + internal static readonly EggMoves6[] EggMovesBW = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_bw.pkl"), "bw")); // Gen 6 - internal static readonly EggMoves[] EggMovesXY = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_xy.pkl"), "xy")); - internal static readonly Learnset[] LevelUpXY = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_xy.pkl"), "xy")); - internal static readonly EggMoves[] EggMovesAO = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_ao.pkl"), "ao")); - internal static readonly Learnset[] LevelUpAO = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_ao.pkl"), "ao")); + internal static readonly EggMoves6[] EggMovesXY = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_xy.pkl"), "xy")); + internal static readonly Learnset[] LevelUpXY = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_xy.pkl"), "xy")); + internal static readonly EggMoves6[] EggMovesAO = EggMoves6.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_ao.pkl"), "ao")); + internal static readonly Learnset[] LevelUpAO = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_ao.pkl"), "ao")); // Gen 7 - internal static readonly EggMoves[] EggMovesSM = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_sm.pkl"), "sm")); - internal static readonly Learnset[] LevelUpSM = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm")); - internal static readonly EggMoves[] EggMovesUSUM = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_uu.pkl"), "uu")); - internal static readonly Learnset[] LevelUpUSUM = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_uu.pkl"), "uu")); - internal static readonly Learnset[] LevelUpGG = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_gg.pkl"), "gg")); + internal static readonly EggMoves7[] EggMovesSM = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_sm.pkl"), "sm")); + internal static readonly Learnset[] LevelUpSM = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm")); + internal static readonly EggMoves7[] EggMovesUSUM = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_uu.pkl"), "uu")); + internal static readonly Learnset[] LevelUpUSUM = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_uu.pkl"), "uu")); + internal static readonly Learnset[] LevelUpGG = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_gg.pkl"), "gg")); // Gen 8 - internal static readonly EggMoves[] EggMovesSWSH = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_sm.pkl"), "sm")); - internal static readonly Learnset[] LevelUpSWSH = Learnset6.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm")); + internal static readonly EggMoves7[] EggMovesSWSH = EggMoves7.GetArray(Data.UnpackMini(Util.GetBinaryResource("eggmove_sm.pkl"), "sm")); + internal static readonly Learnset[] LevelUpSWSH = LearnsetReader.GetArray(Data.UnpackMini(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm")); // Setup Help static Legal() { // Misc Fixes to Data pertaining to legality constraints - Array.Resize(ref EggMovesUSUM[198].Moves, 15); // Remove Punishment from USUM Murkrow (no species can pass it #1829) + + // Remove Punishment from USUM Murkrow (no species can pass it #1829) + // DONE: Egg Move Data for EggMovesUSUM no longer has it at the end + // Prevent Silvally from being tutored Fire/Water Pledge (logic can only tutor one, and Grass is first) var pi = PersonalTable.USUM[773]; pi.TypeTutors[1] = false; // fire @@ -563,7 +566,7 @@ internal static bool IsEvolutionValidWithMove(PKM pkm, LegalInfo info) // Check also if the current encounter include the evolve move as an special move // That means the pokemon have the move from the encounter level - if (info.EncounterMatch is IMoveset s && s.Moves?.Any(m => moves.Contains(m)) == true) + if (info.EncounterMatch is IMoveset s && s.Moves.Any(m => moves.Contains(m))) LearnLevel = Math.Min(LearnLevel, info.EncounterMatch.LevelMin); // If the encounter is a player hatched egg check if the move could be an egg move or inherited level up move diff --git a/PKHeX.Core/Legality/Data.cs b/PKHeX.Core/Legality/Data.cs index b5319599c..1f48e6e3d 100644 --- a/PKHeX.Core/Legality/Data.cs +++ b/PKHeX.Core/Legality/Data.cs @@ -10,13 +10,13 @@ public static class Data /// Packed data /// Signature expected in the first two bytes (ASCII) /// Unpacked array containing all files that were packed. - public static byte[][] UnpackMini(byte[] fileData, string identifier) + public static byte[][] UnpackMini(byte[]? fileData, string identifier) { if (fileData == null || fileData.Length < 4) - return null; + throw new ArgumentException(nameof(fileData)); if (identifier[0] != fileData[0] || identifier[1] != fileData[1]) - return null; + throw new ArgumentException(nameof(identifier)); int count = BitConverter.ToUInt16(fileData, 2); int ctr = 4; int start = BitConverter.ToInt32(fileData, ctr); ctr += 4; diff --git a/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs b/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs index 72b329032..d7d5fbe7a 100644 --- a/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs +++ b/PKHeX.Core/Legality/Encounters/Data/EncounterEvent.cs @@ -38,11 +38,11 @@ public static class EncounterEvent private static HashSet GetPGFDB(byte[] bin) => new HashSet(ArrayUtil.EnumerateSplit(bin, PGF.Size).Select(d => new PGF(d))); private static HashSet GetWC6DB(byte[] wc6bin, byte[] wc6full) => new HashSet( - ArrayUtil.EnumerateSplit(wc6full, WC6.SizeFull).Select(d => new WC6(d)) + ArrayUtil.EnumerateSplit(wc6full, WC6Full.Size).Select(d => new WC6Full(d).Gift) .Concat(ArrayUtil.EnumerateSplit(wc6bin, WC6.Size).Select(d => new WC6(d)))); private static HashSet GetWC7DB(byte[] wc7bin, byte[] wc7full) => new HashSet( - ArrayUtil.EnumerateSplit(wc7full, WC7.SizeFull).Select(d => new WC7(d)) + ArrayUtil.EnumerateSplit(wc7full, WC7Full.Size).Select(d => new WC7Full(d).Gift) .Concat(ArrayUtil.EnumerateSplit(wc7bin, WC7.Size).Select(d => new WC7(d)))); private static HashSet GetWB7DB(byte[] wc7full) => new HashSet(ArrayUtil.EnumerateSplit(wc7full, WB7.SizeFull).Select(d => new WB7(d))); diff --git a/PKHeX.Core/Legality/Encounters/Data/EncounterUtil.cs b/PKHeX.Core/Legality/Encounters/Data/EncounterUtil.cs index a354bc151..59271039d 100644 --- a/PKHeX.Core/Legality/Encounters/Data/EncounterUtil.cs +++ b/PKHeX.Core/Legality/Encounters/Data/EncounterUtil.cs @@ -243,13 +243,13 @@ private static EncounterStatic DreamRadarClone(this EncounterStatic s, int level internal static void MarkEncounterTradeStrings(EncounterTrade[] table, string[][] strings) { int half = strings[1].Length / 2; - for (var i = 0; i < half; i++) + for (int i = 0; i < half; i++) { var t = table[i]; t.Nicknames = getNames(i, strings); t.TrainerNames = getNames(i + half, strings); } - string[] getNames(int i, IEnumerable names) => names?.Select(z => z?.Length > i ? z[i] : null).ToArray(); + string[] getNames(int i, IEnumerable names) => names.Select(z => z.Length > i ? z[i] : string.Empty).ToArray(); } internal static void MarkEncounterGame(IEnumerable table, GameVersion version) diff --git a/PKHeX.Core/Legality/Encounters/Data/Encounters1.cs b/PKHeX.Core/Legality/Encounters/Data/Encounters1.cs index 1befc28e0..39b827d38 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Encounters1.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Encounters1.cs @@ -31,7 +31,7 @@ static Encounters1() StaticRBY.SetVersion(GameVersion.RBY); } - internal static readonly string[] TradeOTG1 = {null, "トレーナー", "Trainer", "Dresseur", "Allenatore", "Trainer", null, "Entrenador", "트레이너"}; + internal static readonly string[] TradeOTG1 = {string.Empty, "トレーナー", "Trainer", "Dresseur", "Allenatore", "Trainer", string.Empty, "Entrenador", "트레이너"}; private static EncounterArea1[] GetAreas() { diff --git a/PKHeX.Core/Legality/Encounters/Data/Encounters3.cs b/PKHeX.Core/Legality/Encounters/Data/Encounters3.cs index c8b330c90..e723c2267 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Encounters3.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Encounters3.cs @@ -273,6 +273,13 @@ private static void MarkG3SlotsSafariZones(ref EncounterArea3[] Areas, int locat private static readonly string[][] TradeRSE = Util.GetLanguageStrings7(tradeRSE); private static readonly string[][] TradeFRLG = Util.GetLanguageStrings7(tradeFRLG); + private static readonly int[] MoveSwarmSurskit = { 145, 098 }; /* Bubble, Quick Attack */ + private static readonly int[] MoveSwarmSeedot = { 145, 098 }; /* Bide, Harden, Leech Seed */ + private static readonly int[] MoveSwarmNuzleaf = { 145, 098 }; /* Harden, Growth, Nature Power, Leech Seed */ + private static readonly int[] MoveSwarmSeedotF = { 202, 218, 076, 073 }; /* Giga Drain, Frustration, Solar Beam, Leech Seed */ + private static readonly int[] MoveSwarmSkittyRS = { 045, 033 }; /* Growl, Tackle */ + private static readonly int[] MoveSwarmSkittyE = { 045, 033, 039, 213 }; /* Growl, Tackle, Tail Whip, Attract */ + #region AltSlots private static readonly EncounterArea3[] SlotsRSEAlt = { @@ -280,38 +287,38 @@ private static void MarkG3SlotsSafariZones(ref EncounterArea3[] Areas, int locat // Encounter Percent is a 50% call new EncounterArea3 { Location = 17, // Route 102 - Slots = new[] + Slots = new EncounterSlot[] { - new EncounterSlotMoves { Species = 283, LevelMin = 03, LevelMax = 03, Type = SlotType.Swarm, Moves = new[] {145, 098} /* Bubble, Quick Attack */ }, // Surskit (R/S) - new EncounterSlotMoves { Species = 273, LevelMin = 03, LevelMax = 03, Type = SlotType.Swarm, Moves = new[] {117, 106, 073} /* Bide, Harden, Leech Seed */ }, // Seedot (E) + new EncounterSlot3Swarm(MoveSwarmSurskit) { Species = 283, LevelMin = 03, LevelMax = 03, Type = SlotType.Swarm }, + new EncounterSlot3Swarm(MoveSwarmSeedot) { Species = 273, LevelMin = 03, LevelMax = 03, Type = SlotType.Swarm }, },}, new EncounterArea3 { Location = 29, // Route 114 - Slots = new[] + Slots = new EncounterSlot[] { - new EncounterSlotMoves { Species = 283, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm, Moves = new[] {145, 098} /* Bubble, Quick Attack */ }, // Surskit (R/S) - new EncounterSlotMoves { Species = 274, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm, Moves = new[] {106, 074, 267, 073} /* Harden, Growth, Nature Power, Leech Seed */ }, // Nuzleaf (E) + new EncounterSlot3Swarm(MoveSwarmSurskit) { Species = 283, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm }, + new EncounterSlot3Swarm(MoveSwarmNuzleaf) { Species = 274, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm }, },}, new EncounterArea3 { Location = 31, // Route 116 - Slots = new[] + Slots = new EncounterSlot[] { - new EncounterSlotMoves { Species = 300, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm, Moves = new[] {045, 033} /* Growl, Tackle */ }, // Skitty (R/S) - new EncounterSlotMoves { Species = 300, LevelMin = 08, LevelMax = 08, Type = SlotType.Swarm, Moves = new[] {045, 033, 039, 213} /* Growl, Tackle, Tail Whip, Attract */ }, // Skitty (E) + new EncounterSlot3Swarm(MoveSwarmSkittyRS) { Species = 300, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm }, + new EncounterSlot3Swarm(MoveSwarmSkittyE) { Species = 300, LevelMin = 08, LevelMax = 08, Type = SlotType.Swarm }, },}, new EncounterArea3 { Location = 32, // Route 117 - Slots = new[] + Slots = new EncounterSlot[] { - new EncounterSlotMoves { Species = 283, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm, Moves = new[] {145, 098} /* Bubble, Quick Attack */ }, // Surskit (R/S) - new EncounterSlotMoves { Species = 273, LevelMin = 13, LevelMax = 13, Type = SlotType.Swarm, Moves = new[] {106, 074, 267, 073} /* Harden, Growth, Nature Power, Leech Seed */ }, // Seedot (E) + new EncounterSlot3Swarm(MoveSwarmSurskit) { Species = 283, LevelMin = 15, LevelMax = 15, Type = SlotType.Swarm }, + new EncounterSlot3Swarm(MoveSwarmNuzleaf) { Species = 273, LevelMin = 13, LevelMax = 13, Type = SlotType.Swarm }, // Has same moves as Nuzleaf },}, new EncounterArea3 { Location = 35, // Route 120 - Slots = new[] + Slots = new EncounterSlot[] { - new EncounterSlotMoves { Species = 283, LevelMin = 28, LevelMax = 28, Type = SlotType.Swarm, Moves = new[] {145, 098} /* Bubble, Quick Attack */ }, // Surskit (R/S) - new EncounterSlotMoves { Species = 273, LevelMin = 25, LevelMax = 25, Type = SlotType.Swarm, Moves = new[] {202, 218, 076, 073} /* Giga Drain, Frustration, Solar Beam, Leech Seed */ }, // Seedot (E) + new EncounterSlot3Swarm(MoveSwarmSurskit) { Species = 283, LevelMin = 28, LevelMax = 28, Type = SlotType.Swarm }, + new EncounterSlot3Swarm(MoveSwarmSeedotF) { Species = 273, LevelMin = 25, LevelMax = 25, Type = SlotType.Swarm }, },}, // Feebas fishing spot @@ -356,7 +363,7 @@ private static EncounterArea3 GetUnownArea(int location, IReadOnlyList Slot new EncounterStatic { Gift = true, Species = 196, Level = 25, Location = 254, Gender = 0 }, // Espeon new EncounterStatic { Gift = true, Species = 197, Level = 26, Location = 254, Gender = 0, Moves = new[] {044} }, // Umbreon (Bite) - new EncounterStaticShadow { Species = 296, Level = 30, Gauge = 03000, Moves = new[] {193,116,233,238}, Location = 005, Locks = ColoMakuhita }, // Makuhita: Miror B.Peon Trudly @ Phenac City + new EncounterStaticShadow(ColoMakuhita) { Species = 296, Level = 30, Gauge = 03000, Moves = new[] {193,116,233,238}, Location = 005 }, // Makuhita: Miror B.Peon Trudly @ Phenac City new EncounterStaticShadow { Species = 153, Level = 30, Gauge = 03000, Moves = new[] {241,235,075,034}, Location = 003 }, // Bayleef: Cipher Peon Verde @ Phenac City new EncounterStaticShadow { Species = 156, Level = 30, Gauge = 03000, Moves = new[] {241,108,091,172}, Location = 003 }, // Quilava: Cipher Peon Rosso @ Phenac City @@ -415,8 +422,6 @@ private static EncounterArea3 GetUnownArea(int location, IReadOnlyList Slot new EncounterStaticShadow { Species = 243, Level = 40, Gauge = 13000, Moves = new[] {240,043,098,087}, Location = 125 }, // Raikou: Cipher Admin Ein @ Deep Colosseum new EncounterStaticShadow { Species = 243, Level = 40, Gauge = 13000, Moves = new[] {240,043,098,087}, Location = 069 }, // Raikou: Cipher Admin Ein @ Shadow PKMN Lab - new EncounterStaticShadow { Species = 207, Level = 43, Gauge = 06000, Moves = new[] {185,028,040,163}, Location = 058, Locks = Gligar }, // Gligar: Hunter Frena @ The Under Subway - new EncounterStaticShadow { Species = 207, Level = 43, Gauge = 06000, Moves = new[] {185,028,040,163}, Location = 133, Locks = Gligar }, // Gligar: Hunter Frena @ Snagem Hideout new EncounterStaticShadow { Species = 234, Level = 43, Gauge = 06000, Moves = new[] {310,095,043,036}, Location = 058 }, // Stantler: Chaser Liaks @ The Under Subway new EncounterStaticShadow { Species = 234, Level = 43, Gauge = 06000, Moves = new[] {310,095,043,036}, Location = 133 }, // Stantler: Chaser Liaks @ Snagem Hideout new EncounterStaticShadow { Species = 221, Level = 43, Gauge = 06000, Moves = new[] {203,316,091,059}, Location = 058 }, // Piloswine: Bodybuilder Lonia @ The Under Subway @@ -424,7 +429,6 @@ private static EncounterArea3 GetUnownArea(int location, IReadOnlyList Slot new EncounterStaticShadow { Species = 215, Level = 43, Gauge = 06000, Moves = new[] {185,103,154,196}, Location = 058 }, // Sneasel: Rider Nelis @ The Under Subway new EncounterStaticShadow { Species = 215, Level = 43, Gauge = 06000, Moves = new[] {185,103,154,196}, Location = 134 }, // Sneasel: Rider Nelis @ Snagem Hideout new EncounterStaticShadow { Species = 190, Level = 43, Gauge = 06000, Moves = new[] {226,321,154,129}, Location = 067 }, // Aipom: Cipher Peon Cole @ Shadow PKMN Lab - new EncounterStaticShadow { Species = 198, Level = 43, Gauge = 06000, Moves = new[] {185,212,101,019}, Location = 067, Locks = Murkrow }, // Murkrow: Cipher Peon Lare @ Shadow PKMN Lab new EncounterStaticShadow { Species = 205, Level = 43, Gauge = 06000, Moves = new[] {153,182,117,229}, Location = 067 }, // Forretress: Cipher Peon Vana @ Shadow PKMN Lab new EncounterStaticShadow { Species = 168, Level = 43, Gauge = 06000, Moves = new[] {169,184,141,188}, Location = 069 }, // Ariados: Cipher Peon Lesar @ Shadow PKMN Lab new EncounterStaticShadow { Species = 210, Level = 43, Gauge = 06000, Moves = new[] {044,184,046,070}, Location = 069 }, // Granbull: Cipher Peon Tanie @ Shadow PKMN Lab @@ -432,7 +436,6 @@ private static EncounterArea3 GetUnownArea(int location, IReadOnlyList Slot new EncounterStaticShadow { Species = 192, Level = 45, Gauge = 07000, Moves = new[] {241,074,275,076}, Location = 109 }, // Sunflora: Cipher Peon Baila @ Realgam Tower new EncounterStaticShadow { Species = 225, Level = 45, Gauge = 07000, Moves = new[] {059,213,217,019}, Location = 109 }, // Delibird: Cipher Peon Arton @ Realgam Tower - new EncounterStaticShadow { Species = 214, Level = 45, Gauge = 07000, Moves = new[] {179,203,068,280}, Location = 111, Locks = Heracross }, // Heracross: Cipher Peon Dioge @ Realgam Tower new EncounterStaticShadow { Species = 227, Level = 47, Gauge = 13000, Moves = new[] {065,319,314,211}, Location = 117 }, // Skarmory: Snagem Head Gonzap @ Realgam Tower new EncounterStaticShadow { Species = 192, Level = 45, Gauge = 07000, Moves = new[] {241,074,275,076}, Location = 132 }, // Sunflora: Cipher Peon Baila @ Snagem Hideout new EncounterStaticShadow { Species = 225, Level = 45, Gauge = 07000, Moves = new[] {059,213,217,019}, Location = 132 }, // Delibird: Cipher Peon Arton @ Snagem Hideout @@ -446,12 +449,17 @@ private static EncounterArea3 GetUnownArea(int location, IReadOnlyList Slot new EncounterStaticShadow { Species = 376, Level = 50, Gauge = 15000, Moves = new[] {063,334,232,094}, Location = 118 }, // Metagross: Cipher Nascour @ Tower Colosseum new EncounterStaticShadow { Species = 248, Level = 55, Gauge = 20000, Moves = new[] {242,087,157,059}, Location = 118 }, // Tyranitar: Cipher Head Evice @ Tower Colosseum new EncounterStaticShadow { Species = 235, Level = 45, Gauge = 07000, Moves = new[] {166,039,003,231}, Location = 132 }, // Smeargle: Team Snagem Biden @ Snagem Hideout - new EncounterStaticShadow { Species = 217, Level = 45, Gauge = 07000, Moves = new[] {185,313,122,163}, Location = 132, Locks = Ursaring }, // Ursaring: Team Snagem Agrev @ Snagem Hideout new EncounterStaticShadow { Species = 213, Level = 45, Gauge = 07000, Moves = new[] {219,227,156,117}, Location = 125 }, // Shuckle: Deep King Agnol @ Deep Colosseum new EncounterStaticShadow { Species = 176, Level = 20, Gauge = 05000, Moves = new[] {118,204,186,281}, Location = 001 }, // Togetic: Cipher Peon Fein @ Outskirt Stand - new EncounterStaticShadow { Species = 175, Level = 20, Gauge = 00000, Moves = new[] {118,204,186,281}, IVs = new[] {0,0,0,0,0,0}, EReader = true, Locks = CTogepi }, // Togepi: Chaser ボデス @ Card e Room (Japanese games only) - new EncounterStaticShadow { Species = 179, Level = 37, Gauge = 00000, Moves = new[] {087,084,086,178}, IVs = new[] {0,0,0,0,0,0}, EReader = true, Locks = CMareep }, // Mareep: Hunter ホル @ Card e Room (Japanese games only) - new EncounterStaticShadow { Species = 212, Level = 50, Gauge = 00000, Moves = new[] {210,232,014,163}, IVs = new[] {0,0,0,0,0,0}, EReader = true, Locks = CScizor }, // Scizor: Bodybuilder ワーバン @ Card e Room (Japanese games only) + + new EncounterStaticShadow(Gligar) { Species = 207, Level = 43, Gauge = 06000, Moves = new[] {185,028,040,163}, Location = 058 }, // Gligar: Hunter Frena @ The Under Subway + new EncounterStaticShadow(Gligar) { Species = 207, Level = 43, Gauge = 06000, Moves = new[] {185,028,040,163}, Location = 133 }, // Gligar: Hunter Frena @ Snagem Hideout + new EncounterStaticShadow(Murkrow) { Species = 198, Level = 43, Gauge = 06000, Moves = new[] {185,212,101,019}, Location = 067 }, // Murkrow: Cipher Peon Lare @ Shadow PKMN Lab + new EncounterStaticShadow(Heracross) { Species = 214, Level = 45, Gauge = 07000, Moves = new[] {179,203,068,280}, Location = 111, }, // Heracross: Cipher Peon Dioge @ Realgam Tower + new EncounterStaticShadow(Ursaring) { Species = 217, Level = 45, Gauge = 07000, Moves = new[] {185,313,122,163}, Location = 132 }, // Ursaring: Team Snagem Agrev @ Snagem Hideout + new EncounterStaticShadow(CTogepi) { Species = 175, Level = 20, Gauge = 00000, Moves = new[] {118,204,186,281}, IVs = new[] {0,0,0,0,0,0}, EReader = true }, // Togepi: Chaser ボデス @ Card e Room (Japanese games only) + new EncounterStaticShadow(CMareep) { Species = 179, Level = 37, Gauge = 00000, Moves = new[] {087,084,086,178}, IVs = new[] {0,0,0,0,0,0}, EReader = true }, // Mareep: Hunter ホル @ Card e Room (Japanese games only) + new EncounterStaticShadow(CScizor) { Species = 212, Level = 50, Gauge = 00000, Moves = new[] {210,232,014,163}, IVs = new[] {0,0,0,0,0,0}, EReader = true }, // Scizor: Bodybuilder ワーバン @ Card e Room (Japanese games only) }; #endregion @@ -474,113 +482,113 @@ private static EncounterArea3 GetUnownArea(int location, IReadOnlyList Slot new EncounterStatic { Fateful = true, Gift = true, Species = 158, Level = 05, Location = 016, Moves = new[] {242,010,043,308} }, // Totodile new EncounterStaticShadow { Fateful = true, Species = 216, Level = 11, Gauge = 03000, Moves = new[] {216,287,122,232}, Location = 143 }, // Teddiursa: Cipher Peon Naps @ Pokémon HQ Lab - new EncounterStaticShadow { Fateful = true, Species = 165, Level = 10, Gauge = 02500, Moves = new[] {060,287,332,048}, Location = 153, Locks = Ledyba, }, // Ledyba: Casual Guy Cyle @ Gateon Port - new EncounterStaticShadow { Fateful = true, Species = 261, Level = 10, Gauge = 02500, Moves = new[] {091,215,305,336}, Location = 162, Locks = Poochyena, }, // Poochyena: Bodybuilder Kilen @ Gateon Port new EncounterStaticShadow { Fateful = true, Species = 228, Level = 17, Gauge = 01500, Moves = new[] {185,204,052,046}, Location = 011, }, // Houndour: Cipher Peon Resix @ Cipher Lab new EncounterStaticShadow { Fateful = true, Species = 343, Level = 17, Gauge = 01500, Moves = new[] {317,287,189,060}, Location = 011, }, // Baltoy: Cipher Peon Browsix @ Cipher Lab new EncounterStaticShadow { Fateful = true, Species = 179, Level = 17, Gauge = 01500, Moves = new[] {034,215,084,086}, Location = 011, }, // Mareep: Cipher Peon Yellosix @ Cipher Lab - new EncounterStaticShadow { Fateful = true, Species = 273, Level = 17, Gauge = 01500, Moves = new[] {202,287,331,290}, Location = 011, Locks = Seedot, }, // Seedot: Cipher Peon Greesix @ Cipher Lab - new EncounterStaticShadow { Fateful = true, Species = 363, Level = 17, Gauge = 01500, Moves = new[] {062,204,055,189}, Location = 011, Locks = Spheal, }, // Spheal: Cipher Peon Blusix @ Cipher Lab - new EncounterStaticShadow { Fateful = true, Species = 316, Level = 17, Gauge = 01500, Moves = new[] {351,047,124,092}, Location = 011, Locks = Gulpin, }, // Gulpin: Cipher Peon Purpsix @ Cipher Lab - new EncounterStaticShadow { Fateful = true, Species = 167, Level = 14, Gauge = 01500, Moves = new[] {091,287,324,101}, Location = 010, Locks = Spinarak, }, // Spinarak: Cipher Peon Nexir @ Cipher Lab - new EncounterStaticShadow { Fateful = true, Species = 322, Level = 14, Gauge = 01500, Moves = new[] {036,204,091,052}, Location = 009, Locks = Numel, }, // Numel: Cipher Peon Solox @ Cipher Lab new EncounterStaticShadow { Fateful = true, Species = 318, Level = 15, Gauge = 01700, Moves = new[] {352,287,184,044}, Location = 008, }, // Carvanha: Cipher Peon Cabol @ Cipher Lab - new EncounterStaticShadow { Fateful = true, Species = 285, Level = 15, Gauge = 01800, Moves = new[] {206,287,072,078}, Location = 008, Locks = Shroomish, }, // Shroomish: Cipher R&D Klots @ Cipher Lab - new EncounterStaticShadow { Fateful = true, Species = 301, Level = 18, Gauge = 02500, Moves = new[] {290,186,213,351}, Location = 008, Locks = Delcatty, }, // Delcatty: Cipher Admin Lovrina @ Cipher Lab - new EncounterStaticShadow { Fateful = true, Species = 100, Level = 19, Gauge = 02500, Moves = new[] {243,287,209,129}, Location = 092, Locks = Voltorb, }, // Voltorb: Wanderer Miror B. @ Cave Poké Spot - new EncounterStaticShadow { Fateful = true, Species = 296, Level = 18, Gauge = 02000, Moves = new[] {280,287,292,317}, Location = 109, Locks = Makuhita, }, // Makuhita: Cipher Peon Torkin @ ONBS Building - new EncounterStaticShadow { Fateful = true, Species = 037, Level = 18, Gauge = 02000, Moves = new[] {257,204,052,091}, Location = 109, Locks = Vulpix, }, // Vulpix: Cipher Peon Mesin @ ONBS Building - new EncounterStaticShadow { Fateful = true, Species = 355, Level = 19, Gauge = 02200, Moves = new[] {247,270,310,109}, Location = 110, Locks = Duskull, }, // Duskull: Cipher Peon Lobar @ ONBS Building - new EncounterStaticShadow { Fateful = true, Species = 280, Level = 20, Gauge = 02200, Moves = new[] {351,047,115,093}, Location = 119, Locks = Ralts, }, // Ralts: Cipher Peon Feldas @ ONBS Building - new EncounterStaticShadow { Fateful = true, Species = 303, Level = 22, Gauge = 02500, Moves = new[] {206,047,011,334}, Location = 111, Locks = Mawile, }, // Mawile: Cipher Cmdr Exol @ ONBS Building - new EncounterStaticShadow { Fateful = true, Species = 361, Level = 20, Gauge = 02500, Moves = new[] {352,047,044,196}, Location = 097, Locks = Snorunt }, // Snorunt: Cipher Peon Exinn @ Phenac City - new EncounterStaticShadow { Fateful = true, Species = 204, Level = 20, Gauge = 02500, Moves = new[] {042,287,191,068}, Location = 096, Locks = Pineco, }, // Pineco: Cipher Peon Gonrap @ Phenac City - new EncounterStaticShadow { Fateful = true, Species = 177, Level = 22, Gauge = 02500, Moves = new[] {248,226,101,332}, Location = 094, Locks = Natu, }, // Natu: Cipher Peon Eloin @ Phenac City - - new EncounterStaticShadow { Fateful = true, Species = 315, Level = 22, Gauge = 03000, Moves = new[] {345,186,320,073}, Location = 113, Locks = Roselia }, // Roselia: Cipher Peon Fasin @ Phenac City - new EncounterStaticShadow { Fateful = true, Species = 315, Level = 22, Gauge = 03000, Moves = new[] {345,186,320,073}, Location = 094, Locks = Roselia }, // Roselia: Cipher Peon Fasin @ Phenac City - new EncounterStaticShadow { Fateful = true, Species = 052, Level = 22, Gauge = 03500, Moves = new[] {163,047,006,044}, Location = 113, Locks = Meowth }, // Meowth: Cipher Peon Fostin @ Phenac City - new EncounterStaticShadow { Fateful = true, Species = 052, Level = 22, Gauge = 03500, Moves = new[] {163,047,006,044}, Location = 094, Locks = Meowth }, // Meowth: Cipher Peon Fostin @ Phenac City - - new EncounterStaticShadow { Fateful = true, Species = 220, Level = 22, Gauge = 02500, Moves = new[] {246,204,054,341}, Location = 100, Locks = Swinub }, // Swinub: Cipher Peon Greck @ Phenac City - - new EncounterStaticShadow { Fateful = true, Species = 021, Level = 22, Gauge = 04500, Moves = new[] {206,226,043,332}, Location = 059, Locks = Spearow }, // Spearow: Cipher Peon Ezin @ Phenac Stadium - new EncounterStaticShadow { Fateful = true, Species = 021, Level = 22, Gauge = 04500, Moves = new[] {206,226,043,332}, Location = 107, Locks = Spearow }, // Spearow: Cipher Peon Ezin @ Phenac Stadium - new EncounterStaticShadow { Fateful = true, Species = 088, Level = 23, Gauge = 03000, Moves = new[] {188,270,325,107}, Location = 059, Locks = Grimer }, // Grimer: Cipher Peon Faltly @ Phenac Stadium - new EncounterStaticShadow { Fateful = true, Species = 088, Level = 23, Gauge = 03000, Moves = new[] {188,270,325,107}, Location = 107, Locks = Grimer }, // Grimer: Cipher Peon Faltly @ Phenac Stadium - - new EncounterStaticShadow { Fateful = true, Species = 086, Level = 23, Gauge = 03500, Moves = new[] {057,270,219,058}, Location = 107, Locks = Seel }, // Seel: Cipher Peon Egrog @ Phenac Stadium - new EncounterStaticShadow { Fateful = true, Species = 337, Level = 25, Gauge = 05000, Moves = new[] {094,226,240,317}, Location = 107, Locks = Lunatone }, // Lunatone: Cipher Admin Snattle @ Phenac Stadium new EncounterStaticShadow { Fateful = true, Species = 175, Level = 25, Gauge = 04500, Moves = new[] {266,161,246,270}, Location = 164, Gift = true }, // Togepi: Pokémon Trainer Hordel @ Outskirt Stand - new EncounterStaticShadow { Fateful = true, Species = 299, Level = 26, Gauge = 04000, Moves = new[] {085,270,086,157}, Location = 090, Locks = Nosepass }, // Nosepass: Wanderer Miror B. @ Pyrite Colosseum/Realgam Colosseum/Poké Spots - new EncounterStaticShadow { Fateful = true, Species = 299, Level = 26, Gauge = 04000, Moves = new[] {085,270,086,157}, Location = 113, Locks = Nosepass }, // Nosepass: Wanderer Miror B. @ Pyrite Colosseum/Realgam Colosseum/Poké Spots - new EncounterStaticShadow { Fateful = true, Species = 335, Level = 28, Gauge = 05000, Moves = new[] {280,287,068,306}, Location = 071 }, // Zangoose: Thug Zook @ Cipher Key Lair new EncounterStaticShadow { Fateful = true, Species = 335, Level = 28, Gauge = 05000, Moves = new[] {280,287,068,306}, Location = 090 }, // Zangoose: Thug Zook @ Cipher Key Lair - - new EncounterStaticShadow { Fateful = true, Species = 046, Level = 28, Gauge = 04000, Moves = new[] {147,287,163,206}, Location = 064, Locks = Paras }, // Paras: Cipher Peon Humah @ Cipher Key Lair - - new EncounterStaticShadow { Fateful = true, Species = 058, Level = 28, Gauge = 04000, Moves = new[] {053,204,044,036}, Location = 064, Locks = Growlithe }, // Growlithe: Cipher Peon Humah @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 058, Level = 28, Gauge = 04000, Moves = new[] {053,204,044,036}, Location = 113, Locks = Growlithe }, // Growlithe: Cipher Peon Humah @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 015, Level = 30, Gauge = 04500, Moves = new[] {188,226,041,014}, Location = 059 }, // Beedrill: Cipher Peon Lok @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 012, Level = 30, Gauge = 04000, Moves = new[] {094,234,079,332}, Location = 059, Locks = Butterfree }, // Butterfree: Cipher Peon Targ @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 049, Level = 32, Gauge = 04000, Moves = new[] {318,287,164,094}, Location = 059, Locks = Venomoth }, // Venomoth: Cipher Peon Angic @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 097, Level = 34, Gauge = 05500, Moves = new[] {094,226,096,247}, Location = 059, Locks = Hypno }, // Hypno: Cipher Admin Gorigan @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 354, Level = 37, Gauge = 07000, Moves = new[] {185,270,247,174}, Location = 059, Locks = Banette }, // Banette: Cipher Peon Litnar @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 090, Level = 29, Gauge = 04000, Moves = new[] {036,287,057,062}, Location = 065 }, // Shellder: Cipher Peon Gorog @ Cipher Key Lair new EncounterStaticShadow { Fateful = true, Species = 015, Level = 30, Gauge = 04500, Moves = new[] {188,226,041,014}, Location = 066 }, // Beedrill: Cipher Peon Lok @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 017, Level = 30, Gauge = 04000, Moves = new[] {017,287,211,297}, Location = 066, Locks = Pidgeotto }, // Pidgeotto: Cipher Peon Lok @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 114, Level = 30, Gauge = 04000, Moves = new[] {076,234,241,275}, Location = 067, Locks = Tangela }, // Tangela: Cipher Peon Targ @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 012, Level = 30, Gauge = 04000, Moves = new[] {094,234,079,332}, Location = 067, Locks = Butterfree }, // Butterfree: Cipher Peon Targ @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 082, Level = 30, Gauge = 04500, Moves = new[] {038,287,240,087}, Location = 067, Locks = Magneton }, // Magneton: Cipher Peon Snidle @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 049, Level = 32, Gauge = 04000, Moves = new[] {318,287,164,094}, Location = 070, Locks = Venomoth }, // Venomoth: Cipher Peon Angic @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 070, Level = 32, Gauge = 04000, Moves = new[] {345,234,188,230}, Location = 070, Locks = Weepinbell }, // Weepinbell: Cipher Peon Angic @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 024, Level = 33, Gauge = 05000, Moves = new[] {188,287,137,044}, Location = 070, Locks = Arbok }, // Arbok: Cipher Peon Smarton @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 057, Level = 34, Gauge = 06000, Moves = new[] {238,270,116,179}, Location = 069, Locks = Primeape }, // Primeape: Cipher Admin Gorigan @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 097, Level = 34, Gauge = 05500, Moves = new[] {094,226,096,247}, Location = 069, Locks = Hypno }, // Hypno: Cipher Admin Gorigan @ Cipher Key Lair - new EncounterStaticShadow { Fateful = true, Species = 055, Level = 33, Gauge = 06500, Moves = new[] {127,204,244,280}, Location = 088, Locks = Golduck }, // Golduck: Navigator Abson @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 302, Level = 33, Gauge = 07000, Moves = new[] {247,270,185,105}, Location = 088, Locks = Sableye }, // Sableye: Navigator Abson @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 085, Level = 34, Gauge = 08000, Moves = new[] {065,226,097,161}, Location = 076, Locks = Dodrio }, // Dodrio: Chaser Furgy @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 020, Level = 34, Gauge = 06000, Moves = new[] {162,287,184,158}, Location = 076, Locks = Raticate }, // Raticate: Chaser Furgy @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 083, Level = 36, Gauge = 05500, Moves = new[] {163,226,014,332}, Location = 076, Locks = Farfetchd }, // Farfetch'd: Cipher Admin Lovrina @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 334, Level = 36, Gauge = 06500, Moves = new[] {225,215,076,332}, Location = 076, Locks = Altaria }, // Altaria: Cipher Admin Lovrina @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 115, Level = 35, Gauge = 06000, Moves = new[] {089,047,039,146}, Location = 085, Locks = Kangaskhan }, // Kangaskhan: Cipher Peon Litnar @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 354, Level = 37, Gauge = 07000, Moves = new[] {185,270,247,174}, Location = 085, Locks = Banette }, // Banette: Cipher Peon Litnar @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 126, Level = 36, Gauge = 07000, Moves = new[] {126,266,238,009}, Location = 077, Locks = Magmar }, // Magmar: Cipher Peon Grupel @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 127, Level = 35, Gauge = 07000, Moves = new[] {012,270,206,066}, Location = 077, Locks = Pinsir }, // Pinsir: Cipher Peon Grupel @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 078, Level = 40, Gauge = 06000, Moves = new[] {076,226,241,053}, Location = 080, Locks = Rapidash }, // Rapidash: Cipher Peon Kolest @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 219, Level = 38, Gauge = 05500, Moves = new[] {257,287,089,053}, Location = 080, Locks = Magcargo }, // Magcargo: Cipher Peon Kolest @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 107, Level = 38, Gauge = 06000, Moves = new[] {005,270,170,327}, Location = 081, Locks = Hitmonchan }, // Hitmonchan: Cipher Peon Karbon @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 106, Level = 38, Gauge = 07000, Moves = new[] {136,287,170,025}, Location = 081, Locks = Hitmonlee }, // Hitmonlee: Cipher Peon Petro @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 108, Level = 38, Gauge = 05000, Moves = new[] {038,270,111,205}, Location = 084, Locks = Lickitung }, // Lickitung: Cipher Peon Geftal @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 123, Level = 40, Gauge = 08000, Moves = new[] {013,234,318,163}, Location = 084, Locks = Scyther }, // Scyther: Cipher Peon Leden @ Citadark Isle - - new EncounterStaticShadow { Fateful = true, Species = 113, Level = 39, Gauge = 04000, Moves = new[] {085,186,135,285}, Location = 084, Locks = Chansey }, // Chansey: Cipher Peon Leden @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 113, Level = 39, Gauge = 04000, Moves = new[] {085,186,135,285}, Location = 087, Locks = Chansey }, // Chansey: Cipher Peon Leden @ Citadark Isle - - new EncounterStaticShadow { Fateful = true, Species = 338, Level = 41, Gauge = 07500, Moves = new[] {094,226,241,322}, Location = 087, Locks = Solrock }, // Solrock: Cipher Admin Snattle @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 121, Level = 41, Gauge = 07500, Moves = new[] {127,287,058,105}, Location = 087, Locks = Starmie }, // Starmie: Cipher Admin Snattle @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 277, Level = 43, Gauge = 07000, Moves = new[] {143,226,097,263}, Location = 087 }, // Swellow: Cipher Admin Ardos @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 125, Level = 43, Gauge = 07000, Moves = new[] {238,266,086,085}, Location = 087, Locks = Electabuzz }, // Electabuzz: Cipher Admin Ardos @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 143, Level = 43, Gauge = 09000, Moves = new[] {090,287,174,034}, Location = 087, Locks = Snorlax }, // Snorlax: Cipher Admin Ardos @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 062, Level = 42, Gauge = 07500, Moves = new[] {056,270,240,280}, Location = 087, Locks = Poliwrath }, // Poliwrath: Cipher Admin Gorigan @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 122, Level = 42, Gauge = 06500, Moves = new[] {094,266,227,009}, Location = 087, Locks = MrMime }, // Mr. Mime: Cipher Admin Gorigan @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 051, Level = 40, Gauge = 05000, Moves = new[] {089,204,201,161}, Location = 075, Locks = Dugtrio }, // Dugtrio: Cipher Peon Kolax @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 310, Level = 44, Gauge = 07000, Moves = new[] {087,287,240,044}, Location = 073, Locks = Manectric }, // Manectric: Cipher Admin Eldes @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 373, Level = 50, Gauge = 09000, Moves = new[] {337,287,349,332}, Location = 073, Locks = Salamence }, // Salamence: Cipher Admin Eldes @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 105, Level = 44, Gauge = 06500, Moves = new[] {089,047,014,157}, Location = 073, Locks = Marowak }, // Marowak: Cipher Admin Eldes @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 131, Level = 44, Gauge = 06000, Moves = new[] {056,215,240,059}, Location = 073, Locks = Lapras }, // Lapras: Cipher Admin Eldes @ Citadark Isle new EncounterStaticShadow { Fateful = true, Species = 249, Level = 50, Gauge = 12000, Moves = new[] {354,297,089,056}, Location = 074 }, // Lugia: Grand Master Greevil @ Citadark Isle new EncounterStaticShadow { Fateful = true, Species = 112, Level = 46, Gauge = 07000, Moves = new[] {224,270,184,089}, Location = 074 }, // Rhydon: Grand Master Greevil @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 146, Level = 50, Gauge = 10000, Moves = new[] {326,234,261,053}, Location = 074, Locks = Moltres }, // Moltres: Grand Master Greevil @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 103, Level = 46, Gauge = 09000, Moves = new[] {094,287,095,246}, Location = 074, Locks = Exeggutor }, // Exeggutor: Grand Master Greevil @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 128, Level = 46, Gauge = 09000, Moves = new[] {089,287,039,034}, Location = 074, Locks = Tauros }, // Tauros: Grand Master Greevil @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 144, Level = 50, Gauge = 10000, Moves = new[] {326,215,114,058}, Location = 074, Locks = Articuno }, // Articuno: Grand Master Greevil @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 145, Level = 50, Gauge = 10000, Moves = new[] {326,226,319,085}, Location = 074, Locks = Zapdos }, // Zapdos: Grand Master Greevil @ Citadark Isle - new EncounterStaticShadow { Fateful = true, Species = 149, Level = 55, Gauge = 09000, Moves = new[] {063,215,349,089}, Location = 162, Locks = Dragonite }, // Dragonite: Wanderer Miror B. @ Gateon Port + new EncounterStaticShadow { Fateful = true, Species = 277, Level = 43, Gauge = 07000, Moves = new[] {143,226,097,263}, Location = 087 }, // Swellow: Cipher Admin Ardos @ Citadark Isle + + new EncounterStaticShadow(Ledyba) { Fateful = true, Species = 165, Level = 10, Gauge = 02500, Moves = new[] {060,287,332,048}, Location = 153 }, // Ledyba: Casual Guy Cyle @ Gateon Port + new EncounterStaticShadow(Poochyena){ Fateful = true, Species = 261, Level = 10, Gauge = 02500, Moves = new[] {091,215,305,336}, Location = 162 }, // Poochyena: Bodybuilder Kilen @ Gateon Port + new EncounterStaticShadow(Seedot) { Fateful = true, Species = 273, Level = 17, Gauge = 01500, Moves = new[] {202,287,331,290}, Location = 011 }, // Seedot: Cipher Peon Greesix @ Cipher Lab + new EncounterStaticShadow(Spheal) { Fateful = true, Species = 363, Level = 17, Gauge = 01500, Moves = new[] {062,204,055,189}, Location = 011 }, // Spheal: Cipher Peon Blusix @ Cipher Lab + new EncounterStaticShadow(Gulpin) { Fateful = true, Species = 316, Level = 17, Gauge = 01500, Moves = new[] {351,047,124,092}, Location = 011 }, // Gulpin: Cipher Peon Purpsix @ Cipher Lab + new EncounterStaticShadow(Spinarak) { Fateful = true, Species = 167, Level = 14, Gauge = 01500, Moves = new[] {091,287,324,101}, Location = 010 }, // Spinarak: Cipher Peon Nexir @ Cipher Lab + new EncounterStaticShadow(Numel) { Fateful = true, Species = 322, Level = 14, Gauge = 01500, Moves = new[] {036,204,091,052}, Location = 009 }, // Numel: Cipher Peon Solox @ Cipher Lab + new EncounterStaticShadow(Shroomish){ Fateful = true, Species = 285, Level = 15, Gauge = 01800, Moves = new[] {206,287,072,078}, Location = 008 }, // Shroomish: Cipher R&D Klots @ Cipher Lab + new EncounterStaticShadow(Delcatty) { Fateful = true, Species = 301, Level = 18, Gauge = 02500, Moves = new[] {290,186,213,351}, Location = 008 }, // Delcatty: Cipher Admin Lovrina @ Cipher Lab + new EncounterStaticShadow(Voltorb) { Fateful = true, Species = 100, Level = 19, Gauge = 02500, Moves = new[] {243,287,209,129}, Location = 092 }, // Voltorb: Wanderer Miror B. @ Cave Poké Spot + new EncounterStaticShadow(Makuhita) { Fateful = true, Species = 296, Level = 18, Gauge = 02000, Moves = new[] {280,287,292,317}, Location = 109 }, // Makuhita: Cipher Peon Torkin @ ONBS Building + new EncounterStaticShadow(Vulpix) { Fateful = true, Species = 037, Level = 18, Gauge = 02000, Moves = new[] {257,204,052,091}, Location = 109 }, // Vulpix: Cipher Peon Mesin @ ONBS Building + new EncounterStaticShadow(Duskull) { Fateful = true, Species = 355, Level = 19, Gauge = 02200, Moves = new[] {247,270,310,109}, Location = 110 }, // Duskull: Cipher Peon Lobar @ ONBS Building + new EncounterStaticShadow(Ralts) { Fateful = true, Species = 280, Level = 20, Gauge = 02200, Moves = new[] {351,047,115,093}, Location = 119 }, // Ralts: Cipher Peon Feldas @ ONBS Building + new EncounterStaticShadow(Mawile) { Fateful = true, Species = 303, Level = 22, Gauge = 02500, Moves = new[] {206,047,011,334}, Location = 111 }, // Mawile: Cipher Cmdr Exol @ ONBS Building + new EncounterStaticShadow(Snorunt) { Fateful = true, Species = 361, Level = 20, Gauge = 02500, Moves = new[] {352,047,044,196}, Location = 097 }, // Snorunt: Cipher Peon Exinn @ Phenac City + new EncounterStaticShadow(Pineco) { Fateful = true, Species = 204, Level = 20, Gauge = 02500, Moves = new[] {042,287,191,068}, Location = 096 }, // Pineco: Cipher Peon Gonrap @ Phenac City + new EncounterStaticShadow(Natu) { Fateful = true, Species = 177, Level = 22, Gauge = 02500, Moves = new[] {248,226,101,332}, Location = 094 }, // Natu: Cipher Peon Eloin @ Phenac City + + new EncounterStaticShadow(Roselia) { Fateful = true, Species = 315, Level = 22, Gauge = 03000, Moves = new[] {345,186,320,073}, Location = 113, }, // Roselia: Cipher Peon Fasin @ Phenac City + new EncounterStaticShadow(Roselia) { Fateful = true, Species = 315, Level = 22, Gauge = 03000, Moves = new[] {345,186,320,073}, Location = 094, }, // Roselia: Cipher Peon Fasin @ Phenac City + new EncounterStaticShadow(Meowth) { Fateful = true, Species = 052, Level = 22, Gauge = 03500, Moves = new[] {163,047,006,044}, Location = 113, }, // Meowth: Cipher Peon Fostin @ Phenac City + new EncounterStaticShadow(Meowth) { Fateful = true, Species = 052, Level = 22, Gauge = 03500, Moves = new[] {163,047,006,044}, Location = 094, }, // Meowth: Cipher Peon Fostin @ Phenac City + + new EncounterStaticShadow(Swinub) { Fateful = true, Species = 220, Level = 22, Gauge = 02500, Moves = new[] {246,204,054,341}, Location = 100, }, // Swinub: Cipher Peon Greck @ Phenac City + + new EncounterStaticShadow(Spearow) { Fateful = true, Species = 021, Level = 22, Gauge = 04500, Moves = new[] {206,226,043,332}, Location = 059, }, // Spearow: Cipher Peon Ezin @ Phenac Stadium + new EncounterStaticShadow(Spearow) { Fateful = true, Species = 021, Level = 22, Gauge = 04500, Moves = new[] {206,226,043,332}, Location = 107, }, // Spearow: Cipher Peon Ezin @ Phenac Stadium + new EncounterStaticShadow(Grimer) { Fateful = true, Species = 088, Level = 23, Gauge = 03000, Moves = new[] {188,270,325,107}, Location = 059, }, // Grimer: Cipher Peon Faltly @ Phenac Stadium + new EncounterStaticShadow(Grimer) { Fateful = true, Species = 088, Level = 23, Gauge = 03000, Moves = new[] {188,270,325,107}, Location = 107, }, // Grimer: Cipher Peon Faltly @ Phenac Stadium + + new EncounterStaticShadow(Seel) { Fateful = true, Species = 086, Level = 23, Gauge = 03500, Moves = new[] {057,270,219,058}, Location = 107, }, // Seel: Cipher Peon Egrog @ Phenac Stadium + new EncounterStaticShadow(Lunatone) { Fateful = true, Species = 337, Level = 25, Gauge = 05000, Moves = new[] {094,226,240,317}, Location = 107, }, // Lunatone: Cipher Admin Snattle @ Phenac Stadium + + new EncounterStaticShadow(Nosepass) { Fateful = true, Species = 299, Level = 26, Gauge = 04000, Moves = new[] {085,270,086,157}, Location = 090, }, // Nosepass: Wanderer Miror B. @ Pyrite Colosseum/Realgam Colosseum/Poké Spots + new EncounterStaticShadow(Nosepass) { Fateful = true, Species = 299, Level = 26, Gauge = 04000, Moves = new[] {085,270,086,157}, Location = 113, }, // Nosepass: Wanderer Miror B. @ Pyrite Colosseum/Realgam Colosseum/Poké Spots + + new EncounterStaticShadow(Paras) { Fateful = true, Species = 046, Level = 28, Gauge = 04000, Moves = new[] {147,287,163,206}, Location = 064, }, // Paras: Cipher Peon Humah @ Cipher Key Lair + + new EncounterStaticShadow(Growlithe) { Fateful = true, Species = 058, Level = 28, Gauge = 04000, Moves = new[] {053,204,044,036}, Location = 064 }, // Growlithe: Cipher Peon Humah @ Cipher Key Lair + new EncounterStaticShadow(Growlithe) { Fateful = true, Species = 058, Level = 28, Gauge = 04000, Moves = new[] {053,204,044,036}, Location = 113 }, // Growlithe: Cipher Peon Humah @ Cipher Key Lair + new EncounterStaticShadow(Butterfree){ Fateful = true, Species = 012, Level = 30, Gauge = 04000, Moves = new[] {094,234,079,332}, Location = 059, }, // Butterfree: Cipher Peon Targ @ Cipher Key Lair + new EncounterStaticShadow(Venomoth) { Fateful = true, Species = 049, Level = 32, Gauge = 04000, Moves = new[] {318,287,164,094}, Location = 059, }, // Venomoth: Cipher Peon Angic @ Cipher Key Lair + new EncounterStaticShadow(Hypno) { Fateful = true, Species = 097, Level = 34, Gauge = 05500, Moves = new[] {094,226,096,247}, Location = 059, }, // Hypno: Cipher Admin Gorigan @ Cipher Key Lair + new EncounterStaticShadow(Banette) { Fateful = true, Species = 354, Level = 37, Gauge = 07000, Moves = new[] {185,270,247,174}, Location = 059, }, // Banette: Cipher Peon Litnar @ Citadark Isle + + new EncounterStaticShadow(Pidgeotto) { Fateful = true, Species = 017, Level = 30, Gauge = 04000, Moves = new[] {017,287,211,297}, Location = 066, }, // Pidgeotto: Cipher Peon Lok @ Cipher Key Lair + new EncounterStaticShadow(Tangela) { Fateful = true, Species = 114, Level = 30, Gauge = 04000, Moves = new[] {076,234,241,275}, Location = 067, }, // Tangela: Cipher Peon Targ @ Cipher Key Lair + new EncounterStaticShadow(Butterfree){ Fateful = true, Species = 012, Level = 30, Gauge = 04000, Moves = new[] {094,234,079,332}, Location = 067, }, // Butterfree: Cipher Peon Targ @ Cipher Key Lair + new EncounterStaticShadow(Magneton) { Fateful = true, Species = 082, Level = 30, Gauge = 04500, Moves = new[] {038,287,240,087}, Location = 067, }, // Magneton: Cipher Peon Snidle @ Cipher Key Lair + new EncounterStaticShadow(Venomoth) { Fateful = true, Species = 049, Level = 32, Gauge = 04000, Moves = new[] {318,287,164,094}, Location = 070, }, // Venomoth: Cipher Peon Angic @ Cipher Key Lair + new EncounterStaticShadow(Weepinbell){ Fateful = true, Species = 070, Level = 32, Gauge = 04000, Moves = new[] {345,234,188,230}, Location = 070, }, // Weepinbell: Cipher Peon Angic @ Cipher Key Lair + new EncounterStaticShadow(Arbok) { Fateful = true, Species = 024, Level = 33, Gauge = 05000, Moves = new[] {188,287,137,044}, Location = 070, }, // Arbok: Cipher Peon Smarton @ Cipher Key Lair + new EncounterStaticShadow(Primeape) { Fateful = true, Species = 057, Level = 34, Gauge = 06000, Moves = new[] {238,270,116,179}, Location = 069, }, // Primeape: Cipher Admin Gorigan @ Cipher Key Lair + new EncounterStaticShadow(Hypno) { Fateful = true, Species = 097, Level = 34, Gauge = 05500, Moves = new[] {094,226,096,247}, Location = 069, }, // Hypno: Cipher Admin Gorigan @ Cipher Key Lair + new EncounterStaticShadow(Golduck) { Fateful = true, Species = 055, Level = 33, Gauge = 06500, Moves = new[] {127,204,244,280}, Location = 088, }, // Golduck: Navigator Abson @ Citadark Isle + new EncounterStaticShadow(Sableye) { Fateful = true, Species = 302, Level = 33, Gauge = 07000, Moves = new[] {247,270,185,105}, Location = 088, }, // Sableye: Navigator Abson @ Citadark Isle + new EncounterStaticShadow(Dodrio) { Fateful = true, Species = 085, Level = 34, Gauge = 08000, Moves = new[] {065,226,097,161}, Location = 076, }, // Dodrio: Chaser Furgy @ Citadark Isle + new EncounterStaticShadow(Raticate) { Fateful = true, Species = 020, Level = 34, Gauge = 06000, Moves = new[] {162,287,184,158}, Location = 076, }, // Raticate: Chaser Furgy @ Citadark Isle + new EncounterStaticShadow(Farfetchd) { Fateful = true, Species = 083, Level = 36, Gauge = 05500, Moves = new[] {163,226,014,332}, Location = 076, }, // Farfetch'd: Cipher Admin Lovrina @ Citadark Isle + new EncounterStaticShadow(Altaria) { Fateful = true, Species = 334, Level = 36, Gauge = 06500, Moves = new[] {225,215,076,332}, Location = 076, }, // Altaria: Cipher Admin Lovrina @ Citadark Isle + new EncounterStaticShadow(Kangaskhan){ Fateful = true, Species = 115, Level = 35, Gauge = 06000, Moves = new[] {089,047,039,146}, Location = 085, }, // Kangaskhan: Cipher Peon Litnar @ Citadark Isle + new EncounterStaticShadow(Banette) { Fateful = true, Species = 354, Level = 37, Gauge = 07000, Moves = new[] {185,270,247,174}, Location = 085, }, // Banette: Cipher Peon Litnar @ Citadark Isle + new EncounterStaticShadow(Magmar) { Fateful = true, Species = 126, Level = 36, Gauge = 07000, Moves = new[] {126,266,238,009}, Location = 077, }, // Magmar: Cipher Peon Grupel @ Citadark Isle + new EncounterStaticShadow(Pinsir) { Fateful = true, Species = 127, Level = 35, Gauge = 07000, Moves = new[] {012,270,206,066}, Location = 077, }, // Pinsir: Cipher Peon Grupel @ Citadark Isle + new EncounterStaticShadow(Rapidash) { Fateful = true, Species = 078, Level = 40, Gauge = 06000, Moves = new[] {076,226,241,053}, Location = 080, }, // Rapidash: Cipher Peon Kolest @ Citadark Isle + new EncounterStaticShadow(Magcargo) { Fateful = true, Species = 219, Level = 38, Gauge = 05500, Moves = new[] {257,287,089,053}, Location = 080, }, // Magcargo: Cipher Peon Kolest @ Citadark Isle + new EncounterStaticShadow(Hitmonchan){ Fateful = true, Species = 107, Level = 38, Gauge = 06000, Moves = new[] {005,270,170,327}, Location = 081, }, // Hitmonchan: Cipher Peon Karbon @ Citadark Isle + new EncounterStaticShadow(Hitmonlee) { Fateful = true, Species = 106, Level = 38, Gauge = 07000, Moves = new[] {136,287,170,025}, Location = 081, }, // Hitmonlee: Cipher Peon Petro @ Citadark Isle + new EncounterStaticShadow(Lickitung) { Fateful = true, Species = 108, Level = 38, Gauge = 05000, Moves = new[] {038,270,111,205}, Location = 084, }, // Lickitung: Cipher Peon Geftal @ Citadark Isle + new EncounterStaticShadow(Scyther) { Fateful = true, Species = 123, Level = 40, Gauge = 08000, Moves = new[] {013,234,318,163}, Location = 084, }, // Scyther: Cipher Peon Leden @ Citadark Isle + + new EncounterStaticShadow(Chansey) { Fateful = true, Species = 113, Level = 39, Gauge = 04000, Moves = new[] {085,186,135,285}, Location = 084, }, // Chansey: Cipher Peon Leden @ Citadark Isle + new EncounterStaticShadow(Chansey) { Fateful = true, Species = 113, Level = 39, Gauge = 04000, Moves = new[] {085,186,135,285}, Location = 087, }, // Chansey: Cipher Peon Leden @ Citadark Isle + + new EncounterStaticShadow(Solrock) { Fateful = true, Species = 338, Level = 41, Gauge = 07500, Moves = new[] {094,226,241,322}, Location = 087, }, // Solrock: Cipher Admin Snattle @ Citadark Isle + new EncounterStaticShadow(Starmie) { Fateful = true, Species = 121, Level = 41, Gauge = 07500, Moves = new[] {127,287,058,105}, Location = 087, }, // Starmie: Cipher Admin Snattle @ Citadark Isle + new EncounterStaticShadow(Electabuzz){ Fateful = true, Species = 125, Level = 43, Gauge = 07000, Moves = new[] {238,266,086,085}, Location = 087, }, // Electabuzz: Cipher Admin Ardos @ Citadark Isle + new EncounterStaticShadow(Snorlax) { Fateful = true, Species = 143, Level = 43, Gauge = 09000, Moves = new[] {090,287,174,034}, Location = 087, }, // Snorlax: Cipher Admin Ardos @ Citadark Isle + new EncounterStaticShadow(Poliwrath) { Fateful = true, Species = 062, Level = 42, Gauge = 07500, Moves = new[] {056,270,240,280}, Location = 087, }, // Poliwrath: Cipher Admin Gorigan @ Citadark Isle + new EncounterStaticShadow(MrMime) { Fateful = true, Species = 122, Level = 42, Gauge = 06500, Moves = new[] {094,266,227,009}, Location = 087, }, // Mr. Mime: Cipher Admin Gorigan @ Citadark Isle + new EncounterStaticShadow(Dugtrio) { Fateful = true, Species = 051, Level = 40, Gauge = 05000, Moves = new[] {089,204,201,161}, Location = 075, }, // Dugtrio: Cipher Peon Kolax @ Citadark Isle + new EncounterStaticShadow(Manectric) { Fateful = true, Species = 310, Level = 44, Gauge = 07000, Moves = new[] {087,287,240,044}, Location = 073, }, // Manectric: Cipher Admin Eldes @ Citadark Isle + new EncounterStaticShadow(Salamence) { Fateful = true, Species = 373, Level = 50, Gauge = 09000, Moves = new[] {337,287,349,332}, Location = 073, }, // Salamence: Cipher Admin Eldes @ Citadark Isle + new EncounterStaticShadow(Marowak) { Fateful = true, Species = 105, Level = 44, Gauge = 06500, Moves = new[] {089,047,014,157}, Location = 073, }, // Marowak: Cipher Admin Eldes @ Citadark Isle + new EncounterStaticShadow(Lapras) { Fateful = true, Species = 131, Level = 44, Gauge = 06000, Moves = new[] {056,215,240,059}, Location = 073, }, // Lapras: Cipher Admin Eldes @ Citadark Isle + new EncounterStaticShadow(Moltres) { Fateful = true, Species = 146, Level = 50, Gauge = 10000, Moves = new[] {326,234,261,053}, Location = 074, }, // Moltres: Grand Master Greevil @ Citadark Isle + new EncounterStaticShadow(Exeggutor) { Fateful = true, Species = 103, Level = 46, Gauge = 09000, Moves = new[] {094,287,095,246}, Location = 074, }, // Exeggutor: Grand Master Greevil @ Citadark Isle + new EncounterStaticShadow(Tauros) { Fateful = true, Species = 128, Level = 46, Gauge = 09000, Moves = new[] {089,287,039,034}, Location = 074, }, // Tauros: Grand Master Greevil @ Citadark Isle + new EncounterStaticShadow(Articuno) { Fateful = true, Species = 144, Level = 50, Gauge = 10000, Moves = new[] {326,215,114,058}, Location = 074, }, // Articuno: Grand Master Greevil @ Citadark Isle + new EncounterStaticShadow(Zapdos) { Fateful = true, Species = 145, Level = 50, Gauge = 10000, Moves = new[] {326,226,319,085}, Location = 074, }, // Zapdos: Grand Master Greevil @ Citadark Isle + new EncounterStaticShadow(Dragonite) { Fateful = true, Species = 149, Level = 55, Gauge = 09000, Moves = new[] {063,215,349,089}, Location = 162, }, // Dragonite: Wanderer Miror B. @ Gateon Port }.SelectMany(CloneMirorB).ToArray(); internal static readonly EncounterArea3[] SlotsXD = diff --git a/PKHeX.Core/Legality/Encounters/Data/Encounters3Shadow.cs b/PKHeX.Core/Legality/Encounters/Data/Encounters3Shadow.cs index 73f591267..0a80901f7 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Encounters3Shadow.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Encounters3Shadow.cs @@ -1,1080 +1,1081 @@ -namespace PKHeX.Core +// ReSharper disable StringLiteralTypo +namespace PKHeX.Core { public static class Encounters3Shadow { #region Colosseum - public static readonly TeamLock CMakuhita = new TeamLock { - Species = 296, // Makuhita - Locks = new[] { + public static readonly TeamLock CMakuhita = new TeamLock( + 296, // Makuhita + new[] { new NPCLock(355, 24, 0, 127), // Duskull (M) (Quirky) new NPCLock(167, 00, 1, 127), // Spinarak (F) (Hardy) - }}; + }); - public static readonly TeamLock CGligar = new TeamLock { - Species = 207, // Gligar - Locks = new[] { + public static readonly TeamLock CGligar = new TeamLock( + 207, // Gligar + new[] { new NPCLock(216, 12, 0, 127), // Teddiursa (M) (Serious) new NPCLock(039, 06, 1, 191), // Jigglypuff (F) (Docile) new NPCLock(285, 18, 0, 127), // Shroomish (M) (Bashful) - }}; + }); - public static readonly TeamLock CMurkrow = new TeamLock { - Species = 198, // Murkrow - Locks = new[] { + public static readonly TeamLock CMurkrow = new TeamLock( + 198, // Murkrow + new[] { new NPCLock(318, 06, 0, 127), // Carvanha (M) (Docile) new NPCLock(274, 12, 1, 127), // Nuzleaf (F) (Serious) new NPCLock(228, 18, 0, 127), // Houndour (M) (Bashful) - }}; + }); - public static readonly TeamLock CHeracross = new TeamLock { - Species = 214, // Heracross - Locks = new[] { + public static readonly TeamLock CHeracross = new TeamLock( + 214, // Heracross + new[] { new NPCLock(284, 00, 0, 127), // Masquerain (M) (Hardy) new NPCLock(168, 00, 1, 127), // Ariados (F) (Hardy) - }}; + }); - public static readonly TeamLock CUrsaring = new TeamLock { - Species = 217, // Ursaring - Locks = new[] { + public static readonly TeamLock CUrsaring = new TeamLock( + 217, // Ursaring + new[] { new NPCLock(067, 20, 1, 063), // Machoke (F) (Calm) new NPCLock(259, 16, 0, 031), // Marshtomp (M) (Mild) new NPCLock(275, 21, 1, 127), // Shiftry (F) (Gentle) - }}; + }); #endregion #region E-Reader - public static readonly TeamLock ETogepi = new TeamLock { - Species = 175, // Togepi - Locks = new[] { + public static readonly TeamLock ETogepi = new TeamLock( + 175, // Togepi + new[] { new NPCLock(302, 23, 0, 127), // Sableye (M) (Careful) new NPCLock(088, 08, 0, 127), // Grimer (M) (Impish) new NPCLock(316, 24, 0, 127), // Gulpin (M) (Quirky) new NPCLock(175, 22, 1, 031), // Togepi (F) (Sassy) -- itself! - }}; + }); - public static readonly TeamLock EMareep = new TeamLock { - Species = 179, // Mareep - Locks = new[] { + public static readonly TeamLock EMareep = new TeamLock( + 179, // Mareep + new[] { new NPCLock(300, 04, 1, 191), // Skitty (F) (Naughty) new NPCLock(211, 10, 1, 127), // Qwilfish (F) (Timid) new NPCLock(355, 12, 1, 127), // Duskull (F) (Serious) new NPCLock(179, 16, 1, 127), // Mareep (F) (Mild) -- itself! - }}; + }); - public static readonly TeamLock EScizor = new TeamLock { - Species = 212, // Scizor - Locks = new[] { + public static readonly TeamLock EScizor = new TeamLock( + 212, // Scizor + new[] { new NPCLock(198, 13, 1, 191), // Murkrow (F) (Jolly) new NPCLock(344, 02, 2, 255), // Claydol (-) (Brave) new NPCLock(208, 03, 0, 127), // Steelix (M) (Adamant) new NPCLock(212, 11, 0, 127), // Scizor (M) (Hasty) -- itself! - }}; + }); #endregion #region XD - public static readonly TeamLock XRalts = new TeamLock { - Species = 280, // Ralts - Locks = new[] { + public static readonly TeamLock XRalts = new TeamLock( + 280, // Ralts + new[] { new NPCLock(064, 00, 0, 063), // Kadabra (M) (Hardy) new NPCLock(180, 06, 1, 127), // Flaaffy (F) (Docile) new NPCLock(288, 18, 0, 127), // Vigoroth (M) (Bashful) - }}; + }); - public static readonly TeamLock XPoochyena = new TeamLock { - Species = 261, // Poochyena - Locks = new[] { + public static readonly TeamLock XPoochyena = new TeamLock( + 261, // Poochyena + new[] { new NPCLock(041, 12, 1, 127), // Zubat (F) (Serious) - }}; + }); - public static readonly TeamLock XLedyba = new TeamLock { - Species = 165, // Ledyba - Locks = new[] { + public static readonly TeamLock XLedyba = new TeamLock( + 165, // Ledyba + new[] { new NPCLock(276, 00, 1, 127), // Taillow (F) (Hardy) - }}; + }); - public static readonly TeamLock XSphealCipherLab = new TeamLock { - Species = 363, // Spheal - Comment = "Cipher Lab", - Locks = new[] { + public static readonly TeamLock XSphealCipherLab = new TeamLock( + 363, // Spheal + "Cipher Lab", + new[] { new NPCLock(116, 24, 0, 063), // Horsea (M) (Quirky) new NPCLock(118, 12, 1, 127), // Goldeen (F) (Serious) - }}; + }); - public static readonly TeamLock XSphealPhenacCityandPost = new TeamLock { - Species = 363, // Spheal - Comment = "Phenac City and Post", - Locks = new[] { + public static readonly TeamLock XSphealPhenacCityandPost = new TeamLock( + 363, // Spheal + "Phenac City and Post", + new[] { new NPCLock(116, 24, 0, 063), // Horsea (M) (Quirky) new NPCLock(118, 12, 1, 127), // Goldeen (F) (Serious) new NPCLock(374, 00, 2, 255), // Beldum (-) (Hardy) - }}; + }); - public static readonly TeamLock XGulpin = new TeamLock { - Species = 316, // Gulpin - Locks = new[] { + public static readonly TeamLock XGulpin = new TeamLock( + 316, // Gulpin + new[] { new NPCLock(109, 12, 1, 127), // Koffing (F) (Serious) new NPCLock(088, 06, 0, 127), // Grimer (M) (Docile) - }}; + }); - public static readonly TeamLock XSeedotCipherLab = new TeamLock { - Species = 273, // Seedot - Comment = "Cipher Lab", - Locks = new[] { + public static readonly TeamLock XSeedotCipherLab = new TeamLock( + 273, // Seedot + "Cipher Lab", + new[] { new NPCLock(043, 06, 0, 127), // Oddish (M) (Docile) new NPCLock(331, 24, 1, 127), // Cacnea (F) (Quirky) new NPCLock(285, 18, 1, 127), // Shroomish (F) (Bashful) new NPCLock(270, 00, 0, 127), // Lotad (M) (Hardy) new NPCLock(204, 12, 0, 127), // Pineco (M) (Serious) - }}; + }); - public static readonly TeamLock XSeedotPhenacCity = new TeamLock { - Species = 273, // Seedot - Comment = "Phenac City", - Locks = new[] { + public static readonly TeamLock XSeedotPhenacCity = new TeamLock( + 273, // Seedot + "Phenac City", + new[] { new NPCLock(043, 06, 0, 127), // Oddish (M) (Docile) new NPCLock(331, 24, 1, 127), // Cacnea (F) (Quirky) new NPCLock(285, 00, 1, 127), // Shroomish (F) (Hardy) new NPCLock(270, 00, 1, 127), // Lotad (F) (Hardy) new NPCLock(204, 06, 0, 127), // Pineco (M) (Docile) - }}; + }); - public static readonly TeamLock XSeedotPost = new TeamLock { - Species = 273, // Seedot - Comment = "Post", - Locks = new[] { + public static readonly TeamLock XSeedotPost = new TeamLock( + 273, // Seedot + "Post", + new[] { new NPCLock(045, 06, 0, 127), // Vileplume (M) (Docile) new NPCLock(332, 24, 1, 127), // Cacturne (F) (Quirky) new NPCLock(286, 00, 1, 127), // Breloom (F) (Hardy) new NPCLock(271, 00, 0, 127), // Lombre (M) (Hardy) new NPCLock(205, 12, 0, 127), // Forretress (M) (Serious) - }}; + }); - public static readonly TeamLock XSpinarak = new TeamLock { - Species = 167, // Spinarak - Locks = new[] { + public static readonly TeamLock XSpinarak = new TeamLock( + 167, // Spinarak + new[] { new NPCLock(220, 12, 1, 127), // Swinub (F) (Serious) new NPCLock(353, 06, 0, 127), // Shuppet (M) (Docile) - }}; + }); - public static readonly TeamLock XNumel = new TeamLock { - Species = 322, // Numel - Locks = new[] { + public static readonly TeamLock XNumel = new TeamLock( + 322, // Numel + new[] { new NPCLock(280, 06, 0, 127), // Ralts (M) (Docile) new NPCLock(100, 00, 2, 255), // Voltorb (-) (Hardy) new NPCLock(371, 24, 1, 127), // Bagon (F) (Quirky) - }}; + }); - public static readonly TeamLock XShroomish = new TeamLock { - Species = 285, // Shroomish - Locks = new[] { + public static readonly TeamLock XShroomish = new TeamLock( + 285, // Shroomish + new[] { new NPCLock(209, 24, 1, 191), // Snubbull (F) (Quirky) new NPCLock(352, 00, 1, 127), // Kecleon (F) (Hardy) - }}; + }); - public static readonly TeamLock XDelcatty = new TeamLock { - Species = 301, // Delcatty - Locks = new[] { + public static readonly TeamLock XDelcatty = new TeamLock( + 301, // Delcatty + new[] { new NPCLock(370, 06, 1, 191), // Luvdisc (F) (Docile) new NPCLock(267, 00, 0, 127), // Beautifly (M) (Hardy) new NPCLock(315, 24, 0, 127), // Roselia (M) (Quirky) - }}; + }); - public static readonly TeamLock XVoltorb = new TeamLock { - Species = 100, // Voltorb - Locks = new[] { + public static readonly TeamLock XVoltorb = new TeamLock( + 100, // Voltorb + new[] { new NPCLock(271, 00, 0, 127), // Lombre (M) (Hardy) new NPCLock(271, 18, 0, 127), // Lombre (M) (Bashful) new NPCLock(271, 12, 1, 127), // Lombre (F) (Serious) - }}; + }); - public static readonly TeamLock XMakuhita = new TeamLock { - Species = 296, // Makuhita - Locks = new[] { + public static readonly TeamLock XMakuhita = new TeamLock( + 296, // Makuhita + new[] { new NPCLock(352, 06, 0, 127), // Kecleon (M) (Docile) new NPCLock(283, 18, 1, 127), // Surskit (F) (Bashful) - }}; + }); - public static readonly TeamLock XVulpix = new TeamLock { - Species = 037, // Vulpix - Locks = new[] { + public static readonly TeamLock XVulpix = new TeamLock( + 037, // Vulpix + new[] { new NPCLock(167, 00, 0, 127), // Spinarak (M) (Hardy) new NPCLock(267, 06, 1, 127), // Beautifly (F) (Docile) new NPCLock(269, 18, 0, 127), // Dustox (M) (Bashful) - }}; + }); - public static readonly TeamLock XDuskull = new TeamLock { - Species = 355, // Duskull - Locks = new[] { + public static readonly TeamLock XDuskull = new TeamLock( + 355, // Duskull + new[] { new NPCLock(215, 12, 0, 127), // Sneasel (M) (Serious) new NPCLock(193, 18, 1, 127), // Yanma (F) (Bashful) new NPCLock(200, 24, 0, 127), // Misdreavus (M) (Quirky) - }}; + }); - public static readonly TeamLock XMawile = new TeamLock { - Species = 303, // Mawile - Locks = new[] { + public static readonly TeamLock XMawile = new TeamLock( + 303, // Mawile + new[] { new NPCLock(294, 06, 0, 127), // Loudred (M) (Docile) new NPCLock(203, 18, 1, 127), // Girafarig (F) (Bashful) - }}; + }); - public static readonly TeamLock XSnorunt = new TeamLock { - Species = 361, // Snorunt - Locks = new[] { + public static readonly TeamLock XSnorunt = new TeamLock( + 361, // Snorunt + new[] { new NPCLock(336, 06, 1, 127), // Seviper (F) (Docile) - }}; + }); - public static readonly TeamLock XPineco = new TeamLock { - Species = 204, // Pineco - Locks = new[] { + public static readonly TeamLock XPineco = new TeamLock( + 204, // Pineco + new[] { new NPCLock(198, 06, 0, 127), // Murkrow (M) (Docile) - }}; + }); - public static readonly TeamLock XNatu = new TeamLock { - Species = 177, // Natu - Locks = new[] { + public static readonly TeamLock XNatu = new TeamLock( + 177, // Natu + new[] { new NPCLock(281, 00, 0, 127), // Kirlia (M) (Hardy) new NPCLock(264, 00, 1, 127), // Linoone (F) (Hardy) - }}; + }); - public static readonly TeamLock XRoselia = new TeamLock { - Species = 315, // Roselia - Locks = new[] { + public static readonly TeamLock XRoselia = new TeamLock( + 315, // Roselia + new[] { new NPCLock(223, 06, 0, 127), // Remoraid (M) (Docile) new NPCLock(042, 18, 0, 127), // Golbat (M) (Bashful) - }}; + }); - public static readonly TeamLock XMeowth = new TeamLock { - Species = 052, // Meowth - Locks = new[] { + public static readonly TeamLock XMeowth = new TeamLock( + 052, // Meowth + new[] { new NPCLock(064, 06, 0, 063), // Kadabra (M) (Docile) new NPCLock(215, 00, 1, 127), // Sneasel (F) (Hardy) new NPCLock(200, 18, 1, 127), // Misdreavus (F) (Bashful) - }}; + }); - public static readonly TeamLock XSwinub = new TeamLock { - Species = 220, // Swinub - Locks = new[] { + public static readonly TeamLock XSwinub = new TeamLock( + 220, // Swinub + new[] { new NPCLock(324, 18, 1, 127), // Torkoal (F) (Bashful) new NPCLock(274, 00, 0, 127), // Nuzleaf (M) (Hardy) - }}; + }); - public static readonly TeamLock XSpearow = new TeamLock { - Species = 021, // Spearow - Locks = new[] { + public static readonly TeamLock XSpearow = new TeamLock( + 021, // Spearow + new[] { new NPCLock(279, 18, 0, 127), // Pelipper (M) (Bashful) new NPCLock(309, 06, 1, 127), // Electrike (F) (Docile) - }}; + }); - public static readonly TeamLock XGrimer = new TeamLock { - Species = 088, // Grimer - Locks = new[] { + public static readonly TeamLock XGrimer = new TeamLock( + 088, // Grimer + new[] { new NPCLock(358, 12, 0, 127), // Chimecho (M) (Serious) new NPCLock(234, 18, 0, 127), // Stantler (M) (Bashful) - }}; + }); - public static readonly TeamLock XSeel = new TeamLock { - Species = 086, // Seel - Locks = new[] { + public static readonly TeamLock XSeel = new TeamLock( + 086, // Seel + new[] { new NPCLock(163, 06, 0, 127), // Hoothoot (M) (Docile) new NPCLock(075, 18, 0, 127), // Graveler (M) (Bashful) new NPCLock(316, 18, 1, 127), // Gulpin (F) (Bashful) - }}; + }); - public static readonly TeamLock XLunatone = new TeamLock { - Species = 337, // Lunatone - Locks = new[] { + public static readonly TeamLock XLunatone = new TeamLock( + 337, // Lunatone + new[] { new NPCLock(171, 00, 1, 127), // Lanturn (F) (Hardy) new NPCLock(195, 18, 0, 127), // Quagsire (M) (Bashful) - }}; + }); - public static readonly TeamLock XNosepass = new TeamLock { - Species = 299, // Nosepass - Locks = new[] { + public static readonly TeamLock XNosepass = new TeamLock( + 299, // Nosepass + new[] { new NPCLock(271, 00, 0, 127), // Lombre (M) (Hardy) new NPCLock(271, 18, 0, 127), // Lombre (M) (Bashful) new NPCLock(271, 12, 1, 127), // Lombre (F) (Serious) - }}; + }); - public static readonly TeamLock XParas = new TeamLock { - Species = 046, // Paras - Locks = new[] { + public static readonly TeamLock XParas = new TeamLock( + 046, // Paras + new[] { new NPCLock(336, 24, 0, 127), // Seviper (M) (Quirky) new NPCLock(198, 06, 1, 127), // Murkrow (F) (Docile) - }}; + }); - public static readonly TeamLock XGrowlithe = new TeamLock { - Species = 058, // Growlithe - Locks = new[] { + public static readonly TeamLock XGrowlithe = new TeamLock( + 058, // Growlithe + new[] { new NPCLock(336, 24, 0, 127), // Seviper (M) (Quirky) new NPCLock(198, 06, 1, 127), // Murkrow (F) (Docile) new NPCLock(046), // Shadow Paras - }}; + }); - public static readonly TeamLock XGrowlitheParasSeen = new TeamLock { - Species = 058, // Growlithe - Comment = "Paras Seen", - Locks = new[] { + public static readonly TeamLock XGrowlitheParasSeen = new TeamLock( + 058, // Growlithe + "Paras Seen", + new[] { new NPCLock(336, 24, 0, 127), // Seviper (M) (Quirky) new NPCLock(198, 06, 1, 127), // Murkrow (F) (Docile) new NPCLock(046, true), // Shadow Paras (Seen) - }}; + }); - public static readonly TeamLock XPidgeotto = new TeamLock { - Species = 017, // Pidgeotto - Locks = new[] { + public static readonly TeamLock XPidgeotto = new TeamLock( + 017, // Pidgeotto + new[] { new NPCLock(015), // Shadow Beedrill new NPCLock(162, 12, 0, 127), // Furret (M) (Serious) new NPCLock(176, 18, 0, 031), // Togetic (M) (Bashful) - }}; + }); - public static readonly TeamLock XPidgeottoBeedrillSeen = new TeamLock { - Species = 017, // Pidgeotto - Comment = "Beedrill Seen", - Locks = new[] { + public static readonly TeamLock XPidgeottoBeedrillSeen = new TeamLock( + 017, // Pidgeotto + "Beedrill Seen", + new[] { new NPCLock(015, true), // Shadow Beedrill (Seen) new NPCLock(162, 12, 0, 127), // Furret (M) (Serious) new NPCLock(176, 18, 0, 031), // Togetic (M) (Bashful) - }}; + }); - public static readonly TeamLock XTangela = new TeamLock { - Species = 114, // Tangela - Locks = new[] { + public static readonly TeamLock XTangela = new TeamLock( + 114, // Tangela + new[] { new NPCLock(038, 12, 1, 191), // Ninetales (F) (Serious) new NPCLock(189, 06, 0, 127), // Jumpluff (M) (Docile) new NPCLock(184, 00, 1, 127), // Azumarill (F) (Hardy) - }}; + }); - public static readonly TeamLock XButterfree = new TeamLock { - Species = 012, // Butterfree - Locks = new[] { + public static readonly TeamLock XButterfree = new TeamLock( + 012, // Butterfree + new[] { new NPCLock(038, 12, 1, 191), // Ninetales (F) (Serious) new NPCLock(189, 06, 0, 127), // Jumpluff (M) (Docile) new NPCLock(184, 00, 1, 127), // Azumarill (F) (Hardy) new NPCLock(114), // Shadow Tangela - }}; + }); - public static readonly TeamLock XButterfreeTangelaSeen = new TeamLock { - Species = 012, // Butterfree - Comment = "Tangela Seen", - Locks = new[] { + public static readonly TeamLock XButterfreeTangelaSeen = new TeamLock( + 012, // Butterfree + "Tangela Seen", + new[] { new NPCLock(038, 12, 1, 191), // Ninetales (F) (Serious) new NPCLock(189, 06, 0, 127), // Jumpluff (M) (Docile) new NPCLock(184, 00, 1, 127), // Azumarill (F) (Hardy) new NPCLock(114, true), // Shadow Tangela (Seen) - }}; + }); - public static readonly TeamLock XMagneton = new TeamLock { - Species = 082, // Magneton - Locks = new[] { + public static readonly TeamLock XMagneton = new TeamLock( + 082, // Magneton + new[] { new NPCLock(292, 18, 2, 255), // Shedinja (-) (Bashful) new NPCLock(202, 00, 0, 127), // Wobbuffet (M) (Hardy) new NPCLock(329, 12, 1, 127), // Vibrava (F) (Serious) - }}; + }); - public static readonly TeamLock XVenomoth = new TeamLock { - Species = 049, // Venomoth - Locks = new[] { + public static readonly TeamLock XVenomoth = new TeamLock( + 049, // Venomoth + new[] { new NPCLock(055, 18, 1, 127), // Golduck (F) (Bashful) new NPCLock(237, 24, 0, 000), // Hitmontop (M) (Quirky) new NPCLock(297, 12, 0, 063), // Hariyama (M) (Serious) - }}; + }); - public static readonly TeamLock XWeepinbell = new TeamLock { - Species = 070, // Weepinbell - Locks = new[] { + public static readonly TeamLock XWeepinbell = new TeamLock( + 070, // Weepinbell + new[] { new NPCLock(055, 18, 1, 127), // Golduck (F) (Bashful) new NPCLock(237, 24, 0, 000), // Hitmontop (M) (Quirky) new NPCLock(297, 12, 0, 063), // Hariyama (M) (Serious) new NPCLock(049), // Shadow Venomoth - }}; + }); - public static readonly TeamLock XWeepinbellVenomothSeen = new TeamLock { - Species = 070, // Weepinbell - Comment = "Venomoth Seen", - Locks = new[] { + public static readonly TeamLock XWeepinbellVenomothSeen = new TeamLock( + 070, // Weepinbell + "Venomoth Seen", + new[] { new NPCLock(055, 18, 1, 127), // Golduck (F) (Bashful) new NPCLock(237, 24, 0, 000), // Hitmontop (M) (Quirky) new NPCLock(297, 12, 0, 063), // Hariyama (M) (Serious) new NPCLock(049, true), // Shadow Venomoth (Seen) - }}; + }); - public static readonly TeamLock XArbok = new TeamLock { - Species = 024, // Arbok - Locks = new[] { + public static readonly TeamLock XArbok = new TeamLock( + 024, // Arbok + new[] { new NPCLock(367, 06, 0, 127), // Huntail (M) (Docile) new NPCLock(332, 00, 1, 127), // Cacturne (F) (Hardy) new NPCLock(110, 12, 1, 127), // Weezing (F) (Serious) new NPCLock(217, 18, 1, 127), // Ursaring (F) (Bashful) - }}; + }); - public static readonly TeamLock XPrimeape = new TeamLock { - Species = 057, // Primeape - Locks = new[] { + public static readonly TeamLock XPrimeape = new TeamLock( + 057, // Primeape + new[] { new NPCLock(305, 18, 1, 127), // Lairon (F) (Bashful) new NPCLock(364, 12, 1, 127), // Sealeo (F) (Serious) new NPCLock(199, 06, 1, 127), // Slowking (F) (Docile) new NPCLock(217, 24, 0, 127), // Ursaring (M) (Quirky) - }}; + }); - public static readonly TeamLock XHypno = new TeamLock { - Species = 097, // Hypno - Locks = new[] { + public static readonly TeamLock XHypno = new TeamLock( + 097, // Hypno + new[] { new NPCLock(305, 18, 1, 127), // Lairon (F) (Bashful) new NPCLock(364, 12, 1, 127), // Sealeo (F) (Serious) new NPCLock(199, 06, 1, 127), // Slowking (F) (Docile) new NPCLock(217, 24, 0, 127), // Ursaring (M) (Quirky) new NPCLock(057), // Shadow Primeape - }}; + }); - public static readonly TeamLock XHypnoPrimeapeSeen = new TeamLock { - Species = 097, // Hypno - Comment = "Primeape Seen", - Locks = new[] { + public static readonly TeamLock XHypnoPrimeapeSeen = new TeamLock( + 097, // Hypno + "Primeape Seen", + new[] { new NPCLock(305, 18, 1, 127), // Lairon (F) (Bashful) new NPCLock(364, 12, 1, 127), // Sealeo (F) (Serious) new NPCLock(199, 06, 1, 127), // Slowking (F) (Docile) new NPCLock(217, 24, 0, 127), // Ursaring (M) (Quirky) new NPCLock(057, true), // Shadow Primeape (Seen) - }}; + }); - public static readonly TeamLock XGolduck = new TeamLock { - Species = 055, // Golduck - Locks = new[] { + public static readonly TeamLock XGolduck = new TeamLock( + 055, // Golduck + new[] { new NPCLock(342, 24, 0, 127), // Crawdaunt (M) (Quirky) new NPCLock(279, 06, 1, 127), // Pelipper (F) (Docile) new NPCLock(226, 18, 1, 127), // Mantine (F) (Bashful) - }}; + }); - public static readonly TeamLock XSableye = new TeamLock { - Species = 302, // Sableye - Locks = new[] { + public static readonly TeamLock XSableye = new TeamLock( + 302, // Sableye + new[] { new NPCLock(342, 24, 0, 127), // Crawdaunt (M) (Quirky) new NPCLock(279, 06, 1, 127), // Pelipper (F) (Docile) new NPCLock(226, 18, 1, 127), // Mantine (F) (Bashful) new NPCLock(055), // Shadow Golduck - }}; + }); - public static readonly TeamLock XSableyeGolduckSeen = new TeamLock { - Species = 302, // Sableye - Comment = "Golduck Seen", - Locks = new[] { + public static readonly TeamLock XSableyeGolduckSeen = new TeamLock( + 302, // Sableye + "Golduck Seen", + new[] { new NPCLock(342, 24, 0, 127), // Crawdaunt (M) (Quirky) new NPCLock(279, 06, 1, 127), // Pelipper (F) (Docile) new NPCLock(226, 18, 1, 127), // Mantine (F) (Bashful) new NPCLock(055, true), // Shadow Golduck (Seen) - }}; + }); - public static readonly TeamLock XDodrio = new TeamLock { - Species = 085, // Dodrio - Locks = new[] { + public static readonly TeamLock XDodrio = new TeamLock( + 085, // Dodrio + new[] { new NPCLock(178, 18, 1, 127), // Xatu (F) (Bashful) - }}; + }); - public static readonly TeamLock XRaticate = new TeamLock { - Species = 020, // Raticate - Locks = new[] { + public static readonly TeamLock XRaticate = new TeamLock( + 020, // Raticate + new[] { new NPCLock(178, 18, 1, 127), // Xatu (F) (Bashful) new NPCLock(085), // Shadow Dodrio new NPCLock(340, 18, 0, 127), // Whiscash (M) (Bashful) - }}; + }); - public static readonly TeamLock XRaticateDodrioSeen = new TeamLock { - Species = 020, // Raticate - Comment = "Dodrio Seen", - Locks = new[] { + public static readonly TeamLock XRaticateDodrioSeen = new TeamLock( + 020, // Raticate + "Dodrio Seen", + new[] { new NPCLock(178, 18, 1, 127), // Xatu (F) (Bashful) new NPCLock(085, true), // Shadow Dodrio (Seen) new NPCLock(340, 18, 0, 127), // Whiscash (M) (Bashful) - }}; + }); - public static readonly TeamLock XFarfetchd = new TeamLock { - Species = 083, // Farfetch’d - Locks = new[] { + public static readonly TeamLock XFarfetchd = new TeamLock( + 083, // Farfetch’d + new[] { new NPCLock(282, 12, 0, 127), // Gardevoir (M) (Serious) new NPCLock(368, 00, 1, 127), // Gorebyss (F) (Hardy) new NPCLock(315, 24, 0, 127), // Roselia (M) (Quirky) - }}; + }); - public static readonly TeamLock XAltaria = new TeamLock { - Species = 334, // Altaria - Locks = new[] { + public static readonly TeamLock XAltaria = new TeamLock( + 334, // Altaria + new[] { new NPCLock(282, 12, 0, 127), // Gardevoir (M) (Serious) new NPCLock(368, 00, 1, 127), // Gorebyss (F) (Hardy) new NPCLock(315, 24, 0, 127), // Roselia (M) (Quirky) new NPCLock(083), // Shadow Farfetch’d - }}; + }); - public static readonly TeamLock XAltariaFarfetchdSeen = new TeamLock { - Species = 334, // Altaria - Comment = "Farfetch'd Seen", - Locks = new[] { + public static readonly TeamLock XAltariaFarfetchdSeen = new TeamLock( + 334, // Altaria + "Farfetch'd Seen", + new[] { new NPCLock(282, 12, 0, 127), // Gardevoir (M) (Serious) new NPCLock(368, 00, 1, 127), // Gorebyss (F) (Hardy) new NPCLock(315, 24, 0, 127), // Roselia (M) (Quirky) new NPCLock(083, true), // Shadow Farfetch’d (Seen) - }}; + }); - public static readonly TeamLock XKangaskhan = new TeamLock { - Species = 115, // Kangaskhan - Locks = new[] { + public static readonly TeamLock XKangaskhan = new TeamLock( + 115, // Kangaskhan + new[] { new NPCLock(101, 00, 2, 255), // Electrode (-) (Hardy) new NPCLock(200, 18, 1, 127), // Misdreavus (F) (Bashful) new NPCLock(344, 12, 2, 255), // Claydol (-) (Serious) - }}; + }); - public static readonly TeamLock XBanette = new TeamLock { - Species = 354, // Banette - Locks = new[] { + public static readonly TeamLock XBanette = new TeamLock( + 354, // Banette + new[] { new NPCLock(101, 00, 2, 255), // Electrode (-) (Hardy) new NPCLock(200, 18, 1, 127), // Misdreavus (F) (Bashful) new NPCLock(344, 12, 2, 255), // Claydol (-) (Serious) new NPCLock(115), // Shadow Kangaskhan - }}; + }); - public static readonly TeamLock XBanetteKangaskhanSeen = new TeamLock { - Species = 354, // Banette - Comment = "Kangaskhan Seen", - Locks = new[] { + public static readonly TeamLock XBanetteKangaskhanSeen = new TeamLock( + 354, // Banette + "Kangaskhan Seen", + new[] { new NPCLock(101, 00, 2, 255), // Electrode (-) (Hardy) new NPCLock(200, 18, 1, 127), // Misdreavus (F) (Bashful) new NPCLock(344, 12, 2, 255), // Claydol (-) (Serious) new NPCLock(115, true), // Shadow Kangaskhan (Seen) - }}; + }); - public static readonly TeamLock XMagmar = new TeamLock { - Species = 126, // Magmar - Locks = new[] { + public static readonly TeamLock XMagmar = new TeamLock( + 126, // Magmar + new[] { new NPCLock(229, 18, 0, 127), // Houndoom (M) (Bashful) new NPCLock(038, 18, 0, 191), // Ninetales (M) (Bashful) new NPCLock(045, 00, 1, 127), // Vileplume (F) (Hardy) - }}; + }); - public static readonly TeamLock XPinsir = new TeamLock { - Species = 127, // Pinsir - Locks = new[] { + public static readonly TeamLock XPinsir = new TeamLock( + 127, // Pinsir + new[] { new NPCLock(229, 18, 0, 127), // Houndoom (M) (Bashful) new NPCLock(038, 18, 0, 191), // Ninetales (M) (Bashful) new NPCLock(045, 00, 1, 127), // Vileplume (F) (Hardy) new NPCLock(126), // Shadow Magmar - }}; + }); - public static readonly TeamLock XPinsirMagmarSeen = new TeamLock { - Species = 127, // Pinsir - Comment = "Magmar Seen", - Locks = new[] { + public static readonly TeamLock XPinsirMagmarSeen = new TeamLock( + 127, // Pinsir + "Magmar Seen", + new[] { new NPCLock(229, 18, 0, 127), // Houndoom (M) (Bashful) new NPCLock(038, 18, 0, 191), // Ninetales (M) (Bashful) new NPCLock(045, 00, 1, 127), // Vileplume (F) (Hardy) new NPCLock(126, true), // Shadow Magmar (Seen) - }}; + }); - public static readonly TeamLock XRapidash = new TeamLock { - Species = 078, // Rapidash - Locks = new[] { + public static readonly TeamLock XRapidash = new TeamLock( + 078, // Rapidash + new[] { new NPCLock(323, 24, 0, 127), // Camerupt (M) (Quirky) new NPCLock(110, 06, 0, 127), // Weezing (M) (Docile) new NPCLock(089, 12, 1, 127), // Muk (F) (Serious) - }}; + }); - public static readonly TeamLock XMagcargo = new TeamLock { - Species = 219, // Magcargo - Locks = new[] { + public static readonly TeamLock XMagcargo = new TeamLock( + 219, // Magcargo + new[] { new NPCLock(323, 24, 0, 127), // Camerupt (M) (Quirky) new NPCLock(110, 06, 0, 127), // Weezing (M) (Docile) new NPCLock(089, 12, 1, 127), // Muk (F) (Serious) new NPCLock(078), // Shadow Rapidash - }}; + }); - public static readonly TeamLock XMagcargoRapidashSeen = new TeamLock { - Species = 219, // Magcargo - Comment = "Rapidash Seen", - Locks = new[] { + public static readonly TeamLock XMagcargoRapidashSeen = new TeamLock( + 219, // Magcargo + "Rapidash Seen", + new[] { new NPCLock(323, 24, 0, 127), // Camerupt (M) (Quirky) new NPCLock(110, 06, 0, 127), // Weezing (M) (Docile) new NPCLock(089, 12, 1, 127), // Muk (F) (Serious) new NPCLock(078, true), // Shadow Rapidash (Seen) - }}; + }); - public static readonly TeamLock XHitmonchan = new TeamLock { - Species = 107, // Hitmonchan - Locks = new[] { + public static readonly TeamLock XHitmonchan = new TeamLock( + 107, // Hitmonchan + new[] { new NPCLock(308, 24, 0, 127), // Medicham (M) (Quirky) new NPCLock(076, 06, 1, 127), // Golem (F) (Docile) new NPCLock(178, 18, 1, 127), // Xatu (F) (Bashful) - }}; + }); - public static readonly TeamLock XHitmonlee = new TeamLock { - Species = 106, // Hitmonlee - Locks = new[] { + public static readonly TeamLock XHitmonlee = new TeamLock( + 106, // Hitmonlee + new[] { new NPCLock(326, 18, 0, 127), // Grumpig (M) (Bashful) new NPCLock(227, 12, 1, 127), // Skarmory (F) (Serious) new NPCLock(375, 06, 2, 255), // Metang (-) (Docile) new NPCLock(297, 24, 1, 063), // Hariyama (F) (Quirky) - }}; + }); - public static readonly TeamLock XLickitung = new TeamLock { - Species = 108, // Lickitung - Locks = new[] { + public static readonly TeamLock XLickitung = new TeamLock( + 108, // Lickitung + new[] { new NPCLock(171, 24, 0, 127), // Lanturn (M) (Quirky) new NPCLock(082, 06, 2, 255), // Magneton (-) (Docile) - }}; + }); - public static readonly TeamLock XScyther = new TeamLock { - Species = 123, // Scyther - Locks = new[] + public static readonly TeamLock XScyther = new TeamLock( + 123, // Scyther + new[] { new NPCLock(234, 06, 1, 127), // Stantler (F) (Docile) new NPCLock(295, 24, 0, 127), // Exploud (M) (Quirky) - }}; + }); - public static readonly TeamLock XChansey = new TeamLock { - Species = 113, // Chansey - Locks = new[] { + public static readonly TeamLock XChansey = new TeamLock( + 113, // Chansey + new[] { new NPCLock(234, 06, 1, 127), // Stantler (F) (Docile) new NPCLock(295, 24, 0, 127), // Exploud (M) (Quirky) new NPCLock(123), // Shadow Scyther - }}; + }); - public static readonly TeamLock XChanseyScytherSeen = new TeamLock { - Species = 113, // Chansey - Comment = "Scyther Seen", - Locks = new[] { + public static readonly TeamLock XChanseyScytherSeen = new TeamLock( + 113, // Chansey + "Scyther Seen", + new[] { new NPCLock(234, 06, 1, 127), // Stantler (F) (Docile) new NPCLock(295, 24, 0, 127), // Exploud (M) (Quirky) new NPCLock(123, true), // Shadow Scyther (Seen) - }}; + }); - public static readonly TeamLock XSolrock = new TeamLock { - Species = 338, // Solrock - Locks = new[] { + public static readonly TeamLock XSolrock = new TeamLock( + 338, // Solrock + new[] { new NPCLock(375, 24, 2, 255), // Metang (-) (Quirky) new NPCLock(195, 06, 0, 127), // Quagsire (M) (Docile) new NPCLock(212, 00, 1, 127), // Scizor (F) (Hardy) - }}; + }); - public static readonly TeamLock XStarmie = new TeamLock { - Species = 121, // Starmie - Locks = new[] { + public static readonly TeamLock XStarmie = new TeamLock( + 121, // Starmie + new[] { new NPCLock(375, 24, 2, 255), // Metang (-) (Quirky) new NPCLock(195, 06, 0, 127), // Quagsire (M) (Docile) new NPCLock(212, 00, 1, 127), // Scizor (F) (Hardy) new NPCLock(338), // Shadow Solrock new NPCLock(351, 18, 0, 127), // Castform (M) (Bashful) - }}; + }); - public static readonly TeamLock XStarmieSolrockSeen = new TeamLock { - Species = 121, // Starmie - Comment = "Solrock Seen", - Locks = new[] { + public static readonly TeamLock XStarmieSolrockSeen = new TeamLock( + 121, // Starmie + "Solrock Seen", + new[] { new NPCLock(375, 24, 2, 255), // Metang (-) (Quirky) new NPCLock(195, 06, 0, 127), // Quagsire (M) (Docile) new NPCLock(212, 00, 1, 127), // Scizor (F) (Hardy) new NPCLock(338, true), // Shadow Solrock (Seen) new NPCLock(351, 18, 0, 127), // Castform (M) (Bashful) - }}; + }); - public static readonly TeamLock XElectabuzz = new TeamLock { - Species = 125, // Electabuzz - Locks = new[] { + public static readonly TeamLock XElectabuzz = new TeamLock( + 125, // Electabuzz + new[] { new NPCLock(277), // Shadow Swellow new NPCLock(065, 24, 0, 063), // Alakazam (M) (Quirky) new NPCLock(230, 6, 1, 127), // Kingdra (F) (Docile) new NPCLock(214, 18, 1, 127), // Heracross (F) (Bashful) - }}; + }); - public static readonly TeamLock XElectabuzzSwellowSeen = new TeamLock { - Species = 125, // Electabuzz - Comment = "Swellow Seen", - Locks = new[] { + public static readonly TeamLock XElectabuzzSwellowSeen = new TeamLock( + 125, // Electabuzz + "Swellow Seen", + new[] { new NPCLock(277, true), // Shadow Swellow (Seen) new NPCLock(065, 24, 0, 063), // Alakazam (M) (Quirky) new NPCLock(230, 6, 1, 127), // Kingdra (F) (Docile) new NPCLock(214, 18, 1, 127), // Heracross (F) (Bashful) - }}; + }); - public static readonly TeamLock XSnorlax = new TeamLock { - Species = 143, // Snorlax - Locks = new[] { + public static readonly TeamLock XSnorlax = new TeamLock( + 143, // Snorlax + new[] { new NPCLock(277), // Shadow Swellow new NPCLock(065, 24, 0, 063), // Alakazam (M) (Quirky) new NPCLock(230, 6, 1, 127), // Kingdra (F) (Docile) new NPCLock(214, 18, 1, 127), // Heracross (F) (Bashful) new NPCLock(125), // Shadow Electabuzz - }}; + }); - public static readonly TeamLock XSnorlaxSwellowSeen = new TeamLock { - Species = 143, // Snorlax - Comment = "Swellow Seen", - Locks = new[] { + public static readonly TeamLock XSnorlaxSwellowSeen = new TeamLock( + 143, // Snorlax + "Swellow Seen", + new[] { new NPCLock(277, true), // Shadow Swellow (Seen) new NPCLock(065, 24, 0, 063), // Alakazam (M) (Quirky) new NPCLock(230, 6, 1, 127), // Kingdra (F) (Docile) new NPCLock(214, 18, 1, 127), // Heracross (F) (Bashful) new NPCLock(125), // Shadow Electabuzz - }}; + }); - public static readonly TeamLock XSnorlaxSwellowElectabuzzSeen = new TeamLock { - Species = 143, // Snorlax - Comment = "Swellow & Electabuzz Seen", - Locks = new[] { + public static readonly TeamLock XSnorlaxSwellowElectabuzzSeen = new TeamLock( + 143, // Snorlax + "Swellow & Electabuzz Seen", + new[] { new NPCLock(277, true), // Shadow Swellow (Seen) new NPCLock(065, 24, 0, 063), // Alakazam (M) (Quirky) new NPCLock(230, 6, 1, 127), // Kingdra (F) (Docile) new NPCLock(214, 18, 1, 127), // Heracross (F) (Bashful) new NPCLock(125, true), // Shadow Electabuzz - }}; + }); - public static readonly TeamLock XPoliwrath = new TeamLock { - Species = 062, // Poliwrath - Locks = new[] { + public static readonly TeamLock XPoliwrath = new TeamLock( + 062, // Poliwrath + new[] { new NPCLock(199, 18, 0, 127), // Slowking (M) (Bashful) new NPCLock(217, 18, 0, 127), // Ursaring (M) (Bashful) new NPCLock(306, 24, 0, 127), // Aggron (M) (Quirky) new NPCLock(365, 06, 1, 127), // Walrein (F) (Docile) - }}; + }); - public static readonly TeamLock XMrMime = new TeamLock { - Species = 122, // Mr. Mime - Locks = new[] { + public static readonly TeamLock XMrMime = new TeamLock( + 122, // Mr. Mime + new[] { new NPCLock(199, 18, 0, 127), // Slowking (M) (Bashful) new NPCLock(217, 18, 0, 127), // Ursaring (M) (Bashful) new NPCLock(306, 24, 0, 127), // Aggron (M) (Quirky) new NPCLock(365, 06, 1, 127), // Walrein (F) (Docile) new NPCLock(062), // Shadow Poliwrath - }}; + }); - public static readonly TeamLock XMrMimePoliwrathSeen = new TeamLock { - Species = 122, // Mr. Mime - Comment = "Poliwrath Seen", - Locks = new[] { + public static readonly TeamLock XMrMimePoliwrathSeen = new TeamLock( + 122, // Mr. Mime + "Poliwrath Seen", + new[] { new NPCLock(199, 18, 0, 127), // Slowking (M) (Bashful) new NPCLock(217, 18, 0, 127), // Ursaring (M) (Bashful) new NPCLock(306, 24, 0, 127), // Aggron (M) (Quirky) new NPCLock(365, 06, 1, 127), // Walrein (F) (Docile) new NPCLock(062, true), // Shadow Poliwrath (Seen) - }}; + }); - public static readonly TeamLock XDugtrio = new TeamLock { - Species = 051, // Dugtrio - Locks = new[] { + public static readonly TeamLock XDugtrio = new TeamLock( + 051, // Dugtrio + new[] { new NPCLock(362, 00, 0, 127), // Glalie (M) (Hardy) new NPCLock(181, 18, 0, 127), // Ampharos (M) (Bashful) new NPCLock(286, 06, 1, 127), // Breloom (F) (Docile) new NPCLock(232, 12, 0, 127), // Donphan (M) (Serious) - }}; + }); - public static readonly TeamLock XManectric = new TeamLock { - Species = 310, // Manectric - Locks = new[] { + public static readonly TeamLock XManectric = new TeamLock( + 310, // Manectric + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) - }}; + }); - public static readonly TeamLock XSalamence = new TeamLock { - Species = 373, // Salamence - Locks = new[] { + public static readonly TeamLock XSalamence = new TeamLock( + 373, // Salamence + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310), // Shadow Manectric - }}; + }); - public static readonly TeamLock XMarowak = new TeamLock { - Species = 105, // Marowak - Locks = new[] { + public static readonly TeamLock XMarowak = new TeamLock( + 105, // Marowak + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310), // Shadow Manectric new NPCLock(373), // Shadow Salamence new NPCLock(330, 24, 0, 127), // Flygon (M) (Quirky) - }}; + }); - public static readonly TeamLock XLapras = new TeamLock { - Species = 131, // Lapras - Locks = new[] { + public static readonly TeamLock XLapras = new TeamLock( + 131, // Lapras + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310), // Shadow Manectric new NPCLock(373), // Shadow Salamence new NPCLock(330, 24, 0, 127), // Flygon (M) (Quirky) new NPCLock(105), // Shadow Marowak - }}; + }); - public static readonly TeamLock XSalamenceManectricSeen = new TeamLock { - Species = 373, // Salamence - Comment = "Manectric Seen", - Locks = new[] { + public static readonly TeamLock XSalamenceManectricSeen = new TeamLock( + 373, // Salamence + "Manectric Seen", + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310, true), // Shadow Manectric (Seen) - }}; + }); - public static readonly TeamLock XMarowakManectricSeen = new TeamLock { - Species = 105, // Marowak - Comment = "Manectric Seen", - Locks = new[] { + public static readonly TeamLock XMarowakManectricSeen = new TeamLock( + 105, // Marowak + "Manectric Seen", + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310, true), // Shadow Manectric (Seen) new NPCLock(373), // Shadow Salamence new NPCLock(330, 24, 0, 127), // Flygon (M) (Quirky) - }}; + }); - public static readonly TeamLock XMarowakManectricSalamenceSeen = new TeamLock { - Species = 105, // Marowak - Comment = "Manectric & Salamence Seen", - Locks = new[] { + public static readonly TeamLock XMarowakManectricSalamenceSeen = new TeamLock( + 105, // Marowak + "Manectric & Salamence Seen", + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310, true), // Shadow Manectric (Seen) new NPCLock(373, true), // Shadow Salamence (Seen) new NPCLock(330, 24, 0, 127), // Flygon (M) (Quirky) - }}; + }); - public static readonly TeamLock XLaprasManectricSeen = new TeamLock { - Species = 131, // Lapras - Comment = "Manectric Seen", - Locks = new[] { + public static readonly TeamLock XLaprasManectricSeen = new TeamLock( + 131, // Lapras + "Manectric Seen", + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310, true), // Shadow Manectric (Seen) new NPCLock(373), // Shadow Salamence new NPCLock(330, 24, 0, 127), // Flygon (M) (Quirky) new NPCLock(105), // Shadow Marowak - }}; + }); - public static readonly TeamLock XLaprasManectricSalamenceSeen = new TeamLock { - Species = 131, // Lapras - Comment = "Manectric & Salamence Seen", - Locks = new[] { + public static readonly TeamLock XLaprasManectricSalamenceSeen = new TeamLock( + 131, // Lapras + "Manectric & Salamence Seen", + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310, true), // Shadow Manectric (Seen) new NPCLock(373, true), // Shadow Salamence (Seen) new NPCLock(330, 24, 0, 127), // Flygon (M) (Quirky) new NPCLock(105), // Shadow Marowak - }}; + }); - public static readonly TeamLock XLaprasManectricMarowakSeen = new TeamLock { - Species = 131, // Lapras - Comment = "Manectric & Marowak Seen", - Locks = new[] { + public static readonly TeamLock XLaprasManectricMarowakSeen = new TeamLock( + 131, // Lapras + "Manectric & Marowak Seen", + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310, true), // Shadow Manectric (Seen) new NPCLock(373), // Shadow Salamence new NPCLock(330, 24, 0, 127), // Flygon (M) (Quirky) new NPCLock(105, true), // Shadow Marowak (Seen) - }}; + }); - public static readonly TeamLock XLaprasManectricSalamenceMarowakSeen = new TeamLock { - Species = 131, // Lapras - Comment = "Manectric & Salamence & Marowak Seen", - Locks = new[] { + public static readonly TeamLock XLaprasManectricSalamenceMarowakSeen = new TeamLock( + 131, // Lapras + "Manectric & Salamence & Marowak Seen", + new[] { new NPCLock(291, 06, 1, 127), // Ninjask (F) (Docile) new NPCLock(310, true), // Shadow Manectric (Seen) new NPCLock(373, true), // Shadow Salamence (Seen) new NPCLock(330, 24, 0, 127), // Flygon (M) (Quirky) new NPCLock(105, true), // Shadow Marowak (Seen) - }}; + }); - public static readonly TeamLock XMoltres = new TeamLock { - Species = 146, // Moltres - Locks = new[] { + public static readonly TeamLock XMoltres = new TeamLock( + 146, // Moltres + new[] { new NPCLock(112), // Shadow Rhydon - }}; + }); - public static readonly TeamLock XExeggutor = new TeamLock { - Species = 103, // Exeggutor - Locks = new[] { + public static readonly TeamLock XExeggutor = new TeamLock( + 103, // Exeggutor + new[] { new NPCLock(112), // Shadow Rhydon new NPCLock(146), // Shadow Moltres - }}; + }); - public static readonly TeamLock XTauros = new TeamLock { - Species = 128, // Tauros - Locks = new[] { + public static readonly TeamLock XTauros = new TeamLock( + 128, // Tauros + new[] { new NPCLock(112), // Shadow Rhydon new NPCLock(146), // Shadow Moltres new NPCLock(103), // Shadow Exeggutor - }}; + }); - public static readonly TeamLock XArticuno = new TeamLock { - Species = 144, // Articuno - Locks = new[] { + public static readonly TeamLock XArticuno = new TeamLock( + 144, // Articuno + new[] { new NPCLock(112), // Shadow Rhydon new NPCLock(146), // Shadow Moltres new NPCLock(103), // Shadow Exeggutor new NPCLock(128), // Shadow Tauros - }}; + }); - public static readonly TeamLock XZapdos = new TeamLock { - Species = 145, // Zapdos - Locks = new[] { + public static readonly TeamLock XZapdos = new TeamLock( + 145, // Zapdos + new[] { new NPCLock(112), // Shadow Rhydon new NPCLock(146), // Shadow Moltres new NPCLock(103), // Shadow Exeggutor new NPCLock(128), // Shadow Tauros new NPCLock(144), // Shadow Articuno - }}; + }); - public static readonly TeamLock XExeggutorRhydonMoltresSeen = new TeamLock { - Species = 103, // Exeggutor - Comment = "Rhydon & Moltres Seen", - Locks = new[] { + public static readonly TeamLock XExeggutorRhydonMoltresSeen = new TeamLock( + 103, // Exeggutor + "Rhydon & Moltres Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) - }}; + }); - public static readonly TeamLock XTaurosRhydonMoltresSeen = new TeamLock { - Species = 128, // Tauros - Comment = "Rhydon & Moltres Seen", - Locks = new[] { + public static readonly TeamLock XTaurosRhydonMoltresSeen = new TeamLock( + 128, // Tauros + "Rhydon & Moltres Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103), // Shadow Exeggutor - }}; + }); - public static readonly TeamLock XTaurosRhydonMoltresExeggutorSeen = new TeamLock { - Species = 128, // Tauros - Comment = "Rhydon & Moltres & Exeggutor Seen", - Locks = new[] { + public static readonly TeamLock XTaurosRhydonMoltresExeggutorSeen = new TeamLock( + 128, // Tauros + "Rhydon & Moltres & Exeggutor Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103, true), // Shadow Exeggutor (Seen) - }}; + }); - public static readonly TeamLock XArticunoRhydonMoltresSeen = new TeamLock { - Species = 144, // Articuno - Comment = "Rhydon & Moltres Seen", - Locks = new[] { + public static readonly TeamLock XArticunoRhydonMoltresSeen = new TeamLock( + 144, // Articuno + "Rhydon & Moltres Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103), // Shadow Exeggutor new NPCLock(128), // Shadow Tauros - }}; + }); - public static readonly TeamLock XArticunoRhydonMoltresTaurosSeen = new TeamLock { - Species = 144, // Articuno - Comment = "Rhydon & Moltres & Tauros Seen", - Locks = new[] { + public static readonly TeamLock XArticunoRhydonMoltresTaurosSeen = new TeamLock( + 144, // Articuno + "Rhydon & Moltres & Tauros Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103), // Shadow Exeggutor new NPCLock(128, true), // Shadow Tauros (Seen) - }}; + }); - public static readonly TeamLock XArticunoRhydonMoltresExeggutorSeen = new TeamLock { - Species = 144, // Articuno - Comment = "Rhydon & Moltres & Exeggutor Seen", - Locks = new[] { + public static readonly TeamLock XArticunoRhydonMoltresExeggutorSeen = new TeamLock( + 144, // Articuno + "Rhydon & Moltres & Exeggutor Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103, true), // Shadow Exeggutor (Seen) new NPCLock(128), // Shadow Tauros - }}; + }); - public static readonly TeamLock XArticunoRhydonMoltresExeggutorTaurosSeen = new TeamLock { - Species = 144, // Articuno - Comment = "Rhydon & Moltres & Exeggutor & Tauros Seen", - Locks = new[] { + public static readonly TeamLock XArticunoRhydonMoltresExeggutorTaurosSeen = new TeamLock( + 144, // Articuno + "Rhydon & Moltres & Exeggutor & Tauros Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103, true), // Shadow Exeggutor (Seen) new NPCLock(128, true), // Shadow Tauros (Seen) - }}; + }); - public static readonly TeamLock XZapdosRhydonMoltresSeen = new TeamLock { - Species = 145, // Zapdos - Comment = "Rhydon & Moltres Seen", - Locks = new[] { + public static readonly TeamLock XZapdosRhydonMoltresSeen = new TeamLock( + 145, // Zapdos + "Rhydon & Moltres Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103), // Shadow Exeggutor new NPCLock(128), // Shadow Tauros new NPCLock(144), // Shadow Articuno - }}; + }); - public static readonly TeamLock XZapdosRhydonMoltresTaurosSeen = new TeamLock { - Species = 145, // Zapdos - Comment = "Rhydon & Moltres & Tauros Seen", - Locks = new[] { + public static readonly TeamLock XZapdosRhydonMoltresTaurosSeen = new TeamLock( + 145, // Zapdos + "Rhydon & Moltres & Tauros Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103), // Shadow Exeggutor new NPCLock(128, true), // Shadow Tauros (Seen) new NPCLock(144), // Shadow Articuno - }}; + }); - public static readonly TeamLock XZapdosRhydonMoltresArticunoSeen = new TeamLock { - Species = 145, // Zapdos - Comment = "Rhydon & Moltres & Articuno Seen", - Locks = new[] { + public static readonly TeamLock XZapdosRhydonMoltresArticunoSeen = new TeamLock( + 145, // Zapdos + "Rhydon & Moltres & Articuno Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103), // Shadow Exeggutor new NPCLock(128), // Shadow Tauros new NPCLock(144, true), // Shadow Articuno (Seen) - }}; + }); - public static readonly TeamLock XZapdosRhydonMoltresExeggutorSeen = new TeamLock { - Species = 145, // Zapdos - Comment = "Rhydon & Moltres & Exeggutor Seen", - Locks = new[] { + public static readonly TeamLock XZapdosRhydonMoltresExeggutorSeen = new TeamLock( + 145, // Zapdos + "Rhydon & Moltres & Exeggutor Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103, true), // Shadow Exeggutor (Seen) new NPCLock(128), // Shadow Tauros new NPCLock(144), // Shadow Articuno - }}; + }); - public static readonly TeamLock XZapdosRhydonMoltresTaurosArticunoSeen = new TeamLock { - Species = 145, // Zapdos - Comment = "Rhydon & Moltres & Tauros & Articuno Seen", - Locks = new[] { + public static readonly TeamLock XZapdosRhydonMoltresTaurosArticunoSeen = new TeamLock( + 145, // Zapdos + "Rhydon & Moltres & Tauros & Articuno Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103), // Shadow Exeggutor new NPCLock(128, true), // Shadow Tauros (Seen) new NPCLock(144, true), // Shadow Articuno (Seen) - }}; + }); - public static readonly TeamLock XZapdosRhydonMoltresExeggutorTaurosSeen = new TeamLock { - Species = 145, // Zapdos - Comment = "Rhydon & Moltres & Exeggutor & Tauros Seen", - Locks = new[] { + public static readonly TeamLock XZapdosRhydonMoltresExeggutorTaurosSeen = new TeamLock( + 145, // Zapdos + "Rhydon & Moltres & Exeggutor & Tauros Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103, true), // Shadow Exeggutor (Seen) new NPCLock(128, true), // Shadow Tauros (Seen) new NPCLock(144), // Shadow Articuno - }}; + }); - public static readonly TeamLock XZapdosRhydonMoltresExeggutorArticunoSeen = new TeamLock { - Species = 145, // Zapdos - Comment = "Rhydon & Moltres & Exeggutor & Articuno Seen", - Locks = new[] { + public static readonly TeamLock XZapdosRhydonMoltresExeggutorArticunoSeen = new TeamLock( + 145, // Zapdos + "Rhydon & Moltres & Exeggutor & Articuno Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103, true), // Shadow Exeggutor (Seen) new NPCLock(128), // Shadow Tauros new NPCLock(144, true), // Shadow Articuno (Seen) - }}; + }); - public static readonly TeamLock XZapdosRhydonMoltresExeggutorTaurosArticunoSeen = new TeamLock { - Species = 145, // Zapdos - Comment = "Rhydon & Moltres & Exeggutor & Tauros & Articuno Seen", - Locks = new[] { + public static readonly TeamLock XZapdosRhydonMoltresExeggutorTaurosArticunoSeen = new TeamLock( + 145, // Zapdos + "Rhydon & Moltres & Exeggutor & Tauros & Articuno Seen", + new[] { new NPCLock(112, true), // Shadow Rhydon (Seen) new NPCLock(146, true), // Shadow Moltres (Seen) new NPCLock(103, true), // Shadow Exeggutor (Seen) new NPCLock(128, true), // Shadow Tauros (Seen) new NPCLock(144, true), // Shadow Articuno (Seen) - }}; + }); - public static readonly TeamLock XDragonite = new TeamLock { - Species = 149, // Dragonite - Locks = new[] { + public static readonly TeamLock XDragonite = new TeamLock( + 149, // Dragonite + new[] { new NPCLock(272, 00, 0, 127), // Ludicolo (M) (Hardy) new NPCLock(272, 18, 0, 127), // Ludicolo (M) (Bashful) new NPCLock(272, 12, 1, 127), // Ludicolo (F) (Serious) new NPCLock(272, 12, 1, 127), // Ludicolo (F) (Serious) new NPCLock(272, 00, 0, 127), // Ludicolo (M) (Hardy) - }}; + }); #endregion } diff --git a/PKHeX.Core/Legality/Encounters/Data/Encounters4.cs b/PKHeX.Core/Legality/Encounters/Data/Encounters4.cs index 88bc743f7..c68507b48 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Encounters4.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Encounters4.cs @@ -996,7 +996,7 @@ private static void MarkHGSSEncounterTypeSlots(EncounterArea4[] Areas) Encounter_HGSS_Regular); #endregion #region Trade Tables - private static readonly string[] RanchOTNames = { null, "ユカリ", "Hayley", "EULALIE", "GIULIA", "EUKALIA", null, "Eulalia" }; + private static readonly string[] RanchOTNames = { string.Empty, "ユカリ", "Hayley", "EULALIE", "GIULIA", "EUKALIA", string.Empty, "Eulalia" }; private static readonly EncounterTrade[] RanchGifts = { diff --git a/PKHeX.Core/Legality/Encounters/Data/Encounters5.cs b/PKHeX.Core/Legality/Encounters/Data/Encounters5.cs index 8f32cb35e..0d0ed16b7 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Encounters5.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Encounters5.cs @@ -100,7 +100,7 @@ private static void MarkG5DreamWorld(ref EncounterStatic[] t) var list = new List(); foreach (EncounterStatic s in t) { - if (s.Moves == null || s.Moves.Length <= 1) // no special moves + if (s.Moves.Length <= 1) // no special moves { list.Add(s); continue; @@ -745,8 +745,8 @@ private static void MarkG5Slots(ref EncounterArea5[] Areas) private const string tradeB2W2 = "tradeb2w2"; private static readonly string[][] TradeBW = Util.GetLanguageStrings8(tradeBW); private static readonly string[][] TradeB2W2 = Util.GetLanguageStrings8(tradeB2W2); - private static readonly string[] TradeOT_B2W2_F = {null, "ルリ", "Yancy", "Brenda", "Lilì", "Sabine", null, "Belinda", "루리"}; - private static readonly string[] TradeOT_B2W2_M = {null, "テツ", "Curtis", "Julien", "Dadi", "Markus", null, "Julián", "철권"}; + private static readonly string[] TradeOT_B2W2_F = {string.Empty, "ルリ", "Yancy", "Brenda", "Lilì", "Sabine", string.Empty, "Belinda", "루리"}; + private static readonly string[] TradeOT_B2W2_M = {string.Empty, "テツ", "Curtis", "Julien", "Dadi", "Markus", string.Empty, "Julián", "철권"}; internal static readonly EncounterTrade[] TradeGift_B2W2 = TradeGift_B2W2_Regular.Concat(TradeGift_B2W2_YancyCurtis).ToArray(); diff --git a/PKHeX.Core/Legality/Encounters/Data/Encounters7.cs b/PKHeX.Core/Legality/Encounters/Data/Encounters7.cs index b8ca6af4f..5d49d340a 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Encounters7.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Encounters7.cs @@ -26,9 +26,11 @@ static Encounters7() MarkG7REGSlots(ref REG_MN); MarkG7SMSlots(ref SOS_SN); MarkG7SMSlots(ref SOS_MN); - InitializePelagoAreas(); - SlotsSN = AddExtraTableSlots(REG_SN, SOS_SN, Encounter_Pelago_SN); - SlotsMN = AddExtraTableSlots(REG_MN, SOS_MN, Encounter_Pelago_MN); + int[] pelagoMin = { 1, 11, 21, 37, 49 }; + InitializePelagoSM(pelagoMin, out var p_sn, out var p_mn); + InitializePelagoUltra(pelagoMin, out var p_us, out var p_um); + SlotsSN = AddExtraTableSlots(REG_SN, SOS_SN, p_sn); + SlotsMN = AddExtraTableSlots(REG_MN, SOS_MN, p_mn); var REG_US = GetEncounterTables("uu", "us"); var REG_UM = GetEncounterTables("uu", "um"); @@ -38,12 +40,12 @@ static Encounters7() MarkG7REGSlots(ref REG_UM); MarkG7SMSlots(ref SOS_US); MarkG7SMSlots(ref SOS_UM); - SlotsUS = AddExtraTableSlots(REG_US, SOS_US, Encounter_Pelago_US); - SlotsUM = AddExtraTableSlots(REG_UM, SOS_UM, Encounter_Pelago_UM); + SlotsUS = AddExtraTableSlots(REG_US, SOS_US, p_us); + SlotsUM = AddExtraTableSlots(REG_UM, SOS_UM, p_um); MarkEncounterAreaArray(SOS_SN, SOS_MN, SOS_US, SOS_UM, - Encounter_Pelago_SN, Encounter_Pelago_MN, - Encounter_Pelago_US, Encounter_Pelago_UM); + p_sn, p_mn, + p_us, p_um); MarkEncountersGeneration(7, SlotsSN, SlotsMN, SlotsUS, SlotsUM); MarkEncountersGeneration(7, StaticSN, StaticMN, StaticUS, StaticUM, TradeGift_SM, TradeGift_USUM); @@ -407,11 +409,8 @@ private static void MarkG7SMSlots(ref EncounterArea7[] Areas) private static readonly string[][] TradeSM = Util.GetLanguageStrings10(tradeSM); private static readonly string[][] TradeUSUM = Util.GetLanguageStrings10(tradeUSUM); - private static EncounterArea7[] Encounter_Pelago_SN, Encounter_Pelago_MN, Encounter_Pelago_US, Encounter_Pelago_UM; - - private static void InitializePelagoAreas() + private static void InitializePelagoSM(int[] minLevels, out EncounterArea7[] sn, out EncounterArea7[] mn) { - int[] minLevels = { 1, 11, 21, 37, 49 }; int[][] speciesSM = { new[] {627/*SN*/, 021, 041, 090, 278, 731}, // 1-7 @@ -420,10 +419,13 @@ private static void InitializePelagoAreas() new[] {227, 375, 707}, // 37-43 new[] {123, 131, 429, 587}, // 49-55 }; - Encounter_Pelago_SN = GetPelagoArea(speciesSM, minLevels); + sn = GetPelagoArea(speciesSM, minLevels); speciesSM[0][0] = 629; // Rufflet -> Vullaby - Encounter_Pelago_MN = GetPelagoArea(speciesSM, minLevels); + mn = GetPelagoArea(speciesSM, minLevels); + } + private static void InitializePelagoUltra(int[] minLevels, out EncounterArea7[] us, out EncounterArea7[] um) + { int[][] speciesUU = { new[] {731, 278, 041, 742, 086}, // 1-7 @@ -432,9 +434,9 @@ private static void InitializePelagoAreas() new[] {131, 354, 200, /* US */ 228}, // 37-43 new[] {209, 667, 357, 430}, // 49-55 }; - Encounter_Pelago_US = GetPelagoArea(speciesUU, minLevels); + us = GetPelagoArea(speciesUU, minLevels); speciesUU[3][3] = 309; // Houndour -> Electrike - Encounter_Pelago_UM = GetPelagoArea(speciesUU, minLevels); + um = GetPelagoArea(speciesUU, minLevels); } private static EncounterArea7[] GetPelagoArea(int[][] species, int[] min) diff --git a/PKHeX.Core/Legality/Encounters/Data/Encounters7b.cs b/PKHeX.Core/Legality/Encounters/Data/Encounters7b.cs index fd8374c33..5336d0ab4 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Encounters7b.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Encounters7b.cs @@ -60,14 +60,14 @@ static Encounters7b() new EncounterStatic { Species = 059, Level = 16, Location = 33, Gift = true, IVs = new[] {25,30,25,31,30,25}, Version = GameVersion.GE }, // Arcanine @ Vermillion City (Outside Fan Club) }; - private static readonly string[] T1 = { null, "ミニコ", "Tatianna", "BarbaRatatta", "Addoloratta", "Barbaratt", null, "Tatiana", "미니꼬", "小幂妮", "小幂妮", }; - private static readonly string[] T2 = { null, "ボーアイス", "Nicholice", "Iceman-4L0L4", "Goffreddo", "Eisper", null, "Gelasio", "보아이스", "露冰冰", "露冰冰", }; - private static readonly string[] T3 = { null, "レディダグ", "Diggette", "Taupilady", "Lady Glett", "Digga", null, "Glenda", "레이디그다", "蒂淑", "蒂淑", }; - private static readonly string[] T4 = { null, "ワルモン", "Darko", "AlolaZeDark", "Mattetro", "Bösbert", null, "Sinesio", "나뻐기", "达怀丹", "达怀丹", }; - private static readonly string[] T5 = { null, "エリッチ", "Psytrice", "TopDeTonCœur", "Chulia", "Assana", null, "Menchu", "엘리츄", "晶莹丘", "晶莹丘", }; - private static readonly string[] T6 = { null, "ジェンガラ", "Genmar", "OSS-Dandy7", "Mr. Owak", "Knoggelius", null, "Mario", "젠구리", "申史加拉", "申史加拉", }; - private static readonly string[] T7 = { null, "マニシ", "Exemann", "Koko-fan", "Exechiele", "Einrich", null, "Gunter", "마니시", "艾浩舒", "艾浩舒", }; - private static readonly string[] T8 = { null, "コツブ", "Higeo", "Montagnou", "George", "Karstein", null, "Georgie", "산돌", "科布", "科布", }; + private static readonly string[] T1 = { string.Empty, "ミニコ", "Tatianna", "BarbaRatatta", "Addoloratta", "Barbaratt", string.Empty, "Tatiana", "미니꼬", "小幂妮", "小幂妮", }; + private static readonly string[] T2 = { string.Empty, "ボーアイス", "Nicholice", "Iceman-4L0L4", "Goffreddo", "Eisper", string.Empty, "Gelasio", "보아이스", "露冰冰", "露冰冰", }; + private static readonly string[] T3 = { string.Empty, "レディダグ", "Diggette", "Taupilady", "Lady Glett", "Digga", string.Empty, "Glenda", "레이디그다", "蒂淑", "蒂淑", }; + private static readonly string[] T4 = { string.Empty, "ワルモン", "Darko", "AlolaZeDark", "Mattetro", "Bösbert", string.Empty, "Sinesio", "나뻐기", "达怀丹", "达怀丹", }; + private static readonly string[] T5 = { string.Empty, "エリッチ", "Psytrice", "TopDeTonCœur", "Chulia", "Assana", string.Empty, "Menchu", "엘리츄", "晶莹丘", "晶莹丘", }; + private static readonly string[] T6 = { string.Empty, "ジェンガラ", "Genmar", "OSS-Dandy7", "Mr. Owak", "Knoggelius", string.Empty, "Mario", "젠구리", "申史加拉", "申史加拉", }; + private static readonly string[] T7 = { string.Empty, "マニシ", "Exemann", "Koko-fan", "Exechiele", "Einrich", string.Empty, "Gunter", "마니시", "艾浩舒", "艾浩舒", }; + private static readonly string[] T8 = { string.Empty, "コツブ", "Higeo", "Montagnou", "George", "Karstein", string.Empty, "Georgie", "산돌", "科布", "科布", }; internal static readonly EncounterTrade[] TradeGift_GG = { @@ -145,33 +145,39 @@ EncounterSlot GetSlot(int species, int form) private class RareSpawn { - public int Species; - public int[] Locations; + public readonly int Species; + public readonly byte[] Locations; + + protected internal RareSpawn(int species, params byte[] locations) + { + Species = species; + Locations = locations; + } } - private static readonly int[] Sky = {003, 004, 005, 006, 009, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 021, 022, 023, 024, 025, 026, 027}; + private static readonly byte[] Sky = {003, 004, 005, 006, 009, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 021, 022, 023, 024, 025, 026, 027}; private static readonly RareSpawn[] Rare = { // Normal - new RareSpawn {Species = 001, Locations = new[] {039}}, - new RareSpawn {Species = 004, Locations = new[] {005, 006, 041}}, - new RareSpawn {Species = 007, Locations = new[] {026, 027, 044}}, - new RareSpawn {Species = 106, Locations = new[] {045}}, - new RareSpawn {Species = 107, Locations = new[] {045}}, - new RareSpawn {Species = 113, Locations = new[] {007, 008, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 023, 025, 040, 042, 043, 045, 047, 051}}, - new RareSpawn {Species = 137, Locations = new[] {009}}, - new RareSpawn {Species = 143, Locations = new[] {046}}, + new RareSpawn(001, 039), + new RareSpawn(004, 005, 006, 041), + new RareSpawn(007, 026, 027, 044), + new RareSpawn(106, 045), + new RareSpawn(107, 045), + new RareSpawn(113, 007, 008, 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, 020, 023, 025, 040, 042, 043, 045, 047, 051), + new RareSpawn(137, 009), + new RareSpawn(143, 046), // Water - new RareSpawn {Species = 131, Locations = new[] {021, 022}}, + new RareSpawn(131, 021, 022), // Fly - new RareSpawn {Species = 006, Locations = Sky,}, - new RareSpawn {Species = 144, Locations = Sky,}, - new RareSpawn {Species = 145, Locations = Sky,}, - new RareSpawn {Species = 146, Locations = Sky,}, - new RareSpawn {Species = 149, Locations = Sky,}, + new RareSpawn(006, Sky), + new RareSpawn(144, Sky), + new RareSpawn(145, Sky), + new RareSpawn(146, Sky), + new RareSpawn(149, Sky), }; private static void ManuallyAddRareSpawns(IEnumerable areas) @@ -179,7 +185,7 @@ private static void ManuallyAddRareSpawns(IEnumerable areas) foreach (var table in areas) { var loc = table.Location; - var species = Rare.Where(z => z.Locations.Contains(loc)).Select(z => z.Species).ToArray(); + var species = Rare.Where(z => z.Locations.Contains((byte)loc)).Select(z => z.Species).ToArray(); if (species.Length == 0) continue; var slots = table.Slots; diff --git a/PKHeX.Core/Legality/Encounters/Data/EncountersWC3.cs b/PKHeX.Core/Legality/Encounters/Data/EncountersWC3.cs index 158c38eb2..f6ae2aefb 100644 --- a/PKHeX.Core/Legality/Encounters/Data/EncountersWC3.cs +++ b/PKHeX.Core/Legality/Encounters/Data/EncountersWC3.cs @@ -25,9 +25,9 @@ internal static class EncountersWC3 private static IEnumerable GetIngameCXDData() { var langs = new[]{LanguageID.Japanese, LanguageID.English, LanguageID.French, LanguageID.Italian, LanguageID.German, LanguageID.Spanish}; - var h = new[] {null, "ダニー", "HORDEL", "VOLKER", "ODINO", "HORAZ", null, "HORDEL"}; - var d = new[] {null, "ギンザル", "DUKING", "DOKING", "RODRIGO", "GRAND", null, "GERMÁN"}; - var m = new[] {null, "バトルやま", "MATTLE", "MT BATAILL", "MONTE LOTT", "DUELLBERG", null, "ERNESTO"}; // truncated on ck3->pk3 transfer + var h = new[] {string.Empty, "ダニー", "HORDEL", "VOLKER", "ODINO", "HORAZ", string.Empty, "HORDEL"}; + var d = new[] {string.Empty, "ギンザル", "DUKING", "DOKING", "RODRIGO", "GRAND", string.Empty, "GERMÁN"}; + var m = new[] {string.Empty, "バトルやま", "MATTLE", "MT BATAILL", "MONTE LOTT", "DUELLBERG", string.Empty, "ERNESTO"}; // truncated on ck3->pk3 transfer return langs.SelectMany(l => GetIngame((int)l)); IEnumerable GetIngame(int l) diff --git a/PKHeX.Core/Legality/Encounters/EncounterEgg.cs b/PKHeX.Core/Legality/Encounters/EncounterEgg.cs index 306d28246..3f13500aa 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterEgg.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterEgg.cs @@ -77,7 +77,7 @@ private void SetAltForm(PKM pk, ITrainerInfo SAV) case (int)Core.Species.Scatterbug: case (int)Core.Species.Spewpa: case (int)Core.Species.Vivillon: - pk.AltForm = Legal.GetVivillonPattern(SAV.Country, SAV.SubRegion); + pk.AltForm = Legal.GetVivillonPattern((byte)SAV.Country, (byte)SAV.SubRegion); break; } } diff --git a/PKHeX.Core/Legality/Encounters/EncounterInvalid.cs b/PKHeX.Core/Legality/Encounters/EncounterInvalid.cs index d71bfb266..db4a09b78 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterInvalid.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterInvalid.cs @@ -7,6 +7,8 @@ namespace PKHeX.Core /// public sealed class EncounterInvalid : IEncounterable { + public static readonly EncounterInvalid Default = new EncounterInvalid(); + public int Species { get; } public int LevelMin { get; } public int LevelMax { get; } @@ -15,6 +17,8 @@ public sealed class EncounterInvalid : IEncounterable public string Name => "Invalid"; public string LongName => "Invalid"; + private EncounterInvalid() { } + public EncounterInvalid(PKM pkm) { Species = pkm.Species; diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot.cs index bc35b7aba..54c45cae5 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot.cs @@ -50,12 +50,12 @@ public class EncounterSlot : IEncounterable, IGeneration, ILocation, IVersion public EncounterType TypeEncounter { get; set; } = EncounterType.None; public int SlotNumber { get; set; } public int Generation { get; set; } = -1; - internal EncounterSlotPermissions _perm; + private EncounterSlotPermissions? _perm; public EncounterSlotPermissions Permissions => _perm ??= new EncounterSlotPermissions(); public GameVersion Version { get; set; } - internal EncounterArea Area { private get; set; } - public int Location { get => Area.Location; set { } } + internal EncounterArea? Area { private get; set; } + public int Location { get => Area?.Location ?? 0; set { } } public bool EggEncounter => false; public int EggLocation { get => 0; set { } } @@ -122,7 +122,7 @@ public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) private void SetEncounterMoves(PKM pk, GameVersion version, int level) { - var moves = this is EncounterSlotMoves m ? m.Moves : MoveLevelUp.GetEncounterMoves(pk, level, version); + var moves = this is IMoveset m ? m.Moves : MoveLevelUp.GetEncounterMoves(pk, level, version); pk.Moves = moves; pk.SetMaximumPPCurrent(moves); } @@ -205,7 +205,7 @@ private static int GetWildAltForm(PKM pk, int form, ITrainerInfo SAV) int spec = pk.Species; if (spec == (int)Core.Species.Scatterbug || spec == (int)Core.Species.Spewpa || spec == (int)Core.Species.Vivillon) - return Legal.GetVivillonPattern(SAV.Country, SAV.SubRegion); + return Legal.GetVivillonPattern((byte)SAV.Country, (byte)SAV.SubRegion); return 0; } diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot3Swarm.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot3Swarm.cs new file mode 100644 index 000000000..d3a8728a6 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot3Swarm.cs @@ -0,0 +1,9 @@ +namespace PKHeX.Core +{ + internal sealed class EncounterSlot3Swarm : EncounterSlot, IMoveset + { + public int[] Moves { get; } + + public EncounterSlot3Swarm(int[] moves) => Moves = moves; + } +} \ No newline at end of file diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlotMoves.cs b/PKHeX.Core/Legality/Encounters/EncounterSlotMoves.cs deleted file mode 100644 index 0d7890986..000000000 --- a/PKHeX.Core/Legality/Encounters/EncounterSlotMoves.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace PKHeX.Core -{ - internal sealed class EncounterSlotMoves : EncounterSlot, IMoveset - { - public int[] Moves { get; set; } - } -} \ No newline at end of file diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic.cs index b7ee8dd61..151304049 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic.cs @@ -12,7 +12,7 @@ namespace PKHeX.Core public class EncounterStatic : IEncounterable, IMoveset, IGeneration, ILocation, IContestStats, IVersion { public int Species { get; set; } - public int[] Moves { get; set; } + public int[] Moves { get; set; } = Array.Empty(); public int Level { get; set; } public int LevelMin => Level; @@ -29,7 +29,7 @@ public class EncounterStatic : IEncounterable, IMoveset, IGeneration, ILocation, public bool Gift { get; set; } public int Ball { get; set; } = 4; // Only checked when is Gift public GameVersion Version { get; set; } = GameVersion.Any; - public int[] IVs { get; set; } + public int[] IVs { get; set; } = Array.Empty(); public int FlawlessIVCount { get; set; } public int[] Contest { set => this.SetContestStats(value); } @@ -52,9 +52,9 @@ public class EncounterStatic : IEncounterable, IMoveset, IGeneration, ILocation, private void CloneArrays() { // dereference original arrays with new copies - Moves = (int[])Moves?.Clone(); - Relearn = (int[])Relearn.Clone(); - IVs = (int[])IVs?.Clone(); + Moves = Moves.Length == 0 ? Moves : (int[])Moves.Clone(); + Relearn = Relearn.Length == 0 ? Relearn : (int[])Relearn.Clone(); + IVs = IVs.Length == 0 ? IVs : (int[])IVs.Clone(); } internal virtual EncounterStatic Clone() @@ -176,7 +176,7 @@ private void SetMetData(PKM pk, int level, DateTime today) private void SetEncounterMoves(PKM pk, GameVersion version, int level) { - var moves = Moves?.Length > 0 ? Moves : MoveLevelUp.GetEncounterMoves(pk, level, version); + var moves = Moves.Length > 0 ? Moves : MoveLevelUp.GetEncounterMoves(pk, level, version); pk.Moves = moves; pk.SetMaximumPPCurrent(moves); } @@ -196,7 +196,7 @@ private void SanityCheckVersion(ref GameVersion version) protected void SetIVs(PKM pk) { - if (IVs != null) + if (IVs.Length != 0) pk.SetRandomIVs(IVs, FlawlessIVCount); else if (FlawlessIVCount > 0) pk.SetRandomIVs(flawless: FlawlessIVCount); @@ -353,7 +353,7 @@ public bool IsMatch(PKM pkm, int lvl) if (EggLocation == Locations.Daycare5 && Relearn.Length == 0 && pkm.RelearnMoves.Any(z => z != 0)) // gen7 eevee edge case return false; - if (IVs != null && (Generation > 2 || pkm.Format <= 2)) // 1,2->7 regenerates IVs, only check if original IVs still exist + if (IVs.Length != 0 && (Generation > 2 || pkm.Format <= 2)) // 1,2->7 regenerates IVs, only check if original IVs still exist { if (!Legal.GetIsFixedIVSequenceValidSkipRand(IVs, pkm)) return false; diff --git a/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs b/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs index 3cc343d73..77989bd07 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs @@ -10,7 +10,7 @@ public sealed class EncounterStaticShadow : EncounterStatic /// /// Team Specification with required , and Gender. /// - public TeamLock[] Locks { get; internal set; } = Array.Empty(); + public readonly TeamLock[] Locks; /// /// Initial Shadow Gauge value. @@ -20,19 +20,9 @@ public sealed class EncounterStaticShadow : EncounterStatic /// /// Originates from the EReader scans (Japanese Only) /// - public bool EReader { get; set; } + public bool EReader { get; internal set; } - internal override EncounterStatic Clone() - { - var result = (EncounterStaticShadow)base.Clone(); - - if (Locks.Length == 0) - return result; - - result.Locks = new TeamLock[Locks.Length]; - for (int i = 0; i < Locks.Length; i++) - result.Locks[i] = Locks[i].Clone(); - return result; - } + public EncounterStaticShadow(TeamLock[] locks) => Locks = locks; + public EncounterStaticShadow() => Locks = Array.Empty(); } } \ No newline at end of file diff --git a/PKHeX.Core/Legality/Encounters/EncounterTrade.cs b/PKHeX.Core/Legality/Encounters/EncounterTrade.cs index ee8204c38..ed15deaa4 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterTrade.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterTrade.cs @@ -12,7 +12,7 @@ namespace PKHeX.Core public class EncounterTrade : IEncounterable, IMoveset, IGeneration, ILocation, IContestStats, IVersion { public int Species { get; set; } - public int[] Moves { get; set; } + public int[] Moves { get; set; } = Array.Empty(); public int Level { get; set; } public int LevelMin => Level; public int LevelMax => 100; @@ -24,7 +24,7 @@ public class EncounterTrade : IEncounterable, IMoveset, IGeneration, ILocation, public int TID { get; set; } public int SID { get; set; } public GameVersion Version { get; set; } = GameVersion.Any; - public int[] IVs { get; set; } + public int[] IVs { get; set; } = Array.Empty(); public int Form { get; set; } public virtual Shiny Shiny { get; set; } = Shiny.Never; public int Gender { get; set; } = -1; @@ -58,11 +58,12 @@ public int TID7 public bool Fateful { get; set; } public bool IsNicknamed { get; set; } = true; - public string[] Nicknames { get; internal set; } - public string[] TrainerNames { get; internal set; } - public string GetNickname(int language) => Nicknames?.Length > language ? Nicknames[language] : null; - public string GetOT(int language) => TrainerNames?.Length > language ? TrainerNames[language] : null; - public bool HasNickname => Nicknames != null; + public string[] Nicknames { get; internal set; } = Array.Empty(); + public string[] TrainerNames { get; internal set; } = Array.Empty(); + public string GetNickname(int language) => (uint)language < Nicknames.Length ? Nicknames[language] : string.Empty; + public string GetOT(int language) => (uint)language < TrainerNames.Length ? TrainerNames[language] : string.Empty; + public bool HasNickname => Nicknames.Length != 0; + public bool HasTrainerName => TrainerNames.Length != 0; public static readonly int[] DefaultMetLocation = { @@ -160,7 +161,7 @@ protected virtual void SetPINGA(PKM pk, EncounterCriteria criteria) protected void SetIVs(PKM pk) { - if (IVs != null) + if (IVs.Length != 0) pk.SetRandomIVs(IVs, 0); else pk.SetRandomIVs(flawless: 3); @@ -168,7 +169,7 @@ protected void SetIVs(PKM pk) private void SetMoves(PKM pk, GameVersion version, int level) { - var moves = Moves ?? MoveLevelUp.GetEncounterMoves(pk, level, version); + var moves = Moves.Length != 0 ? Moves : MoveLevelUp.GetEncounterMoves(pk, level, version); if (pk.Format == 1 && moves.All(z => z == 0)) moves = ((PersonalInfoG1)PersonalTable.RB[Species]).Moves; pk.Moves = moves; @@ -230,7 +231,7 @@ private static void SetSMOTMemory(PKM pk) public bool IsMatch(PKM pkm, int lvl) { - if (IVs != null) + if (IVs.Length != 0) { if (!Legal.GetIsFixedIVSequenceValidSkipRand(IVs, pkm)) return false; @@ -332,7 +333,7 @@ public bool IsMatchVC2(PKM pkm) { if (Gender >= 0 && Gender != pkm.Gender) return false; - if (IVs != null && !Legal.GetIsFixedIVSequenceValidNoRand(IVs, pkm)) + if (IVs.Length != 0 && !Legal.GetIsFixedIVSequenceValidNoRand(IVs, pkm)) return false; } if (pkm.Met_Location != 0 && pkm.Format == 2 && pkm.Met_Location != 126) diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs index 6136248d8..e24e5759d 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs @@ -45,7 +45,7 @@ bool ivCanMatch(int spec, int enc) public static EncounterCriteria GetCriteria(ShowdownSet s) { - int gender = s.Gender == null ? -1 : PKX.GetGenderFromString(s.Gender); + int gender = string.IsNullOrWhiteSpace(s.Gender) ? -1 : PKX.GetGenderFromString(s.Gender); return new EncounterCriteria { Gender = gender, diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs index a98708679..2b4b6650b 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs @@ -22,7 +22,7 @@ public static class EncounterFinder /// public static LegalInfo FindVerifiedEncounter(PKM pkm) { - LegalInfo info = new LegalInfo(pkm); + var info = new LegalInfo(pkm); var encounters = EncounterGenerator.GetEncounters(pkm, info); using var encounter = new PeekEnumerator(encounters); diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterGenerator.cs index d81747aaf..711de41a4 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterGenerator.cs @@ -69,7 +69,7 @@ private static IEnumerable GetEncounters3(PKM pkm, LegalInfo inf else if (z is EncounterStaticShadow s) { bool valid = false; - if (s.IVs == null) // not ereader + if (s.IVs.Length == 0) // not ereader { valid = LockFinder.IsAllShadowLockValid(s, info.PIDIV, pkm); } @@ -280,7 +280,7 @@ private static GBEncounterPriority GetGBEncounterPriority(PKM pkm, IEncounterabl case EncounterTrade t: return t.Generation == 2 ? GBEncounterPriority.TradeEncounterG2 : GBEncounterPriority.TradeEncounterG1; case EncounterStatic s: - if (s.Moves != null && s.Moves[0] != 0 && pkm.Moves.Contains(s.Moves[0])) + if (s.Moves.Length != 0 && s.Moves[0] != 0 && pkm.Moves.Contains(s.Moves[0])) return GBEncounterPriority.SpecialEncounter; return GBEncounterPriority.StaticEncounter; case EncounterSlot _: diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterMovesetGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterMovesetGenerator.cs index 732d08beb..e6925f0f7 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterMovesetGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterMovesetGenerator.cs @@ -15,10 +15,11 @@ public static class EncounterMovesetGenerator /// Order in which objects are yielded from the generator. /// // ReSharper disable once AutoPropertyCanBeMadeGetOnly.Global - public static IReadOnlyCollection PriorityList { get; set; } - - static EncounterMovesetGenerator() => ResetFilters(); + public static IReadOnlyCollection PriorityList { get; set; } = PriorityList = (EncounterOrder[])Enum.GetValues(typeof(EncounterOrder)); + /// + /// Resets the to the default values. + /// public static void ResetFilters() => PriorityList = (EncounterOrder[])Enum.GetValues(typeof(EncounterOrder)); /// @@ -29,7 +30,7 @@ public static class EncounterMovesetGenerator /// Moves that the resulting must be able to learn. /// Any specific version(s) to iterate for. If left blank, all will be checked. /// A consumable list of possible results. - public static IEnumerable GeneratePKMs(PKM pk, ITrainerInfo info, int[] moves = null, params GameVersion[] versions) + public static IEnumerable GeneratePKMs(PKM pk, ITrainerInfo info, int[]? moves = null, params GameVersion[] versions) { pk.TID = info.TID; var m = moves ?? pk.Moves; @@ -57,7 +58,7 @@ public static IEnumerable GeneratePKMs(PKM pk, ITrainerInfo info, int[] mov /// Trainer information of the receiver. /// Specific generation to iterate versions for. /// Moves that the resulting must be able to learn. - public static IEnumerable GeneratePKMs(PKM pk, ITrainerInfo info, int generation, int[] moves = null) + public static IEnumerable GeneratePKMs(PKM pk, ITrainerInfo info, int generation, int[]? moves = null) { var vers = GameUtil.GetVersionsInGeneration(generation, pk.Version); return GeneratePKMs(pk, info, moves, vers); @@ -70,7 +71,7 @@ public static IEnumerable GeneratePKMs(PKM pk, ITrainerInfo info, int gener /// 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, int generation, int[] moves = null) + public static IEnumerable GenerateEncounter(PKM pk, int generation, int[]? moves = null) { var vers = GameUtil.GetVersionsInGeneration(generation, pk.Version); return GenerateEncounters(pk, moves, vers); @@ -83,14 +84,14 @@ public static IEnumerable GenerateEncounter(PKM pk, int generati /// Moves that the resulting must be able to learn. /// Any specific version(s) to iterate for. If left blank, all will be checked. /// A consumable list of possible encounters. - public static IEnumerable GenerateEncounters(PKM pk, int[] moves = null, params GameVersion[] versions) + public static IEnumerable GenerateEncounters(PKM pk, int[]? moves = null, params GameVersion[] versions) { - var m = moves ?? pk.Moves; + moves ??= pk.Moves; if (versions.Length > 0) return GenerateEncounters(pk, moves, (IReadOnlyList)versions); var vers = GameUtil.GetVersionsWithinRange(pk, pk.Format); - return vers.SelectMany(ver => GenerateVersionEncounters(pk, m, ver)); + return vers.SelectMany(ver => GenerateVersionEncounters(pk, moves, ver)); } /// @@ -100,10 +101,10 @@ public static IEnumerable GenerateEncounters(PKM pk, int[] moves /// Moves that the resulting must be able to learn. /// Any specific version(s) to iterate for. If left blank, all will be checked. /// A consumable list of possible encounters. - public static IEnumerable GenerateEncounters(PKM pk, int[] moves, IReadOnlyList vers) + public static IEnumerable GenerateEncounters(PKM pk, int[]? moves, IReadOnlyList vers) { - var m = moves ?? pk.Moves; - return vers.SelectMany(ver => GenerateVersionEncounters(pk, m, ver)); + moves ??= pk.Moves; + return vers.SelectMany(ver => GenerateVersionEncounters(pk, moves, ver)); } /// diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterTradeGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterTradeGenerator.cs index 25d52f12a..3960a5239 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterTradeGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterTradeGenerator.cs @@ -59,7 +59,7 @@ private static IEnumerable GetPossibleVC(IReadOnlyList return table.Where(f => p.Any(r => r.Species == f.Species)); } - private static IEnumerable GetEncounterTradeTableVC(GameVersion gameSource) + private static IEnumerable? GetEncounterTradeTableVC(GameVersion gameSource) { if (GameVersion.RBY.Contains(gameSource)) return !ParseSettings.AllowGen1Tradeback ? Encounters1.TradeGift_RBY_NoTradeback : Encounters1.TradeGift_RBY_Tradeback; @@ -68,7 +68,7 @@ private static IEnumerable GetEncounterTradeTableVC(GameVersion return null; } - private static IEnumerable GetEncounterTradeTable(PKM pkm) + private static IEnumerable? GetEncounterTradeTable(PKM pkm) { return pkm.GenNumber switch { diff --git a/PKHeX.Core/Legality/Encounters/Generator/PeekEnumerator.cs b/PKHeX.Core/Legality/Encounters/Generator/PeekEnumerator.cs index eca3810ae..4085025c0 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/PeekEnumerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/PeekEnumerator.cs @@ -8,10 +8,10 @@ namespace PKHeX.Core /// Iterates a generic collection with the ability to peek into the collection to see if the next element exists. /// /// Generic Collection Element Type - public sealed class PeekEnumerator : IEnumerator + public sealed class PeekEnumerator : IEnumerator where T : class { private readonly IEnumerator Enumerator; - private T peek; + private T? peek; private bool didPeek; #region IEnumerator Implementation @@ -34,12 +34,13 @@ public bool MoveNext() public void Reset() { Enumerator.Reset(); + peek = default; didPeek = false; } - object IEnumerator.Current => Current; + object? IEnumerator.Current => Current; public void Dispose() => Enumerator.Dispose(); - public T Current => didPeek ? peek : Enumerator.Current; + public T Current => didPeek ? peek! : Enumerator.Current; #endregion @@ -68,10 +69,10 @@ public T Peek() if (!TryFetchPeek()) throw new InvalidOperationException("Enumeration already finished."); - return peek; + return peek!; } - public T PeekOrDefault() => !TryFetchPeek() ? default : peek; + public T? PeekOrDefault() => !TryFetchPeek() ? default : peek; /// /// Checks if a Next element exists diff --git a/PKHeX.Core/Legality/Encounters/Information/EncounterSuggestion.cs b/PKHeX.Core/Legality/Encounters/Information/EncounterSuggestion.cs index c59985644..a0373b1d3 100644 --- a/PKHeX.Core/Legality/Encounters/Information/EncounterSuggestion.cs +++ b/PKHeX.Core/Legality/Encounters/Information/EncounterSuggestion.cs @@ -7,11 +7,8 @@ namespace PKHeX.Core /// public static class EncounterSuggestion { - public static EncounterStatic GetSuggestedMetInfo(PKM pkm) + public static EncounterStatic? GetSuggestedMetInfo(PKM pkm) { - if (pkm == null) - return null; - int loc = GetSuggestedTransferLocation(pkm); if (pkm.WasEgg) diff --git a/PKHeX.Core/Legality/Encounters/Information/ValidEncounterMoves.cs b/PKHeX.Core/Legality/Encounters/Information/ValidEncounterMoves.cs index f80115be9..d35a0faef 100644 --- a/PKHeX.Core/Legality/Encounters/Information/ValidEncounterMoves.cs +++ b/PKHeX.Core/Legality/Encounters/Information/ValidEncounterMoves.cs @@ -9,9 +9,9 @@ namespace PKHeX.Core /// public sealed class ValidEncounterMoves { - public List[] LevelUpMoves { get; } = Empty; - public List[] TMHMMoves { get; } = Empty; - public List[] TutorMoves { get; } = Empty; + public IReadOnlyList[] LevelUpMoves { get; } = Empty; + public IReadOnlyList[] TMHMMoves { get; } = Empty; + public IReadOnlyList[] TutorMoves { get; } = Empty; public int[] Relearn = Array.Empty(); private const int EmptyCount = PKX.Generation + 1; // one for each generation index (and 0th) @@ -28,6 +28,10 @@ public ValidEncounterMoves(List[] levelup) { LevelUpMoves = levelup; } + public ValidEncounterMoves() + { + LevelUpMoves = Array.Empty(); + } } public sealed class LevelUpRestriction diff --git a/PKHeX.Core/Legality/Encounters/LegalInfo.cs b/PKHeX.Core/Legality/Encounters/LegalInfo.cs index e4ecc4519..98c03e3dd 100644 --- a/PKHeX.Core/Legality/Encounters/LegalInfo.cs +++ b/PKHeX.Core/Legality/Encounters/LegalInfo.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -22,20 +23,17 @@ public IEncounterable EncounterMatch get => _match; set { - if (_match != null && (value.LevelMin != _match.LevelMin || value.Species != _match.Species)) + if (_match != EncounterInvalid.Default && (value.LevelMin != _match.LevelMin || value.Species != _match.Species)) _evochains = null; // clear if evo chain has the potential to be different _match = value; Parse.Clear(); } } - private IEncounterable _match; - - /// Indicates whether or not the originated from . - public bool WasXD => pkm?.Version == 15 && EncounterMatch is IVersion v && v.Version == GameVersion.XD; + private IEncounterable _match = EncounterInvalid.Default; /// Base Relearn Moves for the . - public IReadOnlyList RelearnBase { get; internal set; } + public IReadOnlyList RelearnBase { get; internal set; } = Array.Empty(); /// Top level Legality Check result list for the . public readonly List Parse = new List(); @@ -43,12 +41,24 @@ public IEncounterable EncounterMatch public CheckResult[] Relearn { get; internal set; } = new CheckResult[4]; public CheckMoveResult[] Moves { get; internal set; } = new CheckMoveResult[4]; - public ValidEncounterMoves EncounterMoves { get; internal set; } + private static readonly ValidEncounterMoves NONE = new ValidEncounterMoves(); + public ValidEncounterMoves EncounterMoves { get; internal set; } = NONE; public IReadOnlyList[] EvoChainsAllGens => _evochains ??= EvolutionChain.GetEvolutionChainsAllGens(pkm, EncounterMatch); - private IReadOnlyList[] _evochains; + private IReadOnlyList[]? _evochains; /// related information that generated the / value(s). - public PIDIV PIDIV { get; internal set; } + public PIDIV PIDIV + { + get => _pidiv; + internal set + { + _pidiv = value; + PIDParsed = true; + } + } + + public bool PIDParsed { get; private set; } + private PIDIV _pidiv = PIDIV.None; /// Indicates whether or not the can originate from the . /// This boolean is true until all valid encounters are tested, after which it is false. @@ -58,12 +68,9 @@ public IEncounterable EncounterMatch /// This boolean is true until all valid entries are tested for all possible matches, after which it is false. public bool FrameMatches { get; internal set; } = true; - public readonly bool Korean; - public LegalInfo(PKM pk) { pkm = pk; - Korean = pk.Korean; // Store repeatedly accessed values Game = (GameVersion)pkm.Version; @@ -71,7 +78,7 @@ public LegalInfo(PKM pk) } /// List of all near-matches that were rejected for a given reason. - public List InvalidMatches; + public List? InvalidMatches; internal void Reject(CheckResult c) { diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs b/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs index 8b7ebfb18..ce0ad077f 100644 --- a/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs +++ b/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs @@ -43,15 +43,17 @@ private static CheckMoveResult[] ParseMovesForEncounters(PKM pkm, LegalInfo info var restrict = new LevelUpRestriction(pkm, info); info.EncounterMoves = new ValidEncounterMoves(pkm, restrict); - List defaultG1LevelMoves = null; - List defaultG2LevelMoves = null; + IReadOnlyList defaultG1LevelMoves = Array.Empty(); + IReadOnlyList defaultG2LevelMoves = Array.Empty(); var defaultTradeback = pkm.TradebackStatus; bool gb = false; if (info.EncounterMatch is IGeneration g && g.Generation <= 2) { gb = true; defaultG1LevelMoves = info.EncounterMoves.LevelUpMoves[1]; - defaultG2LevelMoves = pkm.InhabitedGeneration(2) ? info.EncounterMoves.LevelUpMoves[2] : null; + if (pkm.InhabitedGeneration(2)) + defaultG2LevelMoves = info.EncounterMoves.LevelUpMoves[2]; + // Generation 1 can have different minimum level in different encounter of the same species; update valid level moves UpdateGen1LevelUpMoves(pkm, info.EncounterMoves, restrict.MinimumLevelGen1, g.Generation, info); @@ -179,7 +181,7 @@ private static CheckMoveResult[] ParseMovesGenGB(PKM pkm, int[] Moves, LegalInfo return ParseMovesSpecialMoveset(pkm, Moves, info); var InitialMoves = Array.Empty(); var SpecialMoves = GetSpecialMoves(info.EncounterMatch); - var games = info.EncounterMatch is IGeneration g && g.Generation == 1 ? GBRestrictions.GetGen1Versions(info) : GBRestrictions.GetGen2Versions(info); + var games = info.EncounterMatch is IGeneration g && g.Generation == 1 ? GBRestrictions.GetGen1Versions(info) : GBRestrictions.GetGen2Versions(info, pkm.Korean); foreach (var ver in games) { var VerInitialMoves = MoveLevelUp.GetEncounterMoves(G1Encounter.Species, 0, G1Encounter.LevelMin, ver); @@ -212,7 +214,7 @@ private static CheckMoveResult[] ParseMovesSpecialMoveset(PKM pkm, int[] Moves, private static int[] GetSpecialMoves(IEncounterable EncounterMatch) { - if (EncounterMatch is IMoveset mg && mg.Moves != null) + if (EncounterMatch is IMoveset mg) return mg.Moves; return Array.Empty(); } @@ -258,7 +260,7 @@ private static CheckMoveResult[] ParseMoves(PKM pkm, MoveParseSource source, Leg return res; // Encapsulate arguments to simplify method calls - var moveInfo = new LearnInfo(pkm) { Source = source }; + var moveInfo = new LearnInfo(pkm, source); // Check moves going backwards, marking the move valid in the most current generation when it can be learned int[] generations = GetGenMovesCheckOrder(pkm); if (pkm.Format <= 2) @@ -549,7 +551,7 @@ private static IList GetIncompatibleRBYMoves(PKM pkm, int[] moves) } } - private static void ParseEvolutionsIncompatibleMoves(PKM pkm, IList res, int[] moves, List tmhm) + private static void ParseEvolutionsIncompatibleMoves(PKM pkm, IList res, IReadOnlyList moves, IReadOnlyList tmhm) { GBRestrictions.GetIncompatibleEvolutionMoves(pkm, moves, tmhm, out var prevSpeciesID, @@ -829,7 +831,7 @@ private static void UpdateGen1LevelUpMoves(PKM pkm, ValidEncounterMoves Encounte { if (generation >= 3) return; - var lvlG1 = info.EncounterMatch?.LevelMin + 1 ?? 6; + var lvlG1 = info.EncounterMatch.LevelMin + 1; if (lvlG1 == defaultLvlG1) return; EncounterMoves.LevelUpMoves[1] = Legal.GetValidMoves(pkm, info.EvoChainsAllGens[1], generation: 1, minLvLG1: lvlG1, LVL: true, Tutor: false, Machine: false, MoveReminder: false).ToList(); @@ -839,7 +841,7 @@ private static void UpdateGen2LevelUpMoves(PKM pkm, ValidEncounterMoves Encounte { if (generation >= 3) return; - var lvlG2 = info.EncounterMatch?.LevelMin + 1 ?? 6; + var lvlG2 = info.EncounterMatch.LevelMin + 1; if (lvlG2 == defaultLvlG2) return; EncounterMoves.LevelUpMoves[2] = Legal.GetValidMoves(pkm, info.EvoChainsAllGens[2], generation: 2, minLvLG2: defaultLvlG2, LVL: true, Tutor: false, Machine: false, MoveReminder: false).ToList(); diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet4.cs b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet4.cs index 1b8aebdd2..caf0c5106 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet4.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet4.cs @@ -15,7 +15,7 @@ private static EvolutionMethod GetMethod(byte[] data, int offset) int species = BitConverter.ToUInt16(data, offset + 4); if (method == 0) - return null; + throw new ArgumentException(nameof(data)); // To have the same structure as gen 6 // Gen 4 Method 6 is Gen 6 Method 7, G4 7 = G6 8, and so on diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet5.cs b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet5.cs index 693978198..70d71e94f 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet5.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionSets/EvolutionSet5.cs @@ -15,7 +15,7 @@ private static EvolutionMethod GetMethod(byte[] data, int offset) int species = BitConverter.ToUInt16(data, offset + 4); if (method == 0) - return null; + throw new ArgumentException(nameof(data)); var evo = new EvolutionMethod { diff --git a/PKHeX.Core/Legality/GBRestrictions.cs b/PKHeX.Core/Legality/GBRestrictions.cs index 84425a040..b486863f5 100644 --- a/PKHeX.Core/Legality/GBRestrictions.cs +++ b/PKHeX.Core/Legality/GBRestrictions.cs @@ -104,7 +104,7 @@ private static List[] GetExclusiveMovesG1(int species1, int species2, IEnum return new[] { moves1, moves2 }; } - internal static void GetIncompatibleEvolutionMoves(PKM pkm, int[] moves, List tmhm, out int previousspecies, out IList incompatible_previous, out IList incompatible_current) + internal static void GetIncompatibleEvolutionMoves(PKM pkm, IReadOnlyList moves, IReadOnlyList tmhm, out int previousspecies, out IList incompatible_previous, out IList incompatible_current) { switch (pkm.Species) { @@ -154,7 +154,7 @@ internal static void GetIncompatibleEvolutionMoves(PKM pkm, int[] moves, List moves, LegalInfo info, IReadOnlyList initialmoves) { if (!pk.Gen1_NotTradeback) // No Move Deleter in Gen 1 return 1; // Move Deleter exits, slots from 2 onwards can always be empty @@ -174,7 +174,7 @@ internal static int GetRequiredMoveCount(PKM pk, int[] moves, LegalInfo info, in return Math.Min(4, required); } - private static int GetRequiredMoveCount(PKM pk, int[] moves, List[] learn, int[] initialmoves) + private static int GetRequiredMoveCount(PKM pk, IReadOnlyList moves, IReadOnlyList[] learn, IReadOnlyList initialmoves) { if (SpecialMinMoveSlots.Contains(pk.Species)) return GetRequiredMoveCountSpecial(pk, moves, learn); @@ -185,7 +185,7 @@ private static int GetRequiredMoveCount(PKM pk, int[] moves, List[] learn, return required != 0 ? required : GetRequiredMoveCountDecrement(pk, moves, learn, initialmoves); } - private static int GetRequiredMoveSlotsRegular(PKM pk, int[] moves, List[] learn, int[] initialmoves) + private static int GetRequiredMoveSlotsRegular(PKM pk, IReadOnlyList moves, IReadOnlyList[] learn, IReadOnlyList initialmoves) { int species = pk.Species; int catch_rate = ((PK1)pk).Catch_Rate; @@ -209,7 +209,7 @@ private static int GetRequiredMoveSlotsRegular(PKM pk, int[] moves, List[] return IsMoveCountRequired3(species, pk.CurrentLevel, moves) ? 3 : 0; // no match } - private static bool IsMoveCountRequired3(int species, int level, int[] moves) + private static bool IsMoveCountRequired3(int species, int level, IReadOnlyList moves) { // Species that evolve and learn the 4th move as evolved species at a greather level than base species // The 4th move is included in the level up table set as a preevolution move, @@ -228,7 +228,7 @@ private static bool IsMoveCountRequired3(int species, int level, int[] moves) } } - private static int GetRequiredMoveCountDecrement(PKM pk, int[] moves, List[] learn, int[] initialmoves) + private static int GetRequiredMoveCountDecrement(PKM pk, IReadOnlyList moves, IReadOnlyList[] learn, IReadOnlyList initialmoves) { int usedslots = initialmoves.Union(learn[1]).Where(m => m != 0).Distinct().Count(); switch (pk.Species) @@ -272,7 +272,7 @@ private static int GetRequiredMoveCountDecrement(PKM pk, int[] moves, List[ return usedslots; } - private static int GetRequiredMoveCountSpecial(PKM pk, int[] moves, List[] learn) + private static int GetRequiredMoveCountSpecial(PKM pk, IReadOnlyList moves, IReadOnlyList[] learn) { // Species with few mandatory slots, species with stone evolutions that could evolve at lower level and do not learn any more moves // and Pikachu and Nidoran family, those only have mandatory the initial moves and a few have one level up moves, @@ -322,9 +322,9 @@ private static List GetRequiredMoveCountLevel(PKM pk) return MoveLevelUp.GetMovesLevelUp1(basespecies, 0, maxlevel, minlevel); } - internal static IEnumerable GetGen2Versions(LegalInfo Info) + internal static IEnumerable GetGen2Versions(LegalInfo Info, bool korean) { - if (ParseSettings.AllowGen2Crystal(Info.Korean) && Info.Game.Contains(GameVersion.C)) + if (ParseSettings.AllowGen2Crystal(korean) && Info.Game.Contains(GameVersion.C)) yield return GameVersion.C; yield return GameVersion.GS; } diff --git a/PKHeX.Core/Legality/Learnset/Learnset.cs b/PKHeX.Core/Legality/Learnset/Learnset.cs index c7953200a..7c4cfe555 100644 --- a/PKHeX.Core/Legality/Learnset/Learnset.cs +++ b/PKHeX.Core/Legality/Learnset/Learnset.cs @@ -6,22 +6,23 @@ namespace PKHeX.Core /// /// Level Up Learn Movepool Information /// - public abstract class Learnset + public sealed class Learnset { - /// - /// Amount of moves present. - /// - protected int Count; - /// /// Moves that can be learned. /// - protected int[] Moves; + private readonly int[] Moves; /// /// Levels at which a move at a given index can be learned. /// - protected int[] Levels; + private readonly int[] Levels; + + public Learnset(int[] moves, int[] levels) + { + Moves = moves; + Levels = levels; + } /// /// Returns the moves a Pokémon can learn between the specified level range. @@ -147,7 +148,7 @@ public int GetMinMoveLevel(int level) return Math.Max(end - 4, 1); } - private Dictionary Learn; + private Dictionary? Learn; private Dictionary GetDictionary() { @@ -165,7 +166,7 @@ public int GetMinMoveLevel(int level) /// Level the move is learned at. If the result is below 0, the move cannot be learned by leveling up. public int GetLevelLearnMove(int move) { - return (Learn ?? (Learn = GetDictionary())).TryGetValue(move, out var level) ? level : -1; + return (Learn ??= GetDictionary()).TryGetValue(move, out var level) ? level : -1; } /// Returns the level that a Pokémon can learn the specified move. diff --git a/PKHeX.Core/Legality/Learnset/Learnset1.cs b/PKHeX.Core/Legality/Learnset/Learnset1.cs deleted file mode 100644 index 3c07d8eac..000000000 --- a/PKHeX.Core/Legality/Learnset/Learnset1.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace PKHeX.Core -{ - /// - /// Level Up Learn Movepool Information (Generation 1/2) - /// - public sealed class Learnset1 : Learnset - { - private Learnset1(byte[] data, ref int offset) - { - int end = offset; // scan for count - while (data[end] != 0) - end += 2; - Count = (end - offset) / 2; - Moves = new int[Count]; - Levels = new int[Count]; - for (int i = 0; i < Moves.Length; i++) - { - Levels[i] = data[offset++]; - Moves[i] = data[offset++]; - } - ++offset; - } - - public static Learnset[] GetArray(byte[] input, int maxSpecies) - { - var data = new Learnset[maxSpecies + 1]; - - int offset = 0; - for (int s = 0; s < data.Length; s++) - data[s] = new Learnset1(input, ref offset); - - return data; - } - } -} \ No newline at end of file diff --git a/PKHeX.Core/Legality/Learnset/Learnset6.cs b/PKHeX.Core/Legality/Learnset/Learnset6.cs deleted file mode 100644 index 55584bb02..000000000 --- a/PKHeX.Core/Legality/Learnset/Learnset6.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.IO; - -namespace PKHeX.Core -{ - /// - /// Level Up Learn Movepool Information - /// - public sealed class Learnset6 : Learnset - { - private Learnset6(byte[] data) - { - if (data.Length < 4 || data.Length % 4 != 0) - { Count = 0; Levels = Moves = Array.Empty(); return; } - Count = (data.Length / 4) - 1; - Moves = new int[Count]; - Levels = new int[Count]; - using var ms = new MemoryStream(data); - using var br = new BinaryReader(ms); - for (int i = 0; i < Count; i++) - { - Moves[i] = br.ReadInt16(); - Levels[i] = br.ReadInt16(); - } - } - - public static Learnset[] GetArray(byte[][] entries) - { - Learnset[] data = new Learnset[entries.Length]; - for (int i = 0; i < data.Length; i++) - data[i] = new Learnset6(entries[i]); - return data; - } - } -} \ No newline at end of file diff --git a/PKHeX.Core/Legality/Learnset/LearnsetReader.cs b/PKHeX.Core/Legality/Learnset/LearnsetReader.cs new file mode 100644 index 000000000..5ba6ca9b9 --- /dev/null +++ b/PKHeX.Core/Legality/Learnset/LearnsetReader.cs @@ -0,0 +1,77 @@ +using System; + +namespace PKHeX.Core +{ + /// + /// Unpacks data from legality binary inputs. + /// + public static class LearnsetReader + { + private static readonly Learnset EMPTY = new Learnset(Array.Empty(), Array.Empty()); + + public static Learnset[] GetArray(byte[] input, int maxSpecies) + { + var data = new Learnset[maxSpecies + 1]; + + int offset = 0; + for (int s = 0; s < data.Length; s++) + data[s] = ReadLearnset8(input, ref offset); + + return data; + } + + public static Learnset[] GetArray(byte[][] entries) + { + Learnset[] data = new Learnset[entries.Length]; + for (int i = 0; i < data.Length; i++) + data[i] = ReadLearnset16(entries[i]); + return data; + } + + /// + /// Reads a Level up move pool definition from a contiguous chunk of GB era ROM data. + /// + /// Moves and Levels are 8-bit + private static Learnset ReadLearnset8(byte[] data, ref int offset) + { + int end = offset; // scan for count + if (data[end] == 0) + { + ++offset; + return EMPTY; + } + do { end += 2; } while (data[end] != 0); + + var Count = (end - offset) / 2; + var Moves = new int[Count]; + var Levels = new int[Count]; + for (int i = 0; i < Moves.Length; i++) + { + Levels[i] = data[offset++]; + Moves[i] = data[offset++]; + } + ++offset; + return new Learnset(Moves, Levels); + } + + /// + /// Reads a Level up move pool definition from a single move pool definition. + /// + /// Count of moves, followed by Moves and Levels which are 16-bit + private static Learnset ReadLearnset16(byte[] data) + { + if (data.Length < 4 || data.Length % 4 != 0) + return EMPTY; + var Count = (data.Length / 4) - 1; + var Moves = new int[Count]; + var Levels = new int[Count]; + for (int i = 0; i < Count; i++) + { + int ofs = i * 4; + Moves[i] = BitConverter.ToInt16(data, ofs); + Levels[i] = BitConverter.ToInt16(data, ofs + 2); + } + return new Learnset(Moves, Levels); + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Legality/Moves/LearnInfo.cs b/PKHeX.Core/Legality/Moves/LearnInfo.cs index 3103a85d7..ff6026967 100644 --- a/PKHeX.Core/Legality/Moves/LearnInfo.cs +++ b/PKHeX.Core/Legality/Moves/LearnInfo.cs @@ -11,13 +11,14 @@ internal class LearnInfo public List LevelUpEggMoves { get; } = new List(); public List EventEggMoves { get; } = new List(); public List IncenseMoves { get; } = new List(); - public MoveParseSource Source { get; set; } + public readonly MoveParseSource Source; public readonly bool IsGen2Pkm; - public LearnInfo(PKM pkm) + public LearnInfo(PKM pkm, MoveParseSource source) { IsGen2Pkm = pkm.Format == 2 || pkm.VC2; + Source = source; } } diff --git a/PKHeX.Core/Legality/Moves/MoveEgg.cs b/PKHeX.Core/Legality/Moves/MoveEgg.cs index 0be1a5b0b..5dba5ca05 100644 --- a/PKHeX.Core/Legality/Moves/MoveEgg.cs +++ b/PKHeX.Core/Legality/Moves/MoveEgg.cs @@ -30,49 +30,42 @@ private static int[] GetEggMoves(int gen, int species, int formnum, GameVersion case 3: return EggMovesRS[species].Moves; case 4: - switch (version) + return version switch { - case GameVersion.HG: - case GameVersion.SS: - return EggMovesHGSS[species].Moves; - default: - return EggMovesDPPt[species].Moves; - } + GameVersion.HG => EggMovesHGSS[species].Moves, + GameVersion.SS => EggMovesHGSS[species].Moves, + _ => EggMovesDPPt[species].Moves + }; case 5: return EggMovesBW[species].Moves; case 6: // entries per species - switch (version) + return version switch { - case GameVersion.OR: - case GameVersion.AS: - return EggMovesAO[species].Moves; - default: - return EggMovesXY[species].Moves; - } + GameVersion.OR => EggMovesAO[species].Moves, + GameVersion.AS => EggMovesAO[species].Moves, + _ => EggMovesXY[species].Moves + }; case 7: // entries per form if required - switch (version) + return version switch { - case GameVersion.US: - case GameVersion.UM: - return GetFormEggMoves(species, formnum, EggMovesUSUM); - default: - return GetFormEggMoves(species, formnum, EggMovesSM); - } + GameVersion.US => GetFormEggMoves(species, formnum, EggMovesUSUM), + GameVersion.UM => GetFormEggMoves(species, formnum, EggMovesUSUM), + _ => GetFormEggMoves(species, formnum, EggMovesSM) + }; case 8: - switch (version) + return version switch { - default: - return GetFormEggMoves(species, formnum, EggMovesSWSH); - } + _ => GetFormEggMoves(species, formnum, EggMovesSWSH) + }; default: return Array.Empty(); } } - private static int[] GetFormEggMoves(int species, int formnum, EggMoves[] table) + private static int[] GetFormEggMoves(int species, int formnum, IReadOnlyList table) { var entry = table[species]; if (formnum > 0 && AlolanOriginForms.Contains(species)) diff --git a/PKHeX.Core/Legality/Moves/MoveLevelUp.cs b/PKHeX.Core/Legality/Moves/MoveLevelUp.cs index a559a668b..9b77e9b1f 100644 --- a/PKHeX.Core/Legality/Moves/MoveLevelUp.cs +++ b/PKHeX.Core/Legality/Moves/MoveLevelUp.cs @@ -239,7 +239,7 @@ private static GameVersion GetDeoxysGameVersion3(int form) }; } - private static Learnset GetDeoxysLearn3(int form, GameVersion ver = Any) + private static Learnset? GetDeoxysLearn3(int form, GameVersion ver = Any) { const int index = (int)Species.Deoxys; if (ver == Any) @@ -266,7 +266,7 @@ public static IEnumerable GetMovesLevelUp(PKM pkm, int species, int minlvlG version = (GameVersion)pkm.Version; return Generation switch { - 1 => (IEnumerable) GetMovesLevelUp1(species, form, lvl, minlvlG1, version), + 1 => GetMovesLevelUp1(species, form, lvl, minlvlG1, version), 2 => GetMovesLevelUp2(species, form, lvl, minlvlG2, pkm.Korean, pkm.LearnMovesNew2Disallowed(), version), 3 => GetMovesLevelUp3(species, form, lvl, version), 4 => GetMovesLevelUp4(species, form, lvl, version), @@ -274,7 +274,7 @@ public static IEnumerable GetMovesLevelUp(PKM pkm, int species, int minlvlG 6 => GetMovesLevelUp6(species, form, lvl, version), 7 => GetMovesLevelUp7(species, form, lvl, MoveReminder, version), 8 => GetMovesLevelUp8(species, form, lvl, MoveReminder, version), - _ => Array.Empty() + _ => (IEnumerable)Array.Empty() }; } diff --git a/PKHeX.Core/Legality/RNG/Frame/FrameFinder.cs b/PKHeX.Core/Legality/RNG/Frame/FrameFinder.cs index d828505bb..bf63dd2d1 100644 --- a/PKHeX.Core/Legality/RNG/Frame/FrameFinder.cs +++ b/PKHeX.Core/Legality/RNG/Frame/FrameFinder.cs @@ -13,13 +13,10 @@ public static class FrameFinder /// to yield possible encounter details for further filtering public static IEnumerable GetFrames(PIDIV pidiv, PKM pk) { - if (pidiv.RNG == null) - return Enumerable.Empty(); - FrameGenerator info = new FrameGenerator(pidiv, pk); - if (info.FrameType == FrameType.None) + if (pk.Version == (int)GameVersion.CXD) return Enumerable.Empty(); - info.Nature = pk.EncryptionConstant % 25; + var info = new FrameGenerator(pk) {Nature = pk.EncryptionConstant % 25}; // gather possible nature determination seeds until a same-nature PID breaks the unrolling var seeds = pk.Species == 201 && pk.FRLG // reversed await case @@ -280,12 +277,12 @@ private static IEnumerable FilterNatureSync(IEnumerable seeds, if (!sync && !reg) // doesn't generate nature frame continue; - uint prev = pidiv.RNG.Prev(s); + uint prev = RNG.LCRNG.Prev(s); if (info.AllowLeads && reg) // check for failed sync { var failsync = (info.DPPt ? prev >> 31 : (prev >> 16) & 1) != 1; if (failsync) - yield return info.GetFrame(pidiv.RNG.Prev(prev), LeadRequired.SynchronizeFail); + yield return info.GetFrame(RNG.LCRNG.Prev(prev), LeadRequired.SynchronizeFail); } if (sync) yield return info.GetFrame(prev, LeadRequired.Synchronize); @@ -298,7 +295,7 @@ private static IEnumerable FilterNatureSync(IEnumerable seeds, else { if (info.Safari3) - prev = pidiv.RNG.Prev(prev); // wasted RNG call + prev = RNG.LCRNG.Prev(prev); // wasted RNG call yield return info.GetFrame(prev, LeadRequired.None); } } @@ -382,7 +379,7 @@ private static IEnumerable FilterCuteCharm(IEnumerable seeds, P if (nature != info.Nature) continue; - var prev = pidiv.RNG.Prev(s); + var prev = RNG.LCRNG.Prev(s); var proc = prev >> 16; bool charmProc = (info.DPPt ? proc / 0x5556 : proc % 3) != 0; // 2/3 odds if (!charmProc) diff --git a/PKHeX.Core/Legality/RNG/Frame/FrameGenerator.cs b/PKHeX.Core/Legality/RNG/Frame/FrameGenerator.cs index dbc81fe53..4817dd1a7 100644 --- a/PKHeX.Core/Legality/RNG/Frame/FrameGenerator.cs +++ b/PKHeX.Core/Legality/RNG/Frame/FrameGenerator.cs @@ -1,4 +1,6 @@ -namespace PKHeX.Core +using System; + +namespace PKHeX.Core { public sealed class FrameGenerator { @@ -23,13 +25,13 @@ public Frame GetFrame(uint seed, LeadRequired lead, uint esv, uint lvl, uint ori }; /// - /// Gets the Search Criteria parameters necessary for generating and objects. + /// Gets the Search Criteria parameters necessary for generating and objects for Gen3/4 mainline games. /// - /// Info used to determine the . /// object containing various accessible information required for the encounter. /// Object containing search criteria to be passed by reference to search/filter methods. - public FrameGenerator(PIDIV pidiv, PKM pk) + public FrameGenerator(PKM pk) { + RNG = RNG.LCRNG; var ver = (GameVersion)pk.Version; switch (ver) { @@ -41,7 +43,6 @@ public FrameGenerator(PIDIV pidiv, PKM pk) case GameVersion.E: DPPt = false; FrameType = FrameType.MethodH; - RNG = pidiv.RNG; Safari3 = pk.Ball == 5 && !pk.FRLG; if (ver != GameVersion.E) @@ -68,7 +69,7 @@ public FrameGenerator(PIDIV pidiv, PKM pk) DPPt = true; AllowLeads = true; FrameType = FrameType.MethodJ; - RNG = pidiv.RNG; + RNG = RNG.LCRNG; return; // Method K @@ -77,8 +78,10 @@ public FrameGenerator(PIDIV pidiv, PKM pk) DPPt = false; AllowLeads = true; FrameType = FrameType.MethodK; - RNG = pidiv.RNG; + RNG = RNG.LCRNG; return; + default: + throw new ArgumentException(nameof(ver)); } } diff --git a/PKHeX.Core/Legality/RNG/Frame/SeedInfo.cs b/PKHeX.Core/Legality/RNG/Frame/SeedInfo.cs index 4e00db210..0878acb2f 100644 --- a/PKHeX.Core/Legality/RNG/Frame/SeedInfo.cs +++ b/PKHeX.Core/Legality/RNG/Frame/SeedInfo.cs @@ -21,7 +21,7 @@ public static IEnumerable GetSeedsUntilNature(PIDIV pidiv, FrameGenera yield return new SeedInfo { Seed = seed }; var s1 = seed; - var s2 = pidiv.RNG.Prev(s1); + var s2 = RNG.LCRNG.Prev(s1); while (true) { var a = s2 >> 16; @@ -39,8 +39,8 @@ public static IEnumerable GetSeedsUntilNature(PIDIV pidiv, FrameGenera break; } - s1 = pidiv.RNG.Prev(s2); - s2 = pidiv.RNG.Prev(s1); + s1 = RNG.LCRNG.Prev(s2); + s2 = RNG.LCRNG.Prev(s1); yield return new SeedInfo { Seed = s1, Charm3 = charm3 }; } @@ -59,7 +59,7 @@ public static IEnumerable GetSeedsUntilUnownForm(PIDIV pidiv, FrameGen yield return new SeedInfo { Seed = seed }; var s1 = seed; - var s2 = pidiv.RNG.Prev(s1); + var s2 = RNG.LCRNG.Prev(s1); while (true) { var a = s2 >> 16; @@ -77,8 +77,8 @@ public static IEnumerable GetSeedsUntilUnownForm(PIDIV pidiv, FrameGen } } - s1 = pidiv.RNG.Prev(s2); - s2 = pidiv.RNG.Prev(s1); + s1 = RNG.LCRNG.Prev(s2); + s2 = RNG.LCRNG.Prev(s1); yield return new SeedInfo { Seed = s1 }; } diff --git a/PKHeX.Core/Legality/RNG/Locks/TeamLock.cs b/PKHeX.Core/Legality/RNG/Locks/TeamLock.cs index 4484eb645..b031ad631 100644 --- a/PKHeX.Core/Legality/RNG/Locks/TeamLock.cs +++ b/PKHeX.Core/Legality/RNG/Locks/TeamLock.cs @@ -2,13 +2,24 @@ namespace PKHeX.Core { public sealed class TeamLock { - public int Species; - public string Comment; - public NPCLock[] Locks; + public readonly int Species; + public readonly string Comment; + public readonly NPCLock[] Locks; - internal TeamLock Clone() + internal TeamLock Clone() => new TeamLock(Species, Comment, (NPCLock[])Locks.Clone()); + + public TeamLock(int species, NPCLock[] locks) { - return new TeamLock { Comment = Comment, Locks = (NPCLock[])Locks.Clone() }; + Species = species; + Locks = locks; + Comment = string.Empty; + } + + public TeamLock(int species, string comment, NPCLock[] locks) + { + Species = species; + Locks = locks; + Comment = comment; } } } \ No newline at end of file diff --git a/PKHeX.Core/Legality/RNG/Locks/TeamLockResult.cs b/PKHeX.Core/Legality/RNG/Locks/TeamLockResult.cs index 0b8fc5cba..06c9165f0 100644 --- a/PKHeX.Core/Legality/RNG/Locks/TeamLockResult.cs +++ b/PKHeX.Core/Legality/RNG/Locks/TeamLockResult.cs @@ -76,7 +76,7 @@ internal TeamLockResult(TeamLock teamSpec, uint originSeed, int tsv) /// Frame at which the search starts/continues at. /// Prior data. If this is the last lock in the CPU Team, this is null. /// True if the are valid. - private bool FindLockSeed(int frame = 0, NPCLock prior = null) + private bool FindLockSeed(int frame = 0, NPCLock? prior = null) { if (Locks.Count == 0) // full team reverse-generated return VerifyNPC(frame); @@ -102,7 +102,7 @@ private bool FindLockSeed(int frame = 0, NPCLock prior = null) /// Current lock criteria to satisfy. Used to find valid results to yield. /// Prior lock criteria. Used for determining when the traversal stops. /// List of possible locks for the provided input. - private IEnumerable GetPossibleLocks(int ctr, NPCLock current, NPCLock prior) + private IEnumerable GetPossibleLocks(int ctr, NPCLock current, NPCLock? prior) { if (prior?.Shadow != false) return GetSingleLock(ctr, current); diff --git a/PKHeX.Core/Legality/RNG/MethodFinder.cs b/PKHeX.Core/Legality/RNG/MethodFinder.cs index bd06b9e45..aaeb3e049 100644 --- a/PKHeX.Core/Legality/RNG/MethodFinder.cs +++ b/PKHeX.Core/Legality/RNG/MethodFinder.cs @@ -10,7 +10,6 @@ namespace PKHeX.Core /// public static class MethodFinder { - private static readonly PIDIV NonMatch = new PIDIV {NoSeed = true, Type = PIDType.None}; /// /// Analyzes a to find a matching PIDIV method. @@ -99,7 +98,7 @@ private static bool GetLCRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidi var ivD = D >> 16 & 0x7FFF; if (iv2 == ivD) // ABCD { - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_1}; return true; } @@ -107,7 +106,7 @@ private static bool GetLCRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidi var ivE = E >> 16 & 0x7FFF; if (iv2 == ivE) // ABCE { - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_4}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_4}; return true; } } @@ -122,7 +121,7 @@ private static bool GetLCRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidi var ivE = E >> 16 & 0x7FFF; if (iv2 == ivE) // ABDE { - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_2}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_2}; return true; } } @@ -142,7 +141,7 @@ private static bool GetLCRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidi var ivE = E >> 16 & 0x7FFF; if (iv2 != ivE) continue; - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_3}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_3}; return true; } return GetNonMatch(out pidiv); @@ -168,7 +167,7 @@ private static bool GetLCRNGUnownMatch(uint top, uint bot, uint[] IVs, out PIDIV var ivD = D >> 16 & 0x7FFF; if (iv2 == ivD) // BACD { - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1_Unown}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_1_Unown}; return true; } @@ -176,7 +175,7 @@ private static bool GetLCRNGUnownMatch(uint top, uint bot, uint[] IVs, out PIDIV var ivE = E >> 16 & 0x7FFF; if (iv2 == ivE) // BACE { - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_4_Unown}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_4_Unown}; return true; } } @@ -191,7 +190,7 @@ private static bool GetLCRNGUnownMatch(uint top, uint bot, uint[] IVs, out PIDIV var ivE = E >> 16 & 0x7FFF; if (iv2 == ivE) // BADE { - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_2_Unown}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_2_Unown}; return true; } } @@ -211,7 +210,7 @@ private static bool GetLCRNGUnownMatch(uint top, uint bot, uint[] IVs, out PIDIV var ivE = E >> 16 & 0x7FFF; if (iv2 != ivE) continue; - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_3_Unown}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_3_Unown}; return true; } return GetNonMatch(out pidiv); @@ -230,7 +229,7 @@ private static bool GetLCRNGRoamerMatch(uint top, uint bot, uint[] IVs, out PIDI if (iv1 != ivC) continue; - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1_Roamer}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.Method_1_Roamer}; return true; } return GetNonMatch(out pidiv); @@ -272,7 +271,7 @@ private static bool GetXDRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidi } pidiv = new PIDIVTSV { - OriginSeed = RNG.XDRNG.Prev(A), RNG = RNG.XDRNG, Type = PIDType.CXDAnti, + OriginSeed = RNG.XDRNG.Prev(A), RNG = RNGType.XDRNG, Type = PIDType.CXDAnti, TSV1 = tsv1, TSV2 = tsv2, }; return true; @@ -280,7 +279,7 @@ private static bool GetXDRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidi continue; } - pidiv = new PIDIV {OriginSeed = RNG.XDRNG.Prev(A), RNG = RNG.XDRNG, Type = PIDType.CXD}; + pidiv = new PIDIV {OriginSeed = RNG.XDRNG.Prev(A), RNG = RNGType.XDRNG, Type = PIDType.CXD}; return true; } return GetNonMatch(out pidiv); @@ -315,7 +314,7 @@ private static bool GetChannelMatch(uint top, uint bot, uint[] IVs, out PIDIV pi if (seed >> 16 != pk.SID) continue; - pidiv = new PIDIV {OriginSeed = RNG.XDRNG.Prev(seed), RNG = RNG.XDRNG, Type = PIDType.Channel}; + pidiv = new PIDIV {OriginSeed = RNG.XDRNG.Prev(seed), RNG = RNGType.XDRNG, Type = PIDType.Channel}; return true; } return GetNonMatch(out pidiv); @@ -333,7 +332,7 @@ private static bool GetMG4Match(uint pid, uint[] IVs, out PIDIV pidiv) if (!IVsMatch(C >> 16, D >> 16, IVs)) continue; - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.G4MGAntiShiny}; + pidiv = new PIDIV {OriginSeed = seed, RNG = RNGType.LCRNG, Type = PIDType.G4MGAntiShiny}; return true; } return GetNonMatch(out pidiv); @@ -375,7 +374,7 @@ private static bool GetCuteCharmMatch(PKM pk, uint pid, out PIDIV pidiv) if (nature + rate != pid) break; - pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm}; + pidiv = new PIDIV {NoSeed = true, RNG = RNGType.LCRNG, Type = PIDType.CuteCharm}; return true; case 1: // female if (pid >= 25) @@ -383,7 +382,7 @@ private static bool GetCuteCharmMatch(PKM pk, uint pid, out PIDIV pidiv) if (254 <= getRatio()) // no modification for PID break; - pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm}; + pidiv = new PIDIV {NoSeed = true, RNG = RNGType.LCRNG, Type = PIDType.CuteCharm}; return true; } return GetNonMatch(out pidiv); @@ -426,7 +425,7 @@ private static bool GetChainShinyMatch(PKM pk, uint pid, uint[] IVs, out PIDIV p continue; s = RNG.LCRNG.Reverse(lower, 2); // unroll one final time to get the origin seed - pidiv = new PIDIV {OriginSeed = s, RNG = RNG.LCRNG, Type = PIDType.ChainShiny}; + pidiv = new PIDIV {OriginSeed = s, RNG = RNGType.LCRNG, Type = PIDType.ChainShiny}; return true; } return GetNonMatch(out pidiv); @@ -478,11 +477,11 @@ private static bool GetBACDMatch(PKM pk, uint pid, uint[] IVs, out PIDIV pidiv) if ((sn & 0xFFFF0000) != 0) continue; // shift from unrestricted enum val to restricted enum val - pidiv = new PIDIV {OriginSeed = sn, RNG = RNG.LCRNG, Type = --type }; + pidiv = new PIDIV {OriginSeed = sn, RNG = RNGType.LCRNG, Type = --type }; return true; } // no restricted seed found, thus unrestricted - pidiv = new PIDIV {OriginSeed = s, RNG = RNG.LCRNG, Type = type}; + pidiv = new PIDIV {OriginSeed = s, RNG = RNGType.LCRNG, Type = type}; return true; } return GetNonMatch(out pidiv); @@ -506,7 +505,7 @@ private static bool GetPokewalkerMatch(PKM pk, uint oldpid, out PIDIV pidiv) if (!(gender == 0 && IsAzurillEdgeCaseM(pk, nature, oldpid))) return GetNonMatch(out pidiv); } - pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.Pokewalker}; + pidiv = new PIDIV {NoSeed = true, RNG = RNGType.LCRNG, Type = PIDType.Pokewalker}; return true; } @@ -541,7 +540,7 @@ private static bool GetColoStarterMatch(PKM pk, uint top, uint bot, uint[] IVs, if (!LockFinder.IsColoStarterValid(pk.Species, ref origin, pk.TID, pk.SID, pk.PID, iv1, iv2)) continue; - pidiv = new PIDIV { OriginSeed = origin, RNG = RNG.XDRNG, Type = PIDType.CXD_ColoStarter }; + pidiv = new PIDIV { OriginSeed = origin, RNG = RNGType.XDRNG, Type = PIDType.CXD_ColoStarter }; return true; } return GetNonMatch(out pidiv); @@ -555,7 +554,7 @@ private static bool GetColoStarterMatch(PKM pk, uint top, uint bot, uint[] IVs, [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool GetNonMatch(out PIDIV pidiv) { - pidiv = NonMatch; + pidiv = PIDIV.None; return false; } @@ -622,7 +621,7 @@ private static bool IsBACD_U_AX(uint idxor, uint pid, uint low, uint A, ref PIDT private static PIDIV AnalyzeGB(PKM _) { // not implemented; correlation between IVs and RNG hasn't been converted to code. - return NonMatch; + return PIDIV.None; } private static IEnumerable GetSeedsFromPID(RNG method, uint a, uint b) @@ -760,7 +759,7 @@ public static IEnumerable GetColoEReaderMatches(uint PID) var C = RNG.XDRNG.Advance(A, 7); - yield return new PIDIV { OriginSeed = RNG.XDRNG.Prev(C), RNG = RNG.XDRNG, Type = PIDType.CXD }; + yield return new PIDIV { OriginSeed = RNG.XDRNG.Prev(C), RNG = RNGType.XDRNG, Type = PIDType.CXD }; } } @@ -778,7 +777,7 @@ public static IEnumerable GetPokeSpotSeeds(PKM pkm, int slot) // check for valid encounter slot info if (!IsPokeSpotActivation(slot, seed, out uint s)) continue; - yield return new PIDIV {OriginSeed = s, RNG = RNG.XDRNG, Type = PIDType.PokeSpot}; + yield return new PIDIV {OriginSeed = s, RNG = RNGType.XDRNG, Type = PIDType.PokeSpot}; } } diff --git a/PKHeX.Core/Legality/RNG/PIDIV.cs b/PKHeX.Core/Legality/RNG/PIDIV.cs index d773e0fde..2c74b7dd7 100644 --- a/PKHeX.Core/Legality/RNG/PIDIV.cs +++ b/PKHeX.Core/Legality/RNG/PIDIV.cs @@ -2,8 +2,10 @@ { public class PIDIV { + public static readonly PIDIV None = new PIDIV { NoSeed = true, Type = PIDType.None }; + /// The RNG that generated the PKM from the - public RNG RNG; + public RNGType RNG; /// The RNG seed which immediately generates the PIDIV (starting with PID or IVs, whichever comes first). public uint OriginSeed; diff --git a/PKHeX.Core/Legality/RNG/RNG.cs b/PKHeX.Core/Legality/RNG/RNG.cs index 8c80e5ad7..28a68b6f4 100644 --- a/PKHeX.Core/Legality/RNG/RNG.cs +++ b/PKHeX.Core/Legality/RNG/RNG.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; namespace PKHeX.Core @@ -219,4 +220,26 @@ private IEnumerable GetPossibleSeedsEuclid(uint first, uint second, int bi } } } + + public enum RNGType + { + None, + LCRNG, + XDRNG, + ARNG, + } + + public static class RNGTypeUtil + { + public static RNG GetRNG(this RNGType type) + { + return type switch + { + RNGType.LCRNG => RNG.LCRNG, + RNGType.XDRNG => RNG.XDRNG, + RNGType.ARNG => RNG.ARNG, + _ => throw new ArgumentException(nameof(type)) + }; + } + } } diff --git a/PKHeX.Core/Legality/Structures/EggMoves.cs b/PKHeX.Core/Legality/Structures/EggMoves.cs index 68bc0f18f..102349125 100644 --- a/PKHeX.Core/Legality/Structures/EggMoves.cs +++ b/PKHeX.Core/Legality/Structures/EggMoves.cs @@ -1,25 +1,18 @@ using System; -using System.IO; using System.Linq; namespace PKHeX.Core { public abstract class EggMoves { - protected int Count; - public int[] Moves; - public int FormTableIndex; - + public readonly int[] Moves; + protected EggMoves(int[] moves) => Moves = moves; public bool GetHasEggMove(int move) => Moves.Contains(move); } public sealed class EggMoves2 : EggMoves { - private EggMoves2(byte[] data) - { - Count = data.Length; - Moves = data.Select(i => (int) i).ToArray(); - } + private EggMoves2(byte[] data) : base(data.Select(i => (int)i).ToArray()) { } public static EggMoves[] GetArray(byte[] data, int count) { @@ -42,46 +35,56 @@ public static EggMoves[] GetArray(byte[] data, int count) public sealed class EggMoves6 : EggMoves { - private EggMoves6(byte[] data) + private static readonly EggMoves6 None = new EggMoves6(Array.Empty()); + + private EggMoves6(int[] moves) : base(moves) { } + + private static EggMoves6 Get(byte[] data) { if (data.Length < 2 || data.Length % 2 != 0) - { Count = 0; Moves = Array.Empty(); return; } + return None; - using BinaryReader br = new BinaryReader(new MemoryStream(data)); - Moves = new int[Count = br.ReadUInt16()]; - for (int i = 0; i < Count; i++) - Moves[i] = br.ReadUInt16(); + int count = BitConverter.ToInt16(data, 0); + var moves = new int[count]; + for (int i = 0; i < moves.Length; i++) + moves[i] = BitConverter.ToInt16(data, 2 + (i * 2)); + return new EggMoves6(moves); } - public static EggMoves[] GetArray(byte[][] entries) + public static EggMoves6[] GetArray(byte[][] entries) { - EggMoves[] data = new EggMoves[entries.Length]; + EggMoves6[] data = new EggMoves6[entries.Length]; for (int i = 0; i < data.Length; i++) - data[i] = new EggMoves6(entries[i]); + data[i] = Get(entries[i]); return data; } } public sealed class EggMoves7 : EggMoves { - private EggMoves7(byte[] data) + private static readonly EggMoves7 None = new EggMoves7(Array.Empty()); + public readonly int FormTableIndex; + + private EggMoves7(int[] moves, int formIndex = 0) : base(moves) => FormTableIndex = formIndex; + + private static EggMoves7 Get(byte[] data) { if (data.Length < 2 || data.Length % 2 != 0) - { Count = 0; Moves = Array.Empty(); return; } + return None; - using var br = new BinaryReader(new MemoryStream(data)); - FormTableIndex = br.ReadUInt16(); - Count = br.ReadUInt16(); - Moves = new int[Count]; - for (int i = 0; i < Count; i++) - Moves[i] = br.ReadUInt16(); + int formIndex = BitConverter.ToInt16(data, 0); + int count = BitConverter.ToInt16(data, 2); + var moves = new int[count]; + for (int i = 0; i < moves.Length; i++) + moves[i] = BitConverter.ToInt16(data, 4 + (i * 2)); + return new EggMoves7(moves, formIndex); } - public static EggMoves[] GetArray(byte[][] entries) + public static EggMoves7[] GetArray(byte[][] entries) { - EggMoves[] data = new EggMoves[entries.Length]; + EggMoves7[] data = new EggMoves7[entries.Length]; for (int i = 0; i < data.Length; i++) - data[i] = new EggMoves7(entries[i]); + data[i] = Get(entries[i]); return data; } } diff --git a/PKHeX.Core/Legality/Structures/ILocation.cs b/PKHeX.Core/Legality/Structures/ILocation.cs index 92b3c6211..b48c07372 100644 --- a/PKHeX.Core/Legality/Structures/ILocation.cs +++ b/PKHeX.Core/Legality/Structures/ILocation.cs @@ -10,14 +10,12 @@ public static partial class Extensions { public static int GetLocation(this ILocation encounter) { - if (encounter == null) - return -1; return encounter.Location != 0 ? encounter.Location : encounter.EggLocation; } - internal static string GetEncounterLocation(this ILocation Encounter, int gen, int version = -1) + internal static string? GetEncounterLocation(this ILocation Encounter, int gen, int version = -1) { int loc = Encounter.GetLocation(); if (loc < 0) diff --git a/PKHeX.Core/Legality/Verifiers/CXDVerifier.cs b/PKHeX.Core/Legality/Verifiers/CXDVerifier.cs index b694fbe34..405a08b1e 100644 --- a/PKHeX.Core/Legality/Verifiers/CXDVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/CXDVerifier.cs @@ -1,4 +1,5 @@ -using static PKHeX.Core.LegalityCheckStrings; +using System; +using static PKHeX.Core.LegalityCheckStrings; namespace PKHeX.Core { diff --git a/PKHeX.Core/Legality/Verifiers/FormVerifier.cs b/PKHeX.Core/Legality/Verifiers/FormVerifier.cs index 79947744f..abfa23cba 100644 --- a/PKHeX.Core/Legality/Verifiers/FormVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/FormVerifier.cs @@ -109,7 +109,7 @@ bool IsValidPikachuCap() case (int)Species.Spewpa: if (pkm.AltForm > 17) // Fancy & Pokéball return GetInvalid(LFormVivillonEventPre); - if (!Legal.CheckVivillonPattern(pkm.AltForm, pkm.Country, pkm.Region)) + if (!Legal.CheckVivillonPattern(pkm.AltForm, (byte)pkm.Country, (byte)pkm.Region)) data.AddLine(Get(LFormVivillonInvalid, Severity.Fishy)); break; case (int)Species.Vivillon: @@ -119,7 +119,7 @@ bool IsValidPikachuCap() return GetInvalid(LFormVivillonInvalid); return GetValid(LFormVivillon); } - if (!Legal.CheckVivillonPattern(pkm.AltForm, pkm.Country, pkm.Region)) + if (!Legal.CheckVivillonPattern(pkm.AltForm, (byte)pkm.Country, (byte)pkm.Region)) data.AddLine(Get(LFormVivillonInvalid, Severity.Fishy)); break; diff --git a/PKHeX.Core/Legality/Verifiers/IndividualValueVerifier.cs b/PKHeX.Core/Legality/Verifiers/IndividualValueVerifier.cs index 05b8fe973..b15aa214e 100644 --- a/PKHeX.Core/Legality/Verifiers/IndividualValueVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/IndividualValueVerifier.cs @@ -47,8 +47,8 @@ private static bool AllIVsEqual(PKM pkm, int hpiv) private void VerifyIVsMystery(LegalityAnalysis data, MysteryGift g) { - int[] IVs = g.IVs; - if (IVs == null) + var IVs = g.IVs; + if (IVs.Length == 0) return; var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3); diff --git a/PKHeX.Core/Legality/Verifiers/MemoryVerifier.cs b/PKHeX.Core/Legality/Verifiers/MemoryVerifier.cs index f8a906180..a8138fcb7 100644 --- a/PKHeX.Core/Legality/Verifiers/MemoryVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/MemoryVerifier.cs @@ -13,6 +13,8 @@ public sealed class MemoryVerifier : Verifier { protected override CheckIdentifier Identifier => CheckIdentifier.Memory; + private static readonly CheckResult NONE = new CheckResult(CheckIdentifier.Memory); + public override void Verify(LegalityAnalysis data) { if (data.pkm.Format < 6) @@ -161,7 +163,7 @@ private CheckResult VerifyHistory7(LegalityAnalysis data) private bool VerifyHistoryUntradedHandler(PKM pkm, out CheckResult result) { - result = null; + result = NONE; if (pkm.CurrentHandler != 0) // Badly edited; PKHeX doesn't trip this. result = GetInvalid(LMemoryHTFlagInvalid); else if (pkm.HT_Friendship != 0) @@ -176,7 +178,7 @@ private bool VerifyHistoryUntradedHandler(PKM pkm, out CheckResult result) private bool VerifyHistoryUntradedEvolution(PKM pkm, IReadOnlyList[] chain, out CheckResult result) { - result = null; + result = NONE; // Handling Trainer string is empty implying it has not been traded. // If it must be trade evolved, flag it. diff --git a/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs b/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs index d82817754..410a4b52a 100644 --- a/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/MiscVerifier.cs @@ -185,8 +185,8 @@ private static void VerifyMiscEggCommon(LegalityAnalysis data) data.AddLine(GetInvalid(LEggPP, Egg)); var EncounterMatch = data.EncounterOriginal; - var HatchCycles = (EncounterMatch as EncounterStatic)?.EggCycles; - if (HatchCycles == 0 || HatchCycles == null) + var HatchCycles = EncounterMatch is EncounterStatic s ? s.EggCycles : 0; + if (HatchCycles == 0) // no value set HatchCycles = pkm.PersonalInfo.HatchCycles; if (pkm.CurrentFriendship > HatchCycles) data.AddLine(GetInvalid(LEggHatchCycles, Egg)); diff --git a/PKHeX.Core/Legality/Verifiers/NicknameVerifier.cs b/PKHeX.Core/Legality/Verifiers/NicknameVerifier.cs index 28b84ff62..c638616e9 100644 --- a/PKHeX.Core/Legality/Verifiers/NicknameVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/NicknameVerifier.cs @@ -1,5 +1,6 @@ using System; using static PKHeX.Core.LegalityCheckStrings; +using static PKHeX.Core.LanguageID; namespace PKHeX.Core { @@ -57,9 +58,9 @@ public override void Verify(LegalityAnalysis data) if (ParseSettings.CheckWordFilter && pkm.IsNicknamed) { if (WordFilter.IsFiltered(nickname, out string bad)) - data.AddLine(GetInvalid($"Wordfilter: {bad}")); + data.AddLine(GetInvalid($"Word Filter: {bad}")); if (TrainerNameVerifier.ContainsTooManyNumbers(nickname, data.Info.Generation)) - data.AddLine(GetInvalid("Wordfilter: Too many numbers.")); + data.AddLine(GetInvalid("Word Filter: Too many numbers.")); } } @@ -82,7 +83,7 @@ private bool VerifyUnNicknamedEncounter(LegalityAnalysis data, PKM pkm, string n } if (nickname.Length > Legal.GetMaxLengthNickname(data.Info.Generation, (LanguageID)pkm.Language)) { - var severe = data.EncounterOriginal.EggEncounter && pkm.WasTradedEgg && nickname.Length <= Legal.GetMaxLengthNickname(data.Info.Generation, LanguageID.English) + var severe = data.EncounterOriginal.EggEncounter && pkm.WasTradedEgg && nickname.Length <= Legal.GetMaxLengthNickname(data.Info.Generation, English) ? Severity.Fishy : Severity.Invalid; data.AddLine(Get(LNickLengthLong, severe)); @@ -105,7 +106,7 @@ private bool VerifyUnNicknamedEncounter(LegalityAnalysis data, PKM pkm, string n return false; } - private bool IsNicknameValid(PKM pkm, IEncounterable EncounterMatch, string nickname) + private static bool IsNicknameValid(PKM pkm, IEncounterable EncounterMatch, string nickname) { if (SpeciesName.GetSpeciesNameGeneration(pkm.Species, pkm.Language, pkm.Format) == nickname) return true; @@ -205,7 +206,7 @@ private void VerifyG1NicknameWithinBounds(LegalityAnalysis data, string str) } } - private void VerifyTrade12(LegalityAnalysis data, EncounterTrade t) + private static void VerifyTrade12(LegalityAnalysis data, EncounterTrade t) { if (t.TID != 0) // Gen2 Trade return; // already checked all relevant properties when fetching with getValidEncounterTradeVC2 @@ -214,7 +215,7 @@ private void VerifyTrade12(LegalityAnalysis data, EncounterTrade t) data.AddLine(GetInvalid(LEncTradeChangedOT, CheckIdentifier.Trainer)); } - private void VerifyTrade3(LegalityAnalysis data, EncounterTrade t) + private static void VerifyTrade3(LegalityAnalysis data, EncounterTrade t) { var pkm = data.pkm; int lang = pkm.Language; @@ -223,7 +224,7 @@ private void VerifyTrade3(LegalityAnalysis data, EncounterTrade t) VerifyTrade(data, t, lang); } - private void VerifyTrade4(LegalityAnalysis data, EncounterTrade t) + private static void VerifyTrade4(LegalityAnalysis data, EncounterTrade t) { var pkm = data.pkm; if (pkm.TID == 1000) @@ -249,7 +250,7 @@ private void VerifyTrade4(LegalityAnalysis data, EncounterTrade t) if (lang == 1 && (pkm.Version == (int)GameVersion.D || pkm.Version == (int)GameVersion.P)) { // DP English origin are Japanese lang - if (pkm.OT_Name != t.TrainerNames[1]) // not japanese + if (pkm.OT_Name != t.GetOT(1)) // not japanese lang = 2; // English } break; @@ -259,9 +260,9 @@ private void VerifyTrade4(LegalityAnalysis data, EncounterTrade t) private static void FlagKoreanIncompatibleSameGenTrade(LegalityAnalysis data, PKM pkm, int lang) { - if (pkm.Format != 4 || lang != (int)LanguageID.Korean) + if (pkm.Format != 4 || lang != (int)Korean) return; // transferred or not appropriate - if (ParseSettings.ActiveTrainer.Language != (int)LanguageID.Korean && ParseSettings.ActiveTrainer.Language >= 0) + if (ParseSettings.ActiveTrainer.Language != (int)Korean && ParseSettings.ActiveTrainer.Language >= 0) data.AddLine(GetInvalid(string.Format(LTransferOriginFInvalid0_1, L_XKorean, L_XKoreanNon), CheckIdentifier.Language)); } @@ -279,49 +280,49 @@ private static int DetectTradeLanguage(string OT, EncounterTrade t, int currentL private static int DetectTradeLanguageG3DANTAEJynx(PKM pk, int currentLanguageID) { - if (currentLanguageID != (int)LanguageID.Italian) + if (currentLanguageID != (int)Italian) return currentLanguageID; if (pk.Version == (int)GameVersion.LG) - currentLanguageID = (int)LanguageID.English; // translation error; OT was not localized => same as English + currentLanguageID = (int)English; // translation error; OT was not localized => same as English return currentLanguageID; } private static int DetectTradeLanguageG4MeisterMagikarp(PKM pkm, EncounterTrade t, int currentLanguageID) { - if (currentLanguageID == (int)LanguageID.English) - return (int)LanguageID.German; + if (currentLanguageID == (int)English) + return (int)German; // All have German, regardless of origin version. var lang = DetectTradeLanguage(pkm.OT_Name, t, currentLanguageID); - if (lang == (int)LanguageID.English) // possible collision with FR/ES/DE. Check nickname - return pkm.Nickname == t.Nicknames[(int)LanguageID.French] ? (int)LanguageID.French : (int)LanguageID.Spanish; // Spanish is same as English + if (lang == (int)English) // possible collision with FR/ES/DE. Check nickname + return pkm.Nickname == t.Nicknames[(int)French] ? (int)French : (int)Spanish; // Spanish is same as English return lang; } private static int DetectTradeLanguageG4SurgePikachu(PKM pkm, EncounterTrade t, int currentLanguageID) { - if (currentLanguageID == (int)LanguageID.French) - return (int)LanguageID.English; + if (currentLanguageID == (int)French) + return (int)English; // All have English, regardless of origin version. var lang = DetectTradeLanguage(pkm.OT_Name, t, currentLanguageID); if (lang == 2) // possible collision with ES/IT. Check nickname - return pkm.Nickname == t.Nicknames[(int)LanguageID.Italian] ? (int)LanguageID.Italian : (int)LanguageID.Spanish; + return pkm.Nickname == t.Nicknames[(int)Italian] ? (int)Italian : (int)Spanish; return lang; } - private void VerifyTrade5(LegalityAnalysis data, EncounterTrade t) + private static void VerifyTrade5(LegalityAnalysis data, EncounterTrade t) { var pkm = data.pkm; int lang = pkm.Language; // Trades for JPN games have language ID of 0, not 1. if (pkm.BW) { - if (pkm.Format == 5 && lang == (int)LanguageID.Japanese) - data.AddLine(GetInvalid(string.Format(LOTLanguage, 0, LanguageID.Japanese), CheckIdentifier.Language)); + if (pkm.Format == 5 && lang == (int)Japanese) + data.AddLine(GetInvalid(string.Format(LOTLanguage, 0, Japanese), CheckIdentifier.Language)); lang = Math.Max(lang, 1); VerifyTrade(data, t, lang); diff --git a/PKHeX.Core/Legality/Verifiers/ParseSettings.cs b/PKHeX.Core/Legality/Verifiers/ParseSettings.cs index 29de012ef..c7ae9dad4 100644 --- a/PKHeX.Core/Legality/Verifiers/ParseSettings.cs +++ b/PKHeX.Core/Legality/Verifiers/ParseSettings.cs @@ -58,8 +58,8 @@ public static bool InitFromSaveFileData(SaveFile sav) ActiveTrainer = sav; if (sav.Generation >= 3) return AllowGBCartEra = false; - string path = sav.FileName; - bool vc = path.EndsWith("dat"); + var path = sav.FileName; + bool vc = path?.EndsWith("dat") ?? false; return AllowGBCartEra = !vc; // physical cart selected } } diff --git a/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonResult.cs b/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonResult.cs index 04cd45fb4..62a96ffe3 100644 --- a/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonResult.cs +++ b/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonResult.cs @@ -14,7 +14,7 @@ internal class RibbonResult public RibbonResult(string prop, bool invalid = true) { - Name = RibbonStrings.GetName(prop) ?? prop; + Name = RibbonStrings.GetName(prop); Invalid = invalid; } diff --git a/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonStrings.cs b/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonStrings.cs index 5375c9993..87f136498 100644 --- a/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonStrings.cs +++ b/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonStrings.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -20,10 +21,7 @@ public static void ResetDictionary(IEnumerable lines) string[] split = line.Split('\t'); if (split.Length != 2) continue; - if (RibbonNames.ContainsKey(split[0])) - RibbonNames[split[0]] = split[1]; - else - RibbonNames.Add(split[0], split[1]); + RibbonNames[split[0]] = split[1]; } } @@ -34,9 +32,9 @@ public static void ResetDictionary(IEnumerable lines) /// Ribbon display name public static string GetName(string propertyName) { - if (RibbonNames.TryGetValue(propertyName, out string value)) - return value; - return null; + if (!RibbonNames.TryGetValue(propertyName, out string value)) + throw new ArgumentException(propertyName); + return value; } } } diff --git a/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifier.cs b/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifier.cs index 9fbb0a8f5..df8b40ea6 100644 --- a/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonVerifier.cs @@ -63,8 +63,10 @@ private static bool GetIncorrectRibbonsEgg(PKM pkm, object encounterContent) if (encounterContent is IRibbonSetEvent4 event4) RibbonNames = RibbonNames.Except(event4.RibbonNames()); - foreach (object RibbonValue in RibbonNames.Select(RibbonName => ReflectUtil.GetValue(pkm, RibbonName))) + foreach (var RibbonValue in RibbonNames.Select(RibbonName => ReflectUtil.GetValue(pkm, RibbonName))) { + if (RibbonValue is null) + continue; if (HasFlag(RibbonValue) || HasCount(RibbonValue)) return true; @@ -334,7 +336,7 @@ private static IEnumerable GetInvalidRibbonsEvent1(PKM pkm, object yield break; var names = set1.RibbonNames(); var sb = set1.RibbonBits(); - var eb = (encounterContent as IRibbonSetEvent3).RibbonBits(); + var eb = encounterContent is IRibbonSetEvent3 e3 ? e3.RibbonBits() : new bool[sb.Length]; if (pkm.Gen3) { @@ -360,7 +362,7 @@ private static IEnumerable GetInvalidRibbonsEvent2(PKM pkm, object yield break; var names = set2.RibbonNames(); var sb = set2.RibbonBits(); - var eb = (encounterContent as IRibbonSetEvent4).RibbonBits(); + var eb = encounterContent is IRibbonSetEvent4 e4 ? e4.RibbonBits() : new bool[sb.Length]; if (encounterContent is EncounterStatic s && s.RibbonWishing) eb[1] = true; // require Wishing Ribbon diff --git a/PKHeX.Core/Legality/VivillonTables.cs b/PKHeX.Core/Legality/VivillonTables.cs index 00beeac21..19c7128a3 100644 --- a/PKHeX.Core/Legality/VivillonTables.cs +++ b/PKHeX.Core/Legality/VivillonTables.cs @@ -8,243 +8,140 @@ public static partial class Legal { private class CountryTable { - public byte CountryID; - public byte BaseForm; - public FormSubregionTable[] SubRegionForms; + public readonly byte BaseForm; + public readonly byte CountryID; + public readonly FormSubregionTable[] SubRegionForms; + + internal CountryTable(byte form, byte country, params FormSubregionTable[] subs) + { + BaseForm = form; + CountryID = country; + SubRegionForms = subs; + } } private class FormSubregionTable { - public byte Form; - public int[] Regions; + public readonly byte Form; + public readonly byte[] Regions; + + internal FormSubregionTable(byte form, byte[] regions) + { + Form = form; + Regions = regions; + } } - private static readonly int[][] VivillonCountryTable = + private static readonly byte[][] VivillonCountryTable = { //missing ID 051,068,102,127,160,186 - /* 0 Icy Snow */ new[] { 018, 076, 096, 100, 107 }, - /* 1 Polar */ new[] { 010, 018, 020, 049, 076, 096, 100, 107 }, - /* 2 Tundra */ new[] { 001, 081, 096, }, - /* 3 Continental */ new[] { 010, 067, 073, 074, 075, 077, 078, 084, 087, 094, 096, 097, 100, 107, 136}, - /* 4 Garden */ new[] { 065, 082, 095, 097, 101, 110, 125}, - /* 5 Elegant */ new[] { 001 }, - /* 6 Meadow */ new[] { 066, 077, 078, 083, 086, 088, 105, 108, 122}, - /* 7 Modern */ new[] { 018, 049}, - /* 8 Marine */ new[] { 020, 064, 066, 070, 071, 073, 077, 078, 079, 080, 083, 089, 090, 091, 098, 099, 103, 105, 123, 124, 126, 184, 185}, - /* 9 Archipelago */ new[] { 008, 009, 011, 012, 013, 017, 021, 023, 024, 028, 029, 032, 034, 035, 036, 037, 038, 043, 044, 045, 047, 048, 049, 052, 085, 104,}, - /*10 High Plains */ new[] { 018, 036, 049, 100, 113}, - /*11 Sandstorm */ new[] { 072, 109, 118, 119, 120, 121, 168, 174}, - /*12 River */ new[] { 065, 069, 085, 093, 104, 105, 114, 115, 116, 117}, - /*13 Monsoon */ new[] { 001, 128, 144, 169}, - /*14-Savanna */ new[] { 010, 015, 016, 041, 042, 050}, - /*15 Sun */ new[] { 036, 014, 019, 026, 030, 033, 036, 039, 065, 092, 106, 111, 112}, - /*16 Ocean */ new[] { 049, 077}, - /*17 Jungle */ new[] { 016, 021, 022, 025, 027, 031, 040, 046, 052, 169, 153, 156}, + /* 0 Icy Snow */ new byte[] { 018, 076, 096, 100, 107 }, + /* 1 Polar */ new byte[] { 010, 018, 020, 049, 076, 096, 100, 107 }, + /* 2 Tundra */ new byte[] { 001, 081, 096, }, + /* 3 Continental */ new byte[] { 010, 067, 073, 074, 075, 077, 078, 084, 087, 094, 096, 097, 100, 107, 136}, + /* 4 Garden */ new byte[] { 065, 082, 095, 097, 101, 110, 125}, + /* 5 Elegant */ new byte[] { 001 }, + /* 6 Meadow */ new byte[] { 066, 077, 078, 083, 086, 088, 105, 108, 122}, + /* 7 Modern */ new byte[] { 018, 049}, + /* 8 Marine */ new byte[] { 020, 064, 066, 070, 071, 073, 077, 078, 079, 080, 083, 089, 090, 091, 098, 099, 103, 105, 123, 124, 126, 184, 185}, + /* 9 Archipelago */ new byte[] { 008, 009, 011, 012, 013, 017, 021, 023, 024, 028, 029, 032, 034, 035, 036, 037, 038, 043, 044, 045, 047, 048, 049, 052, 085, 104,}, + /*10 High Plains */ new byte[] { 018, 036, 049, 100, 113}, + /*11 Sandstorm */ new byte[] { 072, 109, 118, 119, 120, 121, 168, 174}, + /*12 River */ new byte[] { 065, 069, 085, 093, 104, 105, 114, 115, 116, 117}, + /*13 Monsoon */ new byte[] { 001, 128, 144, 169}, + /*14-Savanna */ new byte[] { 010, 015, 016, 041, 042, 050}, + /*15 Sun */ new byte[] { 036, 014, 019, 026, 030, 033, 036, 039, 065, 092, 106, 111, 112}, + /*16 Ocean */ new byte[] { 049, 077}, + /*17 Jungle */ new byte[] { 016, 021, 022, 025, 027, 031, 040, 046, 052, 169, 153, 156}, }; private static readonly CountryTable[] RegionFormTable = { - new CountryTable{ - CountryID = 001, // Japan - BaseForm = 05, // Elegant - SubRegionForms = new[] - { - new FormSubregionTable { Form = 02, Regions = new[] {03,04} }, - new FormSubregionTable { Form = 13, Regions = new[] {48} }, - } - }, - new CountryTable{ - CountryID = 049, // USA - BaseForm = 07, // Modern - SubRegionForms = new[] - { - new FormSubregionTable { Form = 01, Regions = new[] {03,09,21,23,24,32,33,36,40,41,48,50} }, - new FormSubregionTable { Form = 09, Regions = new[] {53} }, - new FormSubregionTable { Form = 10, Regions = new[] {06,07,08,15,28,34,35,39,46,49} }, - } - }, - new CountryTable{ - CountryID = 018, // Canada - BaseForm = 01, // Polar - SubRegionForms = new[] - { - new FormSubregionTable { Form = 00, Regions = new[] {12,13,14} }, - new FormSubregionTable { Form = 07, Regions = new[] {05} }, - new FormSubregionTable { Form = 10, Regions = new[] {04} }, - } - }, - new CountryTable{ - CountryID = 016, // Brazil - BaseForm = 14, // Savanna - SubRegionForms = new[] - { - new FormSubregionTable { Form = 17, Regions = new[] {03,06} }, - } - }, - new CountryTable{ - CountryID = 010, // Argentina - BaseForm = 14, // Savanna - SubRegionForms = new[] - { - new FormSubregionTable { Form = 01, Regions = new[] {21,24} }, - new FormSubregionTable { Form = 03, Regions = new[] {16} }, - } - }, - new CountryTable{ - CountryID = 020, // Chile - BaseForm = 08, // Marine - SubRegionForms = new[] - { - new FormSubregionTable { Form = 01, Regions = new[] {12} }, - } - }, - new CountryTable{ - CountryID = 036, // Mexico - BaseForm = 15, // Sun - SubRegionForms = new[] - { - new FormSubregionTable { Form = 09, Regions = new[] {32} }, - new FormSubregionTable { Form = 10, Regions = new[] {04,08,09,12,15,19,20,23,26,27,29} }, - } - }, - new CountryTable{ - CountryID = 052, // Venezuela - BaseForm = 09, // Archipelago - SubRegionForms = new[] - { - new FormSubregionTable { Form = 17, Regions = new[] {17} }, - } - }, - new CountryTable{ - CountryID = 065, // Australia - BaseForm = 09, // River - SubRegionForms = new[] - { - new FormSubregionTable { Form = 04, Regions = new[] {07} }, - new FormSubregionTable { Form = 15, Regions = new[] {04} }, - } - }, - new CountryTable{ - CountryID = 066, // Austria - BaseForm = 08, // Marine - SubRegionForms = new[] - { - new FormSubregionTable { Form = 06, Regions = new[] {10} }, - } - }, - new CountryTable{ - CountryID = 073, // Czecg Republic - BaseForm = 08, // Marine - SubRegionForms = new[] - { - new FormSubregionTable { Form = 03, Regions = new[] {03} }, - } - }, - new CountryTable{ - CountryID = 076, // Finland - BaseForm = 00, // Icy Snow - SubRegionForms = new[] - { - new FormSubregionTable { Form = 01, Regions = new[] {27} }, - } - }, - new CountryTable{ - CountryID = 077, // France - BaseForm = 06, // Meadow - SubRegionForms = new[] - { - new FormSubregionTable { Form = 03, Regions = new[] {18} }, - new FormSubregionTable { Form = 08, Regions = new[] {04,06,08,19} }, - new FormSubregionTable { Form = 16, Regions = new[] {27} }, - } - }, - new CountryTable{ - CountryID = 078, // Germany - BaseForm = 03, // Continental - SubRegionForms = new[] - { - new FormSubregionTable { Form = 06, Regions = new[] {04,13} }, - new FormSubregionTable { Form = 08, Regions = new[] {05} }, - } - }, - new CountryTable{ - CountryID = 078, // Italy - BaseForm = 08, // Marine - SubRegionForms = new[] - { - new FormSubregionTable { Form = 06, Regions = new[] {04,06} }, - } - }, - new CountryTable{ - CountryID = 085, // Lesotho - BaseForm = 09, // Archipelago ?? - SubRegionForms = new[] - { - new FormSubregionTable { Form = 12, Regions = new[] {04} }, - } - }, - new CountryTable{ - CountryID = 096, // Norway - BaseForm = 03, // Continental ?? - SubRegionForms = new[] - { - new FormSubregionTable { Form = 00, Regions = new[] {11} }, - new FormSubregionTable { Form = 01, Regions = new[] {12,15,16,17,20,22} }, - new FormSubregionTable { Form = 02, Regions = new[] {13,14} }, - } - }, - new CountryTable{ - CountryID = 097, // Poland - BaseForm = 03, // Continental - SubRegionForms = new[] - { - new FormSubregionTable { Form = 04, Regions = new[] {11} }, - } - }, - new CountryTable{ - CountryID = 100, // Russia - BaseForm = 01, // Polar - SubRegionForms = new[] - { - new FormSubregionTable { Form = 00, Regions = new[] {14,22,34,38,40,52,66,88} }, - new FormSubregionTable { Form = 03, Regions = new[] {29,46,51,69} }, - new FormSubregionTable { Form = 10, Regions = new[] {20,24,25,28,33,71,73} }, - } - }, - new CountryTable{ - CountryID = 104, //South Africa - BaseForm = 12, // River ?? - SubRegionForms = new[] - { - new FormSubregionTable { Form = 03, Regions = new[] {03,05} }, - } - }, - new CountryTable{ - CountryID = 105, // Spain - BaseForm = 08, // Marine - SubRegionForms = new[] - { - new FormSubregionTable { Form = 06, Regions = new[] {11} }, - new FormSubregionTable { Form = 12, Regions = new[] {07} }, - } - }, - new CountryTable{ - CountryID = 107, // Sweden - BaseForm = 03, // Continental - SubRegionForms = new[] - { - new FormSubregionTable { Form = 00, Regions = new[] {11,21} }, - new FormSubregionTable { Form = 01, Regions = new[] {09,13} }, - } - }, - new CountryTable{ - CountryID = 169, // India - BaseForm = 13, // Monsoon ?? - SubRegionForms = new[] - { - new FormSubregionTable { Form = 17, Regions = new[] {12} }, - } - }, + new CountryTable(05, 1, // Japan: Elegant + new FormSubregionTable(02, new byte[] {03,04}), + new FormSubregionTable(13, new byte[] {48})), + + new CountryTable(07, 49, // USA: Modern + new FormSubregionTable(01, new byte[] {03,09,21,23,24,32,33,36,40,41,48,50}), + new FormSubregionTable(09, new byte[] {53}), + new FormSubregionTable(10, new byte[] {06,07,08,15,28,34,35,39,46,49})), + + new CountryTable(01, 18, // Canada: Polar + new FormSubregionTable(00, new byte[] {12,13,14}), + new FormSubregionTable(07, new byte[] {05}), + new FormSubregionTable(10, new byte[] {04})), + + new CountryTable(14, 16, // Brazil: Savanna + new FormSubregionTable(17, new byte[] {03,06})), + + new CountryTable(14, 10, // Argentina: Savanna + new FormSubregionTable(01, new byte[] {21,24}), + new FormSubregionTable(03, new byte[] {16})), + + new CountryTable(08, 20, // Chile: Marine + new FormSubregionTable(01, new byte[] {12})), + + new CountryTable(15, 36, // Mexico: Sun + new FormSubregionTable(09, new byte[] {32}), + new FormSubregionTable(10, new byte[] {04,08,09,12,15,19,20,23,26,27,29})), + + new CountryTable(09, 52, // Venezuela: Archipelago + new FormSubregionTable(17, new byte[] {17})), + + new CountryTable(09, 65, // Australia: River + new FormSubregionTable(04, new byte[] {07}), + new FormSubregionTable(15, new byte[] {04})), + + new CountryTable(08, 66, // Austria: Marine + new FormSubregionTable(06, new byte[] {10})), + + new CountryTable(08, 73, // Czech Republic: Marine + new FormSubregionTable(03, new byte[] {03})), + + new CountryTable(00, 76, // Finland: Icy Snow + new FormSubregionTable(01, new byte[] {27})), + + new CountryTable(06, 77, // France: Meadow + new FormSubregionTable(03, new byte[] {18}), + new FormSubregionTable(08, new byte[] {04,06,08,19}), + new FormSubregionTable(16, new byte[] {27})), + + new CountryTable(03, 078, // Germany: Continental + new FormSubregionTable(06, new byte[] {04,13}), + new FormSubregionTable(08, new byte[] {05})), + + new CountryTable(08, 83, // Italy: Marine + new FormSubregionTable(06, new byte[] {04,06})), + + new CountryTable(09, 85, // Lesotho: Archipelago ?? + new FormSubregionTable(12, new byte[] {04})), + + new CountryTable(03, 96, // Norway: Continental ?? + new FormSubregionTable(00, new byte[] {11}), + new FormSubregionTable(01, new byte[] {12,15,16,17,20,22}), + new FormSubregionTable(02, new byte[] {13,14})), + + new CountryTable(03, 97, // Poland: Continental + new FormSubregionTable(04, new byte[] {11})), + + new CountryTable(01, 100, // Russia: Polar + new FormSubregionTable(00, new byte[] {14,22,34,38,40,52,66,88}), + new FormSubregionTable(03, new byte[] {29,46,51,69}), + new FormSubregionTable(10, new byte[] {20,24,25,28,33,71,73})), + + new CountryTable(12, 104, // South Affrica: River ?? + new FormSubregionTable(03, new byte[] {03,05})), + + new CountryTable(08, 105, // Spain: Marine + new FormSubregionTable(06, new byte[] {11}), + new FormSubregionTable(12, new byte[] {07})), + + new CountryTable(03, 107, // Sweden: Continental + new FormSubregionTable(00, new byte[] {11,21}), + new FormSubregionTable(01, new byte[] {09,13})), + + new CountryTable(13, 169, // India: Monsoon ?? + new FormSubregionTable(17, new byte[] {12})), }; /// @@ -254,7 +151,7 @@ private class FormSubregionTable /// Country ID /// Console Region ID /// - public static bool CheckVivillonPattern(int form, int country, int region) + public static bool CheckVivillonPattern(int form, byte country, byte region) { if (!VivillonCountryTable[form].Contains(country)) return false; // Country mismatch @@ -274,7 +171,7 @@ public static bool CheckVivillonPattern(int form, int country, int region) /// /// Country ID /// Console Region ID - public static int GetVivillonPattern(int country, int region) + public static int GetVivillonPattern(byte country, byte region) { var ct = Array.Find(RegionFormTable, t => t.CountryID == country); if (ct == default(CountryTable)) // empty = no forms referenced @@ -289,7 +186,7 @@ public static int GetVivillonPattern(int country, int region) return ct.BaseForm; } - private static int GetVivillonPattern(int country) + private static int GetVivillonPattern(byte country) { var form = Array.FindIndex(VivillonCountryTable, z => z.Contains(country)); return Math.Max(0, form); diff --git a/PKHeX.Core/Legality/WordFilter.cs b/PKHeX.Core/Legality/WordFilter.cs index e304ae017..d6c3363a5 100644 --- a/PKHeX.Core/Legality/WordFilter.cs +++ b/PKHeX.Core/Legality/WordFilter.cs @@ -18,6 +18,8 @@ public static class WordFilter /// private static readonly Dictionary Lookup = new Dictionary(INIT_COUNT); + private const string NoMatch = ""; + /// /// Checks to see if a phrase contains filtered content. /// @@ -28,7 +30,7 @@ public static bool IsFiltered(string message, out string regMatch) { if (string.IsNullOrWhiteSpace(message) || message.Length <= 1) { - regMatch = null; + regMatch = NoMatch; return false; } @@ -37,7 +39,7 @@ public static bool IsFiltered(string message, out string regMatch) lock (dictLock) { if (Lookup.TryGetValue(msg, out regMatch)) - return regMatch != null; + return !ReferenceEquals(regMatch, NoMatch); } // not in dictionary, check patterns @@ -58,7 +60,7 @@ public static bool IsFiltered(string message, out string regMatch) { if ((Lookup.Count & ~MAX_COUNT) != 0) Lookup.Clear(); // reset - Lookup.Add(msg, regMatch = null); + Lookup.Add(msg, regMatch = NoMatch); } return false; } diff --git a/PKHeX.Core/MysteryGifts/MysteryGift.cs b/PKHeX.Core/MysteryGifts/MysteryGift.cs index 63cb5d039..5599cc56b 100644 --- a/PKHeX.Core/MysteryGifts/MysteryGift.cs +++ b/PKHeX.Core/MysteryGifts/MysteryGift.cs @@ -1,9 +1,39 @@ using System; using System.Collections.Generic; -using System.Linq; namespace PKHeX.Core { + public abstract class DataMysteryGift : MysteryGift + { + public readonly byte[] Data; + + protected DataMysteryGift(byte[] data) => Data = data; + + public override int GetHashCode() + { + int hash = 17; + foreach (var b in Data) + hash = (hash * 31) + b; + return hash; + } + + + /// + /// Creates a deep copy of the object data. + /// + /// + public override MysteryGift Clone() + { + byte[] data = (byte[])Data.Clone(); + var result = GetMysteryGift(data); + if (result == null) + throw new ArgumentException(nameof(MysteryGift)); + return result; + } + + public override bool Empty => Data.IsRangeAll(0, 0, Data.Length); + } + /// /// Mystery Gift Template File /// @@ -16,7 +46,7 @@ public abstract class MysteryGift : IEncounterable, IMoveset, IGeneration, ILoca /// A boolean indicating whether or not the given length is valid for a mystery gift. public static bool IsMysteryGift(long len) => MGSizes.Contains((int)len); - private static readonly HashSet MGSizes = new HashSet{WC6.SizeFull, WC6.Size, PGF.Size, PGT.Size, PCD.Size }; + private static readonly HashSet MGSizes = new HashSet{ WC6Full.Size, WC6.Size, PGF.Size, PGT.Size, PCD.Size }; /// /// Converts the given data to a . @@ -25,7 +55,7 @@ public abstract class MysteryGift : IEncounterable, IMoveset, IGeneration, ILoca /// Extension of the file from which the was retrieved. /// An instance of representing the given data, or null if or is invalid. /// This overload differs from by checking the / combo for validity. If either is invalid, a null reference is returned. - public static MysteryGift GetMysteryGift(byte[] data, string ext) + public static DataMysteryGift? GetMysteryGift(byte[] data, string ext) { if (ext == null) return GetMysteryGift(data); @@ -35,10 +65,12 @@ public static MysteryGift GetMysteryGift(byte[] data, string ext) case WB7.SizeFull when ext == ".wb7full": case WB7.Size when ext == ".wb7": return new WB7(data); - case WC7.SizeFull when ext == ".wc7full": + case WC7Full.Size when ext == ".wc7full": + return new WC7Full(data).Gift; case WC7.Size when ext == ".wc7": return new WC7(data); - case WC6.SizeFull when ext == ".wc6full": + case WC6Full.Size when ext == ".wc6full": + return new WC6Full(data).Gift; case WC6.Size when ext == ".wc6": return new WC6(data); case WR7.Size when ext == ".wr7": @@ -60,15 +92,15 @@ public static MysteryGift GetMysteryGift(byte[] data, string ext) /// /// Raw data of the mystery gift. /// An instance of representing the given data, or null if is invalid. - public static MysteryGift GetMysteryGift(byte[] data) + public static DataMysteryGift? GetMysteryGift(byte[] data) { switch (data.Length) { - case WC6.SizeFull: + case WC6Full.Size: // Check WC7 size collision if (data[0x205] == 0) // 3 * 0x46 for gen6, now only 2. - return new WC7(data); - return new WC6(data); + return new WC7Full(data).Gift; + return new WC6Full(data).Gift; case WC6.Size: // Check year for WC7 size collision if (BitConverter.ToUInt32(data, 0x4C) / 10000 < 2000) @@ -85,7 +117,6 @@ public static MysteryGift GetMysteryGift(byte[] data) public string Extension => GetType().Name.ToLower(); public string FileName => $"{CardHeader}.{Extension}"; - public byte[] Data { get; set; } public abstract int Format { get; } public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted); @@ -107,11 +138,7 @@ public EncounterMatchRating IsMatch(PKM pkm, IEnumerable vs) /// Creates a deep copy of the object data. /// /// - public MysteryGift Clone() - { - byte[] data = (byte[])Data.Clone(); - return GetMysteryGift(data); - } + public abstract MysteryGift Clone(); /// /// Gets a friendly name for the underlying type. @@ -139,7 +166,7 @@ public MysteryGift Clone() public abstract bool IsPokémon { get; set; } public virtual int Quantity { get => 1; set { } } - public virtual bool Empty => Data.All(z => z == 0); + public virtual bool Empty => false; public virtual bool IsBP { get => false; set { } } public virtual int BP { get => 0; set { } } @@ -148,19 +175,11 @@ public MysteryGift Clone() public virtual int BeanCount { get => 0; set { } } public virtual string CardHeader => (CardID > 0 ? $"Card #: {CardID:0000}" : "N/A") + $" - {CardTitle.Replace('\u3000',' ').Trim()}"; - - public override int GetHashCode() - { - int hash = 17; - foreach (var b in Data) - hash = (hash * 31) + b; - return hash; - } - + // Search Properties public virtual int[] Moves { get => Array.Empty(); set { } } public virtual int[] RelearnMoves { get => Array.Empty(); set { } } - public virtual int[] IVs { get => null; set { } } + public virtual int[] IVs { get => Array.Empty(); set { } } public virtual bool IsShiny => false; public virtual bool IsEgg { get => false; set { } } public virtual int HeldItem { get => -1; set { } } diff --git a/PKHeX.Core/MysteryGifts/MysteryUtil.cs b/PKHeX.Core/MysteryGifts/MysteryUtil.cs index 090e32419..57a7a91ee 100644 --- a/PKHeX.Core/MysteryGifts/MysteryUtil.cs +++ b/PKHeX.Core/MysteryGifts/MysteryUtil.cs @@ -24,7 +24,9 @@ public static IEnumerable GetGiftsFromFolder(string folder) if (!MysteryGift.IsMysteryGift(fi.Length)) continue; - yield return MysteryGift.GetMysteryGift(File.ReadAllBytes(file), fi.Extension); + var gift = MysteryGift.GetMysteryGift(File.ReadAllBytes(file), fi.Extension); + if (gift != null) + yield return gift; } } @@ -138,7 +140,7 @@ public static bool IsCardCompatible(this MysteryGift g, SaveFile SAV, out string } } - message = null; + message = string.Empty; return true; } diff --git a/PKHeX.Core/MysteryGifts/PCD.cs b/PKHeX.Core/MysteryGifts/PCD.cs index 308f81678..eec2d99f9 100644 --- a/PKHeX.Core/MysteryGifts/PCD.cs +++ b/PKHeX.Core/MysteryGifts/PCD.cs @@ -13,7 +13,7 @@ namespace PKHeX.Core /// https://projectpokemon.org/home/forums/topic/5870-pok%C3%A9mon-mystery-gift-editor-v143-now-with-bw-support/ /// See also: http://tccphreak.shiny-clique.net/debugger/pcdfiles.htm /// - public sealed class PCD : MysteryGift + public sealed class PCD : DataMysteryGift { public const int Size = 0x358; // 856 public override int Format => 4; @@ -30,33 +30,21 @@ public override int Ball set => Gift.Ball = value; } - public PCD() => Data = new byte[Size]; - public PCD(byte[] data) => Data = data; + public PCD() : this(new byte[Size]) { } + public PCD(byte[] data) : base(data) { } public PGT Gift { - get - { - if (_gift != null) - return _gift; - byte[] giftData = new byte[PGT.Size]; - Array.Copy(Data, 0, giftData, 0, PGT.Size); - return _gift = new PGT(giftData); - } - set => (_gift = value)?.Data.CopyTo(Data, 0); + get => _gift ??= new PGT(Data.Slice(0, PGT.Size)); + set => (_gift = value).Data.CopyTo(Data, 0); } - private PGT _gift; + private PGT? _gift; public byte[] Information { - get - { - var data = new byte[Data.Length - PGT.Size]; - Array.Copy(Data, PGT.Size, data, 0, data.Length); - return data; - } - set => value?.CopyTo(Data, Data.Length - PGT.Size); + get => Data.SliceEnd(PGT.Size); + set => value.CopyTo(Data, Data.Length - PGT.Size); } public override object Content => Gift.PK; diff --git a/PKHeX.Core/MysteryGifts/PGF.cs b/PKHeX.Core/MysteryGifts/PGF.cs index 57afc3596..14e822a35 100644 --- a/PKHeX.Core/MysteryGifts/PGF.cs +++ b/PKHeX.Core/MysteryGifts/PGF.cs @@ -8,13 +8,13 @@ namespace PKHeX.Core /// /// Generation 5 Mystery Gift Template File /// - public sealed class PGF : MysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IContestStats + public sealed class PGF : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IContestStats { public const int Size = 0xCC; public override int Format => 5; - public PGF() => Data = new byte[Size]; - public PGF(byte[] data) => Data = data; + public PGF() : this(new byte[Size]) { } + public PGF(byte[] data) : base(data) { } public override int TID { get => BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } public override int SID { get => BitConverter.ToUInt16(Data, 0x02); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x02); } @@ -148,7 +148,7 @@ public override int[] IVs get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; set { - if (value?.Length != 6) return; + if (value.Length != 6) return; IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; } @@ -165,7 +165,7 @@ public override int[] IVs public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) - return null; + throw new ArgumentException(nameof(IsPokémon)); var dt = DateTime.Now; if (Day == 0) diff --git a/PKHeX.Core/MysteryGifts/PGT.cs b/PKHeX.Core/MysteryGifts/PGT.cs index ec9e98dac..5cbe12677 100644 --- a/PKHeX.Core/MysteryGifts/PGT.cs +++ b/PKHeX.Core/MysteryGifts/PGT.cs @@ -7,7 +7,7 @@ namespace PKHeX.Core /// /// Generation 4 Mystery Gift Template File (Inner Gift Data, no card data) /// - public sealed class PGT : MysteryGift + public sealed class PGT : DataMysteryGift { public const int Size = 0x104; // 260 public override int Format => 4; @@ -46,8 +46,8 @@ private enum GiftType public override bool GiftUsed { get => false; set { } } public override object Content => PK; - public PGT() => Data = new byte[Size]; - public PGT(byte[] data) => Data = data; + public PGT() : this(new byte[Size]) { } + public PGT(byte[] data) : base(data) { } public byte CardType { get => Data[0]; set => Data[0] = value; } // Unused 0x01 @@ -77,7 +77,7 @@ public PK4 PK } } - private PK4 _pk; + private PK4? _pk; /// /// Double checks the encryption of the gift data for Pokemon data. @@ -122,7 +122,7 @@ private void EncryptPK() public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) - return null; + throw new ArgumentException(nameof(IsPokémon)); // template is already filled out, only minor mutations required PK4 pk4 = new PK4((byte[])PK.Data.Clone()) { Sanity = 0 }; diff --git a/PKHeX.Core/MysteryGifts/PL6.cs b/PKHeX.Core/MysteryGifts/PL6.cs index b023d02ef..9d81b2606 100644 --- a/PKHeX.Core/MysteryGifts/PL6.cs +++ b/PKHeX.Core/MysteryGifts/PL6.cs @@ -137,10 +137,8 @@ public sealed class PL6_PKM : IRibbonSetEvent3, IRibbonSetEvent4 public readonly byte[] Data; - public PL6_PKM(byte[] data = null) - { - Data = data ?? new byte[Size]; - } + public PL6_PKM() : this(new byte[Size]) { } + public PL6_PKM(byte[] data) => Data = data; public int TID { get => BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } public int SID { get => BitConverter.ToUInt16(Data, 0x02); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x02); } diff --git a/PKHeX.Core/MysteryGifts/WB7.cs b/PKHeX.Core/MysteryGifts/WB7.cs index 7ae0c4f12..a81d04036 100644 --- a/PKHeX.Core/MysteryGifts/WB7.cs +++ b/PKHeX.Core/MysteryGifts/WB7.cs @@ -8,7 +8,7 @@ namespace PKHeX.Core /// /// Generation 7 Mystery Gift Template File /// - public sealed class WB7 : MysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IAwakened + public sealed class WB7 : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IAwakened { public const int Size = 0x108; public const int SizeFull = 0x310; @@ -16,8 +16,8 @@ public sealed class WB7 : MysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILang public override int Format => 7; - public WB7() => Data = new byte[SizeFull]; - public WB7(byte[] data) => Data = data; + public WB7() : this(new byte[SizeFull]) { } + public WB7(byte[] data) : base(data) { } public byte RestrictVersion { get => Data[0]; set => Data[0] = value; } @@ -247,7 +247,7 @@ public override int[] IVs get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; set { - if (value?.Length != 6) return; + if (value.Length != 6) return; IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; } @@ -315,7 +315,7 @@ private int GetOTOffset(int language) public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) - return null; + throw new ArgumentException(nameof(IsPokémon)); int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1; int metLevel = MetLevel > 0 ? MetLevel : currentLevel; diff --git a/PKHeX.Core/MysteryGifts/WC3.cs b/PKHeX.Core/MysteryGifts/WC3.cs index b3a5546ae..8eb551808 100644 --- a/PKHeX.Core/MysteryGifts/WC3.cs +++ b/PKHeX.Core/MysteryGifts/WC3.cs @@ -12,12 +12,14 @@ namespace PKHeX.Core /// public sealed class WC3 : MysteryGift, IRibbonSetEvent3, IVersion { + public override MysteryGift Clone() => (WC3)MemberwiseClone(); + /// /// Matched Type /// public PIDType Method; - public override string OT_Name { get; set; } + public override string OT_Name { get; set; } = string.Empty; public int OT_Gender { get; set; } = 3; public override int TID { get; set; } public override int SID { get; set; } @@ -37,7 +39,6 @@ public sealed class WC3 : MysteryGift, IRibbonSetEvent3, IVersion public override int Level { get; set; } public override int Ball { get; set; } = 4; public override bool IsShiny => Shiny == Shiny.Always; - public bool RibbonEarth { get; set; } public bool RibbonNational { get; set; } public bool RibbonCountry { get; set; } diff --git a/PKHeX.Core/MysteryGifts/WC6.cs b/PKHeX.Core/MysteryGifts/WC6.cs index a32ca2475..bcf8e9a4b 100644 --- a/PKHeX.Core/MysteryGifts/WC6.cs +++ b/PKHeX.Core/MysteryGifts/WC6.cs @@ -8,33 +8,14 @@ namespace PKHeX.Core /// /// Generation 6 Mystery Gift Template File /// - public sealed class WC6 : MysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IContestStats + public sealed class WC6 : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IContestStats { public const int Size = 0x108; - public const int SizeFull = 0x310; public const uint EonTicketConst = 0x225D73C2; public override int Format => 6; - public WC6() => Data = new byte[Size]; - - public WC6(byte[] data) - { - Data = data; if (Data.Length == SizeFull) - { - // Load Restrictions - RestrictVersion = Data[0x000]; - RestrictLanguage = Data[0x1FF]; - byte[] wc6 = new byte[Size]; - if (Data[0x205] != 0) // Valid data - Array.Copy(Data, SizeFull - Size, wc6, 0, wc6.Length); - Data = wc6; - - DateTime now = DateTime.Now; - RawDate = SetDate((uint) now.Year, (uint) now.Month, (uint) now.Day); - } - if (Year < 2000) - Data = new byte[Data.Length]; // Invalidate - } + public WC6() : this(new byte[Size]) { } + public WC6(byte[] data) : base(data) { } public int RestrictLanguage { get; set; } // None public byte RestrictVersion { get; set; } // Permit All @@ -64,7 +45,7 @@ public override string CardTitle set => Encoding.Unicode.GetBytes(value.PadRight(36, '\0')).CopyTo(Data, 2); } - private uint RawDate + internal uint RawDate { get => BitConverter.ToUInt32(Data, 0x4C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x4C); @@ -88,7 +69,7 @@ private uint Day set => RawDate = SetDate(Year, Month, value); } - private static uint SetDate(uint year, uint month, uint day) => (year * 10000) + (month * 100) + day; + public static uint SetDate(uint year, uint month, uint day) => (year * 10000) + (month * 100) + day; /// /// Gets or sets the date of the card. @@ -240,7 +221,7 @@ public override int[] IVs get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; set { - if (value?.Length != 6) return; + if (value.Length != 6) return; IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; } @@ -251,7 +232,7 @@ public int[] EVs get => new[] { EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD }; set { - if (value?.Length != 6) return; + if (value.Length != 6) return; EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2]; EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5]; } @@ -287,7 +268,7 @@ public override int[] RelearnMoves public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) - return null; + throw new ArgumentException(nameof(IsPokémon)); int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1; var pi = PersonalTable.AO.GetFormeEntry(Species, Form); diff --git a/PKHeX.Core/MysteryGifts/WC6Full.cs b/PKHeX.Core/MysteryGifts/WC6Full.cs new file mode 100644 index 000000000..7e9c6bc5e --- /dev/null +++ b/PKHeX.Core/MysteryGifts/WC6Full.cs @@ -0,0 +1,26 @@ +using System; + +namespace PKHeX.Core +{ + public sealed class WC6Full + { + public const int Size = 0x310; + public readonly byte[] Data; + public readonly WC6 Gift; + + public byte RestrictVersion { get => Data[0]; set => Data[0] = value; } + public byte RestrictLanguage { get => Data[0x1FF]; set => Data[0x1FF] = value; } + + public WC6Full(byte[] data) + { + Data = data; + var wc6 = data.SliceEnd(Size - WC6.Size); + Gift = new WC6(wc6); + var now = DateTime.Now; + Gift.RawDate = WC6.SetDate((uint)now.Year, (uint)now.Month, (uint)now.Day); + + Gift.RestrictVersion = RestrictVersion; + Gift.RestrictLanguage = RestrictLanguage; + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/MysteryGifts/WC7.cs b/PKHeX.Core/MysteryGifts/WC7.cs index 0810645e0..95cfb3547 100644 --- a/PKHeX.Core/MysteryGifts/WC7.cs +++ b/PKHeX.Core/MysteryGifts/WC7.cs @@ -8,31 +8,13 @@ namespace PKHeX.Core /// /// Generation 7 Mystery Gift Template File /// - public sealed class WC7 : MysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IContestStats + public sealed class WC7 : DataMysteryGift, IRibbonSetEvent3, IRibbonSetEvent4, ILangNick, IContestStats { public const int Size = 0x108; - public const int SizeFull = 0x310; public override int Format => 7; - public WC7() => Data = new byte[Size]; - - public WC7(byte[] data) - { - Data = data; - if (Data.Length != SizeFull) - return; - - // Load Restrictions - RestrictVersion = Data[0x000]; - RestrictLanguage = Data[0x1FF]; - - byte[] wcx = new byte[Size]; - Array.Copy(Data, SizeFull - Size, wcx, 0, wcx.Length); - Data = wcx; - - DateTime now = DateTime.Now; - RawDate = SetDate((uint) now.Year, (uint) now.Month, (uint) now.Day); - } + public WC7() : this(new byte[Size]) { } + public WC7(byte[] data) : base(data) { } public int RestrictLanguage { get; set; } // None public byte RestrictVersion { get; set; } // Permit All @@ -62,7 +44,7 @@ public override string CardTitle set => Encoding.Unicode.GetBytes(value.PadRight(36, '\0')).CopyTo(Data, 2); } - private uint RawDate + internal uint RawDate { get => BitConverter.ToUInt32(Data, 0x4C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x4C); @@ -86,7 +68,7 @@ private uint Day set => RawDate = SetDate(Year, Month, value); } - private static uint SetDate(uint year, uint month, uint day) => (Math.Max(0, year - 2000) * 10000) + (month * 100) + day; + public static uint SetDate(uint year, uint month, uint day) => (Math.Max(0, year - 2000) * 10000) + (month * 100) + day; /// /// Gets or sets the date of the card. @@ -282,7 +264,7 @@ public override int[] IVs get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; set { - if (value?.Length != 6) return; + if (value.Length != 6) return; IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; } @@ -293,7 +275,7 @@ public int[] EVs get => new[] { EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD }; set { - if (value?.Length != 6) return; + if (value.Length != 6) return; EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2]; EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5]; } @@ -329,7 +311,7 @@ public override int[] RelearnMoves public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) - return null; + throw new ArgumentException(nameof(IsPokémon)); int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1; int metLevel = MetLevel > 0 ? MetLevel : currentLevel; diff --git a/PKHeX.Core/MysteryGifts/WC7Full.cs b/PKHeX.Core/MysteryGifts/WC7Full.cs new file mode 100644 index 000000000..d9f82dfee --- /dev/null +++ b/PKHeX.Core/MysteryGifts/WC7Full.cs @@ -0,0 +1,26 @@ +using System; + +namespace PKHeX.Core +{ + public sealed class WC7Full + { + public const int Size = 0x310; + public readonly byte[] Data; + public readonly WC7 Gift; + + public byte RestrictVersion { get => Data[0]; set => Data[0] = value; } + public byte RestrictLanguage { get => Data[0x1FF]; set => Data[0x1FF] = value; } + + public WC7Full(byte[] data) + { + Data = data; + var wc7 = data.SliceEnd(Size - WC7.Size); + Gift = new WC7(wc7); + var now = DateTime.Now; + Gift.RawDate = WC7.SetDate((uint)now.Year, (uint)now.Month, (uint)now.Day); + + Gift.RestrictVersion = RestrictVersion; + Gift.RestrictLanguage = RestrictLanguage; + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/MysteryGifts/WR7.cs b/PKHeX.Core/MysteryGifts/WR7.cs index 91129fbe6..ec7f9e567 100644 --- a/PKHeX.Core/MysteryGifts/WR7.cs +++ b/PKHeX.Core/MysteryGifts/WR7.cs @@ -11,12 +11,12 @@ namespace PKHeX.Core /// A full is not stored in the structure, as it is immediately converted to upon receiving from server. /// The save file just stores a summary of the received data for the user to look back at. /// - public sealed class WR7 : MysteryGift + public sealed class WR7 : DataMysteryGift { public const int Size = 0x140; - public WR7() => Data = new byte[Size]; - public WR7(byte[] data) => Data = data; + public WR7() : this(new byte[Size]) { } + public WR7(byte[] data) : base(data) { } public uint Epoch { @@ -130,7 +130,7 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { // this method shouldn't really be called, use the WB7 data not the WR7 data. if (!IsPokémon) - return null; + throw new ArgumentException(nameof(IsPokémon)); // we'll just generate something as close as we can, since we must return something! var pk = new PB7(); diff --git a/PKHeX.Core/PKHeX.Core.csproj b/PKHeX.Core/PKHeX.Core.csproj index 268b97d92..81247bb18 100644 --- a/PKHeX.Core/PKHeX.Core.csproj +++ b/PKHeX.Core/PKHeX.Core.csproj @@ -11,6 +11,7 @@ https://github.com/kwsch/PKHeX 8 + enable diff --git a/PKHeX.Core/PKM/BK4.cs b/PKHeX.Core/PKM/BK4.cs index bce970018..979c9d1cf 100644 --- a/PKHeX.Core/PKM/BK4.cs +++ b/PKHeX.Core/PKM/BK4.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -11,7 +12,7 @@ public sealed class BK4 : _K4 0x42, 0x43, 0x5E, 0x63, 0x64, 0x65, 0x66, 0x67, 0x87 }; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; public override int SIZE_PARTY => PKX.SIZE_4STORED; public override int SIZE_STORED => PKX.SIZE_4STORED; @@ -22,9 +23,11 @@ public sealed class BK4 : _K4 public override bool Valid => ChecksumValid || (Sanity == 0 && Species <= MaxSpeciesID); - public BK4(byte[] decryptedData) + public override byte[] Data { get; } + + public BK4(byte[] data) { - Data = decryptedData; + Data = data; uint sv = ((PID & 0x3E000) >> 0xD) % 24; Data = PKX.ShuffleArray(Data, sv, PKX.SIZE_4BLOCK); if (Sanity != 0 && Species <= MaxSpeciesID && !ChecksumValid) // We can only hope diff --git a/PKHeX.Core/PKM/CK3.cs b/PKHeX.Core/PKM/CK3.cs index 4aee1b7ec..92a9f1c5b 100644 --- a/PKHeX.Core/PKM/CK3.cs +++ b/PKHeX.Core/PKM/CK3.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -14,14 +15,14 @@ public sealed class CK3 : _K3, IShadowPKM // 0xFC onwards unused? }; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; public override int SIZE_PARTY => PKX.SIZE_3CSTORED; public override int SIZE_STORED => PKX.SIZE_3CSTORED; public override int Format => 3; public override PersonalInfo PersonalInfo => PersonalTable.RS[Species]; - - public CK3(byte[] decryptedData) => Data = decryptedData; + public override byte[] Data { get; } + public CK3(byte[] data) => Data = data; public CK3() => Data = new byte[SIZE_PARTY]; public override PKM Clone() => new CK3((byte[])Data.Clone()) {Identifier = Identifier}; diff --git a/PKHeX.Core/PKM/PB7.cs b/PKHeX.Core/PKM/PB7.cs index a6a68226b..5b6591634 100644 --- a/PKHeX.Core/PKM/PB7.cs +++ b/PKHeX.Core/PKM/PB7.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.CompilerServices; namespace PKHeX.Core @@ -19,22 +20,22 @@ public sealed class PB7 : _K6, IHyperTrain, IAwakened 0xC8, 0xC9, // OT Terminator }; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; public override int SIZE_PARTY => SIZE; public override int SIZE_STORED => SIZE; private const int SIZE = 260; public override int Format => 7; public override PersonalInfo PersonalInfo => PersonalTable.GG.GetFormeEntry(Species, AltForm); - + public override byte[] Data { get; } public PB7() => Data = new byte[SIZE]; - public PB7(byte[] decryptedData) + public PB7(byte[] data) { - Data = decryptedData; - PKX.CheckEncrypted(ref Data, 7); - if (Data.Length != SIZE) - Array.Resize(ref Data, SIZE); + PKX.CheckEncrypted(ref data, 7); + if (data.Length != SIZE) + Array.Resize(ref data, SIZE); + Data = data; } public override PKM Clone() => new PB7((byte[])Data.Clone()){Identifier = Identifier}; diff --git a/PKHeX.Core/PKM/PK1.cs b/PKHeX.Core/PKM/PK1.cs index 23386a00c..79de3de9c 100644 --- a/PKHeX.Core/PKM/PK1.cs +++ b/PKHeX.Core/PKM/PK1.cs @@ -101,7 +101,7 @@ private void SetSpeciesValues(int value) public override int Version { get => (int)GameVersion.RBY; set { } } public override int PKRS_Strain { get => 0; set { } } public override int PKRS_Days { get => 0; set { } } - public override bool CanHoldItem(IList ValidArray) => false; + public override bool CanHoldItem(IReadOnlyList ValidArray) => false; // Maximums public override int MaxMoveID => Legal.MaxMoveID_1; diff --git a/PKHeX.Core/PKM/PK3.cs b/PKHeX.Core/PKM/PK3.cs index 8fad8b194..47c9806c7 100644 --- a/PKHeX.Core/PKM/PK3.cs +++ b/PKHeX.Core/PKM/PK3.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -15,16 +16,17 @@ public sealed class PK3 : _K3 public override int Format => 3; public override PersonalInfo PersonalInfo => PersonalTable.RS[Species]; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; + public override byte[] Data { get; } public PK3() => Data = new byte[PKX.SIZE_3PARTY]; - public PK3(byte[] decryptedData) + public PK3(byte[] data) { - Data = decryptedData; - PKX.CheckEncrypted(ref Data, Format); - if (Data.Length != SIZE_PARTY) - Array.Resize(ref Data, SIZE_PARTY); + PKX.CheckEncrypted(ref data, Format); + if (data.Length != PKX.SIZE_3PARTY) + Array.Resize(ref data, PKX.SIZE_3PARTY); + Data = data; } public override PKM Clone() diff --git a/PKHeX.Core/PKM/PK4.cs b/PKHeX.Core/PKM/PK4.cs index 0bfa5607a..339bc92a7 100644 --- a/PKHeX.Core/PKM/PK4.cs +++ b/PKHeX.Core/PKM/PK4.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; namespace PKHeX.Core @@ -11,21 +12,22 @@ public sealed class PK4 : _K4 0x42, 0x43, 0x5E, 0x63, 0x64, 0x65, 0x66, 0x67, 0x87 }; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; public override int SIZE_PARTY => PKX.SIZE_4PARTY; public override int SIZE_STORED => PKX.SIZE_4STORED; public override int Format => 4; public override PersonalInfo PersonalInfo => PersonalTable.HGSS.GetFormeEntry(Species, AltForm); + public override byte[] Data { get; } public PK4() => Data = new byte[PKX.SIZE_4PARTY]; - public PK4(byte[] decryptedData) + public PK4(byte[] data) { - Data = decryptedData; - PKX.CheckEncrypted(ref Data, Format); - if (Data.Length != SIZE_PARTY) - Array.Resize(ref Data, SIZE_PARTY); + PKX.CheckEncrypted(ref data, Format); + if (data.Length != PKX.SIZE_4PARTY) + Array.Resize(ref data, PKX.SIZE_4PARTY); + Data = data; } public override PKM Clone() => new PK4((byte[])Data.Clone()){Identifier = Identifier}; diff --git a/PKHeX.Core/PKM/PK5.cs b/PKHeX.Core/PKM/PK5.cs index cccc3d5d8..a330b6fd5 100644 --- a/PKHeX.Core/PKM/PK5.cs +++ b/PKHeX.Core/PKM/PK5.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; namespace PKHeX.Core @@ -17,21 +18,22 @@ public sealed class PK5 : PKM, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetUni 0x86, // unused }; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; public override int SIZE_PARTY => PKX.SIZE_5PARTY; public override int SIZE_STORED => PKX.SIZE_5STORED; public override int Format => 5; public override PersonalInfo PersonalInfo => PersonalTable.B2W2.GetFormeEntry(Species, AltForm); + public override byte[] Data { get; } public PK5() => Data = new byte[PKX.SIZE_5PARTY]; - public PK5(byte[] decryptedData) + public PK5(byte[] data) { - Data = decryptedData; - PKX.CheckEncrypted(ref Data, Format); - if (Data.Length != SIZE_PARTY) - Array.Resize(ref Data, SIZE_PARTY); + PKX.CheckEncrypted(ref data, Format); + if (data.Length != PKX.SIZE_5PARTY) + Array.Resize(ref data, PKX.SIZE_5PARTY); + Data = data; } public override PKM Clone() => new PK5((byte[])Data.Clone()){Identifier = Identifier}; diff --git a/PKHeX.Core/PKM/PK6.cs b/PKHeX.Core/PKM/PK6.cs index 51e35e4aa..1370cdf0c 100644 --- a/PKHeX.Core/PKM/PK6.cs +++ b/PKHeX.Core/PKM/PK6.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -11,18 +12,20 @@ public sealed class PK6 : _K6, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCom 0x58, 0x59, 0x73, 0x90, 0x91, 0x9E, 0x9F, 0xA0, 0xA1, 0xA7, 0xAA, 0xAB, 0xAC, 0xAD, 0xC8, 0xC9, 0xD7, 0xE4, 0xE5, 0xE6, 0xE7 }; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; public override int Format => 6; public override PersonalInfo PersonalInfo => PersonalTable.AO.GetFormeEntry(Species, AltForm); public PK6() => Data = new byte[PKX.SIZE_6PARTY]; - public PK6(byte[] decryptedData) + public override byte[] Data { get; } + + public PK6(byte[] data) { - Data = decryptedData; - PKX.CheckEncrypted(ref Data, Format); - if (Data.Length != SIZE_PARTY) - Array.Resize(ref Data, SIZE_PARTY); + PKX.CheckEncrypted(ref data, Format); + if (data.Length != PKX.SIZE_6PARTY) + Array.Resize(ref data, PKX.SIZE_6PARTY); + Data = data; } public override PKM Clone() => new PK6((byte[])Data.Clone()){Identifier = Identifier}; diff --git a/PKHeX.Core/PKM/PK7.cs b/PKHeX.Core/PKM/PK7.cs index e6472eef2..4f2885547 100644 --- a/PKHeX.Core/PKM/PK7.cs +++ b/PKHeX.Core/PKM/PK7.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -12,18 +13,20 @@ public sealed class PK7 : _K6, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCom 0x58, 0x59, 0x73, 0x90, 0x91, 0x9E, 0x9F, 0xA0, 0xA1, 0xA7, 0xAA, 0xAB, 0xAC, 0xAD, 0xC8, 0xC9, 0xD7, 0xE4, 0xE5, 0xE6, 0xE7 }; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; public override int Format => 7; public override PersonalInfo PersonalInfo => PersonalTable.USUM.GetFormeEntry(Species, AltForm); + public override byte[] Data { get; } + public PK7() => Data = new byte[PKX.SIZE_6PARTY]; - public PK7(byte[] decryptedData) + public PK7(byte[] data) { - Data = decryptedData; - PKX.CheckEncrypted(ref Data, Format); - if (Data.Length != SIZE_PARTY) - Array.Resize(ref Data, SIZE_PARTY); + PKX.CheckEncrypted(ref data, Format); + if (data.Length != PKX.SIZE_6PARTY) + Array.Resize(ref data, PKX.SIZE_6PARTY); + Data = data; } public override PKM Clone() => new PK7((byte[])Data.Clone()){Identifier = Identifier}; diff --git a/PKHeX.Core/PKM/PK8.cs b/PKHeX.Core/PKM/PK8.cs index 023fa7b9e..5d9585afd 100644 --- a/PKHeX.Core/PKM/PK8.cs +++ b/PKHeX.Core/PKM/PK8.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -9,18 +10,19 @@ public sealed class PK8 : _K6, IRibbonSetEvent3, IRibbonSetEvent4, IRibbonSetCom { }; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; public override int Format => 8; public override PersonalInfo PersonalInfo => PersonalTable.USUM.GetFormeEntry(Species, AltForm); + public override byte[] Data { get; } public PK8() => Data = new byte[PKX.SIZE_8PARTY]; - public PK8(byte[] decryptedData) + public PK8(byte[] data) { - Data = decryptedData; - PKX.CheckEncrypted(ref Data, Format); - if (Data.Length != SIZE_PARTY) - Array.Resize(ref Data, SIZE_PARTY); + PKX.CheckEncrypted(ref data, Format); + if (data.Length != PKX.SIZE_8PARTY) + Array.Resize(ref data, PKX.SIZE_8PARTY); + Data = data; } public override PKM Clone() => new PK8((byte[])Data.Clone()) { Identifier = Identifier }; diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index 904713de8..fad6669ba 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -14,11 +14,11 @@ public abstract class PKM : ITrainerID, ILangNick, IGameValueLimit public abstract int SIZE_STORED { get; } public string Extension => GetType().Name.ToLower(); public abstract PersonalInfo PersonalInfo { get; } - public abstract byte[] ExtraBytes { get; } + public abstract IReadOnlyList ExtraBytes { get; } // Internal Attributes set on creation - public byte[] Data; // Raw Storage - public string Identifier; // User or Form Custom Attribute + public abstract byte[] Data { get; } // Raw Storage + public string? Identifier; // User or Form Custom Attribute public int Box { get; set; } = -1; // Batch Editor public int Slot { get; set; } = -1; // Batch Editor @@ -39,7 +39,7 @@ private static byte[] Truncate(byte[] data, int newSize) // Trash Bytes public abstract byte[] Nickname_Trash { get; set; } public abstract byte[] OT_Trash { get; set; } - public virtual byte[] HT_Trash { get; set; } + public virtual byte[] HT_Trash { get; set; } = Array.Empty(); protected byte[] GetData(int Offset, int Length) => Data.Slice(Offset, Length); @@ -150,7 +150,7 @@ private byte[] Write() public virtual int Met_Year { get => 0; set { } } public virtual int Met_Month { get => 0; set { } } public virtual int Met_Day { get => 0; set { } } - public virtual string HT_Name { get; set; } + public virtual string HT_Name { get; set; } = string.Empty; public virtual int HT_Gender { get; set; } public virtual int HT_Affection { get; set; } public virtual int HT_Friendship { get; set; } @@ -404,7 +404,8 @@ public int[] IVs get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; set { - if (value?.Length != 6) return; + if (value.Length != 6) + return; IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; } @@ -415,7 +416,8 @@ public int[] EVs get => new[] { EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD }; set { - if (value?.Length != 6) return; + if (value.Length != 6) + return; EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2]; EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5]; } @@ -426,7 +428,7 @@ public int[] Stats get => new[] { Stat_HPCurrent, Stat_ATK, Stat_DEF, Stat_SPE, Stat_SPA, Stat_SPD }; set { - if (value?.Length != 6) + if (value.Length != 6) return; Stat_HPCurrent = value[0]; Stat_ATK = value[1]; Stat_DEF = value[2]; Stat_SPE = value[3]; Stat_SPA = value[4]; Stat_SPD = value[5]; @@ -861,7 +863,7 @@ public bool ForcePartyData() /// /// Items that the can hold. /// True/False if the can hold its . - public virtual bool CanHoldItem(IList ValidArray) => ValidArray.Contains((ushort)HeldItem); + public virtual bool CanHoldItem(IReadOnlyList ValidArray) => ValidArray.Contains((ushort)HeldItem); /// /// Deep clones the object. The clone will not have any shared resources with the source. diff --git a/PKHeX.Core/PKM/Searching/SearchSettings.cs b/PKHeX.Core/PKM/Searching/SearchSettings.cs index 1e470f2b1..9cfbc21ec 100644 --- a/PKHeX.Core/PKM/Searching/SearchSettings.cs +++ b/PKHeX.Core/PKM/Searching/SearchSettings.cs @@ -31,7 +31,7 @@ public sealed class SearchSettings public int EVType { private get; set; } public CloneDetectionMethod SearchClones { private get; set; } - public IList BatchInstructions { private get; set; } + public IList BatchInstructions { private get; set; } = Array.Empty(); public readonly List Moves = new List(); diff --git a/PKHeX.Core/PKM/Searching/SearchUtil.cs b/PKHeX.Core/PKM/Searching/SearchUtil.cs index 732a0ba87..8015b06a4 100644 --- a/PKHeX.Core/PKM/Searching/SearchUtil.cs +++ b/PKHeX.Core/PKM/Searching/SearchUtil.cs @@ -107,9 +107,8 @@ public static IEnumerable FilterByBatchInstruction(IEnumerable res, IL { return Clones switch { - CloneDetectionMethod.HashDetails => HashByDetails, CloneDetectionMethod.HashPID => HashByPID, - _ => (Func)null + _ => (Func)HashByDetails, }; } @@ -136,7 +135,7 @@ public static string HashByPID(PKM pk) public static IEnumerable GetClones(IEnumerable res, CloneDetectionMethod type = CloneDetectionMethod.HashDetails) { var method = GetCloneDetectMethod(type); - return method == null ? res : GetClones(res, method); + return GetClones(res, method); } public static IEnumerable GetClones(IEnumerable res, Func method) diff --git a/PKHeX.Core/PKM/Shared/IHyperTrain.cs b/PKHeX.Core/PKM/Shared/IHyperTrain.cs index 201ac4f0f..00199fe62 100644 --- a/PKHeX.Core/PKM/Shared/IHyperTrain.cs +++ b/PKHeX.Core/PKM/Shared/IHyperTrain.cs @@ -77,7 +77,7 @@ public static bool GetHT(this IHyperTrain pk, int index) /// /// /// to use (if already known). Will fetch the current if not provided. - public static void SetSuggestedHyperTrainingData(this PKM pkm, int[] IVs = null) + public static void SetSuggestedHyperTrainingData(this PKM pkm, int[]? IVs = null) { if (!(pkm is IHyperTrain t)) return; diff --git a/PKHeX.Core/PKM/Shared/PokeListGB.cs b/PKHeX.Core/PKM/Shared/PokeListGB.cs index 2a78fc8ce..a186435f7 100644 --- a/PKHeX.Core/PKM/Shared/PokeListGB.cs +++ b/PKHeX.Core/PKM/Shared/PokeListGB.cs @@ -14,7 +14,7 @@ public abstract class PokeListGB where T : PKM public byte Count { get => Data[0]; private set => Data[0] = value > Capacity ? Capacity : value; } - protected PokeListGB(byte[] d, PokeListType c = PokeListType.Single, bool jp = false) + protected PokeListGB(byte[]? d, PokeListType c = PokeListType.Single, bool jp = false) { Capacity = (byte)c; Entry_Size = GetEntrySize(); @@ -75,7 +75,8 @@ protected static int GetDataSize(PokeListType c, bool jp, int entrySize) } set { - if (value == null) return; + if (value == null) + return; Pokemon[i] = (T)value.Clone(); } } diff --git a/PKHeX.Core/PKM/Shared/_K12.cs b/PKHeX.Core/PKM/Shared/_K12.cs index f4306f778..40bee15ff 100644 --- a/PKHeX.Core/PKM/Shared/_K12.cs +++ b/PKHeX.Core/PKM/Shared/_K12.cs @@ -16,7 +16,7 @@ public abstract class _K12 : PKM public override int OTLength => Japanese ? 5 : 7; public override int NickLength => Japanese ? 5 : 10; - public override byte[] ExtraBytes => Array.Empty(); + public override IReadOnlyList ExtraBytes => Array.Empty(); public override string FileNameWithoutExtension { @@ -30,13 +30,13 @@ public override string FileNameWithoutExtension private int StringLength => Japanese ? STRLEN_J : STRLEN_U; public override bool Japanese => otname.Length == STRLEN_J; - - protected _K12(byte[] decryptedData, bool jp = false) + public override byte[] Data { get; } + protected _K12(byte[] data, bool jp = false) { int partySize = SIZE_PARTY; - Data = decryptedData; - if (Data.Length != partySize) - Array.Resize(ref Data, partySize); + if (data.Length != partySize) + Array.Resize(ref data, partySize); + Data = data; int strLen = jp ? STRLEN_J : STRLEN_U; // initialize string buffers @@ -62,7 +62,7 @@ protected _K12(byte[] decryptedData, bool jp = false) public override bool IsNicknamed { - get => (bool)(_isnicknamed ?? (_isnicknamed = !nick.SequenceEqual(GetNonNickname(GuessedLanguage())))); + get => _isnicknamed ??= !nick.SequenceEqual(GetNonNickname(GuessedLanguage())); set { _isnicknamed = value; diff --git a/PKHeX.Core/PKM/Shared/_K6.cs b/PKHeX.Core/PKM/Shared/_K6.cs index 87094ce3c..44a3770c5 100644 --- a/PKHeX.Core/PKM/Shared/_K6.cs +++ b/PKHeX.Core/PKM/Shared/_K6.cs @@ -5,14 +5,6 @@ namespace PKHeX.Core /// Generation 6 format. public abstract class _K6 : PKM { - private static readonly byte[] Unused = - { - 0x36, 0x37, // Unused Ribbons - 0x58, 0x59, 0x73, 0x90, 0x91, 0x9E, 0x9F, 0xA0, 0xA1, 0xA7, 0xAA, 0xAB, 0xAC, 0xAD, 0xC8, 0xC9, 0xD7, 0xE4, 0xE5, 0xE6, 0xE7 - }; - - public override byte[] ExtraBytes => Unused; - public override int SIZE_PARTY => PKX.SIZE_6PARTY; public override int SIZE_STORED => PKX.SIZE_6STORED; diff --git a/PKHeX.Core/PKM/Util/PKMConverter.cs b/PKHeX.Core/PKM/Util/PKMConverter.cs index b10b380f6..cc2da1c34 100644 --- a/PKHeX.Core/PKM/Util/PKMConverter.cs +++ b/PKHeX.Core/PKM/Util/PKMConverter.cs @@ -83,7 +83,7 @@ public static int GetPKMDataFormat(byte[] data) /// Raw data of the Pokemon file. /// Optional identifier for the preferred generation. Usually the generation of the destination save file. /// An instance of created from the given , or null if is invalid. - public static PKM GetPKMfromBytes(byte[] data, int prefer = 7) + public static PKM? GetPKMfromBytes(byte[] data, int prefer = 7) { int format = GetPKMDataFormat(data); switch (format) @@ -209,7 +209,7 @@ public static bool IsConvertibleToFormat(PKM pk, int format) /// Format/Type to convert to /// Comments regarding the transfer's success/failure /// Converted PKM - public static PKM ConvertToType(PKM pk, Type PKMType, out string comment) + public static PKM? ConvertToType(PKM pk, Type PKMType, out string comment) { if (pk == null) { @@ -237,7 +237,7 @@ public static PKM ConvertToType(PKM pk, Type PKMType, out string comment) return pkm; } - private static PKM ConvertPKM(PKM pk, Type PKMType, Type fromType, out string comment) + private static PKM? ConvertPKM(PKM pk, Type PKMType, Type fromType, out string comment) { if (IsNotTransferable(pk, out comment)) return null; @@ -254,9 +254,9 @@ private static PKM ConvertPKM(PKM pk, Type PKMType, Type fromType, out string co return pkm; } - private static PKM ConvertPKM(PKM pk, Type PKMType, int toFormat, ref string comment) + private static PKM? ConvertPKM(PKM pk, Type PKMType, int toFormat, ref string comment) { - PKM pkm = pk.Clone(); + PKM? pkm = pk.Clone(); if (pkm.IsEgg) pkm.ForceHatchPKM(); while (true) @@ -269,7 +269,7 @@ private static PKM ConvertPKM(PKM pk, Type PKMType, int toFormat, ref string com } } - private static PKM IntermediaryConvert(PKM pk, Type PKMType, int toFormat, ref string comment) + private static PKM? IntermediaryConvert(PKM pk, Type PKMType, int toFormat, ref string comment) { switch (pk) { @@ -318,7 +318,7 @@ private static bool IsNotTransferable(PKM pk, out string comment) switch (pk.Species) { default: - comment = null; + comment = string.Empty; return false; case 025 when pk.AltForm != 0 && pk.Gen6: // Cosplay Pikachu @@ -377,20 +377,27 @@ public static bool TryMakePKMCompatible(PKM pk, PKM target, out string c, out PK { if (!IsConvertibleToFormat(pk, target.Format)) { - pkm = null; + pkm = target; c = string.Format(MsgPKMConvertFailBackwards, pk.GetType().Name, target.Format); if (!AllowIncompatibleConversion) return false; } if (IsIncompatibleGB(target.Format, target.Japanese, pk.Japanese)) { - pkm = null; + pkm = target; c = GetIncompatibleGBMessage(pk, target.Japanese); return false; } - pkm = ConvertToType(pk, target.GetType(), out c); + var convert = ConvertToType(pk, target.GetType(), out c); + if (convert == null) + { + pkm = target; + return false; + } + + pkm = convert; Debug.WriteLine(c); - return pkm != null; + return true; } public static string GetIncompatibleGBMessage(PKM pk, bool destJP) diff --git a/PKHeX.Core/PKM/Util/QRMessageUtil.cs b/PKHeX.Core/PKM/Util/QRMessageUtil.cs index 358c8fbe5..dab85d0a7 100644 --- a/PKHeX.Core/PKM/Util/QRMessageUtil.cs +++ b/PKHeX.Core/PKM/Util/QRMessageUtil.cs @@ -20,7 +20,7 @@ public static class QRMessageUtil /// QR Message /// Preferred to expect. /// Decoded object, null if invalid. - public static PKM GetPKM(string message, int format) + public static PKM? GetPKM(string message, int format) { var pkdata = DecodeMessagePKM(message); if (pkdata == null) @@ -58,7 +58,7 @@ public static string GetMessage(PKM pkm) /// /// Gift data to encode /// QR Message - public static string GetMessage(MysteryGift mg) + public static string GetMessage(DataMysteryGift mg) { var server = GetExploitURLPrefixWC(mg.Format); var data = mg.Data; @@ -71,7 +71,7 @@ public static string GetMessageBase64(byte[] data, string server) return server + qrdata; } - private static byte[] DecodeMessagePKM(string message) + private static byte[]? DecodeMessagePKM(string message) { if (message.Length < 32) // arbitrary length check; everything should be greater than this return null; @@ -84,7 +84,7 @@ private static byte[] DecodeMessagePKM(string message) return null; } - private static byte[] DecodeMessageDataBase64(string url) + private static byte[]? DecodeMessageDataBase64(string url) { try { diff --git a/PKHeX.Core/PKM/XK3.cs b/PKHeX.Core/PKM/XK3.cs index c70242b0d..7250ae39a 100644 --- a/PKHeX.Core/PKM/XK3.cs +++ b/PKHeX.Core/PKM/XK3.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -13,14 +14,14 @@ public sealed class XK3 : _K3, IShadowPKM 0x7E, 0x7F }; - public override byte[] ExtraBytes => Unused; + public override IReadOnlyList ExtraBytes => Unused; public override int SIZE_PARTY => PKX.SIZE_3XSTORED; public override int SIZE_STORED => PKX.SIZE_3XSTORED; public override int Format => 3; public override PersonalInfo PersonalInfo => PersonalTable.RS[Species]; - - public XK3(byte[] decryptedData) => Data = decryptedData; + public override byte[] Data { get; } + public XK3(byte[] data) => Data = data; public XK3() => Data = new byte[SIZE_PARTY]; public override PKM Clone() => new XK3((byte[])Data.Clone()){Identifier = Identifier, Purification = Purification}; diff --git a/PKHeX.Core/PersonalInfo/PersonalInfo.cs b/PKHeX.Core/PersonalInfo/PersonalInfo.cs index 383611c11..831a74621 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfo.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfo.cs @@ -10,7 +10,9 @@ public abstract class PersonalInfo /// /// Raw Data /// - protected byte[] Data; + protected readonly byte[] Data; + + protected PersonalInfo(byte[] data) => Data = data; /// /// Writes entry to raw bytes. @@ -226,12 +228,12 @@ public int[] EggGroups /// /// TM/HM learn compatibility flags for individual moves. /// - public bool[] TMHM { get; protected set; } + public bool[] TMHM { get; protected set; } = Array.Empty(); /// /// Grass-Fire-Water-Etc typed learn compatibility flags for individual moves. /// - public bool[] TypeTutors { get; protected set; } + public bool[] TypeTutors { get; protected set; } = Array.Empty(); /// /// Special tutor learn compatibility flags for individual moves. diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoB2W2.cs b/PKHeX.Core/PersonalInfo/PersonalInfoB2W2.cs index 48fb25d5e..f1cebd1c5 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoB2W2.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoB2W2.cs @@ -7,12 +7,8 @@ public sealed class PersonalInfoB2W2 : PersonalInfoBW { public new const int SIZE = 0x4C; - public PersonalInfoB2W2(byte[] data) + public PersonalInfoB2W2(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - Data = data; - // Unpack TMHM & Tutors TMHM = GetBits(Data, 0x28, 0x10); TypeTutors = GetBits(Data, 0x38, 0x4); diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoBW.cs b/PKHeX.Core/PersonalInfo/PersonalInfoBW.cs index 8e1d711b7..527b36dbc 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoBW.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoBW.cs @@ -7,15 +7,10 @@ namespace PKHeX.Core /// public class PersonalInfoBW : PersonalInfo { - protected PersonalInfoBW() { } public const int SIZE = 0x3C; - public PersonalInfoBW(byte[] data) + public PersonalInfoBW(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - Data = data; - // Unpack TMHM & Tutors TMHM = GetBits(Data, 0x28, 0x10); TypeTutors = GetBits(Data, 0x38, 0x4); diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoG1.cs b/PKHeX.Core/PersonalInfo/PersonalInfoG1.cs index 0e2a85dd1..bafe6b1c3 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoG1.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoG1.cs @@ -7,12 +7,8 @@ public sealed class PersonalInfoG1 : PersonalInfo { public const int SIZE = 0x1C; - public PersonalInfoG1(byte[] data) + public PersonalInfoG1(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - - Data = data; TMHM = GetBits(Data, 0x14, 0x8); } diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoG2.cs b/PKHeX.Core/PersonalInfo/PersonalInfoG2.cs index 0630682df..1cec203de 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoG2.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoG2.cs @@ -7,12 +7,8 @@ public sealed class PersonalInfoG2 : PersonalInfo { public const int SIZE = 0x20; - public PersonalInfoG2(byte[] data) + public PersonalInfoG2(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - - Data = data; TMHM = GetBits(Data, 0x18, 0x8); } diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoG3.cs b/PKHeX.Core/PersonalInfo/PersonalInfoG3.cs index b4a04b7dd..e0afe2b23 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoG3.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoG3.cs @@ -7,15 +7,10 @@ namespace PKHeX.Core /// public class PersonalInfoG3 : PersonalInfo { - protected PersonalInfoG3() { } public const int SIZE = 0x1C; - public PersonalInfoG3(byte[] data) + public PersonalInfoG3(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - - Data = data; } public override byte[] Write() => Data; diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoG4.cs b/PKHeX.Core/PersonalInfo/PersonalInfoG4.cs index 00f472bec..c36ea84bb 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoG4.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoG4.cs @@ -9,12 +9,8 @@ public sealed class PersonalInfoG4 : PersonalInfoG3 { public new const int SIZE = 0x2C; - public PersonalInfoG4(byte[] data) + public PersonalInfoG4(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - Data = data; - // Unpack TMHM & Tutors TMHM = GetBits(Data, 0x1C, 0x0D); TypeTutors = Array.Empty(); // not stored in personal diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoGG.cs b/PKHeX.Core/PersonalInfo/PersonalInfoGG.cs index 14249c039..254c7d053 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoGG.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoGG.cs @@ -7,12 +7,8 @@ namespace PKHeX.Core /// public class PersonalInfoGG : PersonalInfoSM { - public PersonalInfoGG(byte[] data) + public PersonalInfoGG(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - Data = data; - TMHM = GetBits(Data, 0x28, 8); // only 60 TMs used TypeTutors = GetBits(Data, 0x38, 1); // at most 8 flags used } diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoORAS.cs b/PKHeX.Core/PersonalInfo/PersonalInfoORAS.cs index f07119b37..c709a17aa 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoORAS.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoORAS.cs @@ -7,12 +7,8 @@ public sealed class PersonalInfoORAS : PersonalInfoXY { public new const int SIZE = 0x50; - public PersonalInfoORAS(byte[] data) + public PersonalInfoORAS(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - Data = data; - // Unpack TMHM & Tutors TMHM = GetBits(Data, 0x28, 0x10); TypeTutors = GetBits(Data, 0x38, 0x4); diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoSM.cs b/PKHeX.Core/PersonalInfo/PersonalInfoSM.cs index 0709bc7f6..336c644df 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoSM.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoSM.cs @@ -7,15 +7,10 @@ namespace PKHeX.Core /// public class PersonalInfoSM : PersonalInfoXY { - protected PersonalInfoSM() { } // For GG public new const int SIZE = 0x54; - public PersonalInfoSM(byte[] data) + public PersonalInfoSM(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - Data = data; - TMHM = GetBits(Data, 0x28, 0x10); // 36-39 TypeTutors = GetBits(Data, 0x38, 0x4); // 40 diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoSWSH.cs b/PKHeX.Core/PersonalInfo/PersonalInfoSWSH.cs index 421b8aa11..525b8edb1 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoSWSH.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoSWSH.cs @@ -10,12 +10,8 @@ public sealed class PersonalInfoSWSH : PersonalInfoSM public new const int SIZE = PersonalInfoSM.SIZE; // todo: this is a copy of lgpe class - public PersonalInfoSWSH(byte[] data) + public PersonalInfoSWSH(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - Data = data; - TMHM = GetBits(Data, 0x28, 8); // only 60 TMs used TypeTutors = GetBits(Data, 0x38, 1); // at most 8 flags used } diff --git a/PKHeX.Core/PersonalInfo/PersonalInfoXY.cs b/PKHeX.Core/PersonalInfo/PersonalInfoXY.cs index edab1dc0c..f07bffcb3 100644 --- a/PKHeX.Core/PersonalInfo/PersonalInfoXY.cs +++ b/PKHeX.Core/PersonalInfo/PersonalInfoXY.cs @@ -5,15 +5,10 @@ /// public class PersonalInfoXY : PersonalInfoBW { - protected PersonalInfoXY() { } // For ORAS public new const int SIZE = 0x40; - public PersonalInfoXY(byte[] data) + public PersonalInfoXY(byte[] data) : base(data) { - if (data.Length != SIZE) - return; - Data = data; - // Unpack TMHM & Tutors TMHM = GetBits(Data, 0x28, 0x10); TypeTutors = GetBits(Data, 0x38, 0x4); diff --git a/PKHeX.Core/Resources/byte/eggmove_uu.pkl b/PKHeX.Core/Resources/byte/eggmove_uu.pkl index 8f9fb0178..4e6ace27f 100644 Binary files a/PKHeX.Core/Resources/byte/eggmove_uu.pkl and b/PKHeX.Core/Resources/byte/eggmove_uu.pkl differ diff --git a/PKHeX.Core/Ribbons/IRibbonSetCommon3.cs b/PKHeX.Core/Ribbons/IRibbonSetCommon3.cs index 68ff21178..36997af17 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetCommon3.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetCommon3.cs @@ -17,8 +17,6 @@ internal static partial class RibbonExtensions internal static bool[] RibbonBits(this IRibbonSetCommon3 set) { - if (set == null) - return new bool[3]; return new[] { set.RibbonChampionG3Hoenn, diff --git a/PKHeX.Core/Ribbons/IRibbonSetCommon4.cs b/PKHeX.Core/Ribbons/IRibbonSetCommon4.cs index ac9fa28cf..192f611fe 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetCommon4.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetCommon4.cs @@ -28,8 +28,6 @@ internal static partial class RibbonExtensions internal static bool[] RibbonBitsCosmetic(this IRibbonSetCommon4 set) { - if (set == null) - return new bool[3]; return new[] { set.RibbonGorgeous, @@ -47,8 +45,6 @@ internal static bool[] RibbonBitsCosmetic(this IRibbonSetCommon4 set) internal static bool[] RibbonBitsOnly(this IRibbonSetCommon4 set) { - if (set == null) - return new bool[3]; return new[] { set.RibbonRecord, @@ -68,8 +64,6 @@ internal static bool[] RibbonBitsOnly(this IRibbonSetCommon4 set) internal static bool[] RibbonBitsDaily(this IRibbonSetCommon4 set) { - if (set == null) - return new bool[7]; return new[] { set.RibbonAlert, diff --git a/PKHeX.Core/Ribbons/IRibbonSetCommon6.cs b/PKHeX.Core/Ribbons/IRibbonSetCommon6.cs index 8dfbd54c4..0ecc4d96a 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetCommon6.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetCommon6.cs @@ -40,8 +40,6 @@ internal static partial class RibbonExtensions internal static bool[] RibbonBits(this IRibbonSetCommon6 set) { - if (set == null) - return new bool[11]; return new[] { set.RibbonChampionKalos, @@ -62,8 +60,6 @@ internal static bool[] RibbonBits(this IRibbonSetCommon6 set) internal static bool[] RibbonBitsContest(this IRibbonSetCommon6 set) { - if (set == null) - return new bool[5]; return new[] { set.RibbonMasterCoolness, diff --git a/PKHeX.Core/Ribbons/IRibbonSetCommon7.cs b/PKHeX.Core/Ribbons/IRibbonSetCommon7.cs index 8c954b58b..f04612178 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetCommon7.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetCommon7.cs @@ -19,8 +19,6 @@ internal static partial class RibbonExtensions internal static bool[] RibbonBits(this IRibbonSetCommon7 set) { - if (set == null) - return new bool[4]; return new[] { set.RibbonChampionAlola, diff --git a/PKHeX.Core/Ribbons/IRibbonSetEvent3.cs b/PKHeX.Core/Ribbons/IRibbonSetEvent3.cs index b009dec41..3a4953ded 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetEvent3.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetEvent3.cs @@ -21,8 +21,6 @@ internal static partial class RibbonExtensions internal static bool[] RibbonBits(this IRibbonSetEvent3 set) { - if (set == null) - return new bool[6]; return new[] { set.RibbonEarth, diff --git a/PKHeX.Core/Ribbons/IRibbonSetEvent4.cs b/PKHeX.Core/Ribbons/IRibbonSetEvent4.cs index f17802a15..b34e50b87 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetEvent4.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetEvent4.cs @@ -25,8 +25,6 @@ internal static partial class RibbonExtensions internal static bool[] RibbonBits(this IRibbonSetEvent4 set) { - if (set == null) - return new bool[9]; return new[] { set.RibbonClassic, diff --git a/PKHeX.Core/Ribbons/IRibbonSetOnly3.cs b/PKHeX.Core/Ribbons/IRibbonSetOnly3.cs index 7e2cc0f8a..8d756f8c3 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetOnly3.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetOnly3.cs @@ -30,8 +30,6 @@ internal static partial class RibbonExtensions internal static int[] RibbonCounts(this IRibbonSetOnly3 set) { - if (set == null) - return new int[5]; return new[] { set.RibbonCountG3Cool, diff --git a/PKHeX.Core/Ribbons/IRibbonSetUnique3.cs b/PKHeX.Core/Ribbons/IRibbonSetUnique3.cs index fb290f135..ae2e03c64 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetUnique3.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetUnique3.cs @@ -19,8 +19,6 @@ internal static partial class RibbonExtensions internal static bool[] RibbonBits(this IRibbonSetUnique3 set) { - if (set == null) - return new bool[2]; return new[] { set.RibbonWinning, diff --git a/PKHeX.Core/Ribbons/IRibbonSetUnique4.cs b/PKHeX.Core/Ribbons/IRibbonSetUnique4.cs index 5825e44e2..74193b1bd 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetUnique4.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetUnique4.cs @@ -115,8 +115,6 @@ internal static partial class RibbonExtensions internal static bool[] RibbonBitsAbility(this IRibbonSetUnique4 set) { - if (set == null) - return new bool[6]; return new[] { set.RibbonAbility, @@ -130,9 +128,6 @@ internal static bool[] RibbonBitsAbility(this IRibbonSetUnique4 set) internal static bool[] RibbonBitsContest3(this IRibbonSetUnique4 set) { - if (set == null) - return new bool[20]; - return new[] { set.RibbonG3Cool, @@ -164,9 +159,6 @@ internal static bool[] RibbonBitsContest3(this IRibbonSetUnique4 set) internal static bool[] RibbonBitsContest4(this IRibbonSetUnique4 set) { - if (set == null) - return new bool[20]; - return new[] { set.RibbonG4Cool, diff --git a/PKHeX.Core/Ribbons/RibbonInfo.cs b/PKHeX.Core/Ribbons/RibbonInfo.cs index 8478fb9d3..a860ccb20 100644 --- a/PKHeX.Core/Ribbons/RibbonInfo.cs +++ b/PKHeX.Core/Ribbons/RibbonInfo.cs @@ -44,7 +44,7 @@ public static IReadOnlyList GetRibbonInfo(PKM pkm) var names = ReflectUtil.GetPropertiesStartWithPrefix(pkm.GetType(), "Ribbon"); foreach (var name in names) { - object RibbonValue = ReflectUtil.GetValue(pkm, name); + object? RibbonValue = ReflectUtil.GetValue(pkm, name); if (RibbonValue is int x) riblist.Add(new RibbonInfo(name, x)); if (RibbonValue is bool b) diff --git a/PKHeX.Core/Saves/Access/ISaveBlock5BW.cs b/PKHeX.Core/Saves/Access/ISaveBlock5BW.cs new file mode 100644 index 000000000..a0acc177a --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock5BW.cs @@ -0,0 +1,14 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock5BW + { + MyItem Items { get; } + Zukan5 Zukan { get; } + Misc5 MiscBlock { get; } + MysteryBlock5 MysteryBlock { get; } + Daycare5 DaycareBlock { get; } + BoxLayout5 BoxLayout { get; } + PlayerData5 PlayerData { get; } + BattleSubway5 BattleSubwayBlock { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlock6AO.cs b/PKHeX.Core/Saves/Access/ISaveBlock6AO.cs new file mode 100644 index 000000000..81bcd057b --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock6AO.cs @@ -0,0 +1,8 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock6AO : ISaveBlock6Main + { + Misc6AO Misc { get; } + Zukan6AO Zukan { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlock6Core.cs b/PKHeX.Core/Saves/Access/ISaveBlock6Core.cs new file mode 100644 index 000000000..90b2a42e9 --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock6Core.cs @@ -0,0 +1,13 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock6Core + { + MyItem Items { get; } + ItemInfo6 ItemInfo { get; } + GameTime6 GameTime { get; } + Situation6 Situation { get; } + PlayTime6 Played { get; } + MyStatus6 Status { get; } + Record6 Records { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlock6Main.cs b/PKHeX.Core/Saves/Access/ISaveBlock6Main.cs new file mode 100644 index 000000000..1f304cf93 --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock6Main.cs @@ -0,0 +1,9 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock6Main : ISaveBlock6Core, IPokePuff, IOPower, ILink + { + BoxLayout6 BoxLayout { get; } + BattleBox6 BattleBoxBlock { get; } + MysteryBlock6 MysteryBlock { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlock6XY.cs b/PKHeX.Core/Saves/Access/ISaveBlock6XY.cs new file mode 100644 index 000000000..985a53672 --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock6XY.cs @@ -0,0 +1,9 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock6XY : ISaveBlock6Main + { + Misc6XY Misc { get; } + Zukan6XY Zukan { get; } + Fashion6XY Fashion6XY { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlock7Main.cs b/PKHeX.Core/Saves/Access/ISaveBlock7Main.cs new file mode 100644 index 000000000..93156798f --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock7Main.cs @@ -0,0 +1,25 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock7Main + { + MyItem Items { get; } + MysteryBlock7 MysteryBlock { get; } + PokeFinder7 PokeFinder { get; } + JoinFesta7 Festa { get; } + Daycare7 DaycareBlock { get; } + Record6 Records { get; } + PlayTime6 Played { get; } + MyStatus7 MyStatus { get; } + FieldMoveModelSave7 OverworldBlock { get; } + Situation7 Situation { get; } + ConfigSave7 Config { get; } + GameTime7 GameTime { get; } + Misc7 MiscBlock { get; } + Zukan7 Zukan { get; } + BoxLayout7 BoxLayout { get; } + BattleTree7 BattleTreeBlock { get; } + ResortSave7 ResortSave { get; } + FieldMenu7 FieldMenu { get; } + FashionBlock7 FashionBlock { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlock7SM.cs b/PKHeX.Core/Saves/Access/ISaveBlock7SM.cs new file mode 100644 index 000000000..95a131b0a --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock7SM.cs @@ -0,0 +1,6 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock7SM : ISaveBlock7Main + { + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlock7USUM.cs b/PKHeX.Core/Saves/Access/ISaveBlock7USUM.cs new file mode 100644 index 000000000..c89f34168 --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock7USUM.cs @@ -0,0 +1,8 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock7USUM : ISaveBlock7Main + { + // BattleFesSave + // FinderStudioSave + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlock8Main.cs b/PKHeX.Core/Saves/Access/ISaveBlock8Main.cs new file mode 100644 index 000000000..08b8b9ef1 --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock8Main.cs @@ -0,0 +1,18 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock8Main + { + MyItem Items { get; } + Record8 Records { get; } + PlayTime8 Played { get; } + MyStatus8 MyStatus { get; } + ConfigSave8 Config { get; } + GameTime8 GameTime { get; } + Misc8 MiscBlock { get; } + Zukan8 Zukan { get; } + EventWork8 EventWork { get; } + BoxLayout8 BoxLayout { get; } + Situation8 Situation { get; } + FieldMoveModelSave8 OverworldBlock { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlock8SWSH.cs b/PKHeX.Core/Saves/Access/ISaveBlock8SWSH.cs new file mode 100644 index 000000000..7d04e8d11 --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlock8SWSH.cs @@ -0,0 +1,6 @@ +namespace PKHeX.Core +{ + public interface ISaveBlock8SWSH : ISaveBlock8Main + { + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/ISaveBlockAccessor.cs b/PKHeX.Core/Saves/Access/ISaveBlockAccessor.cs new file mode 100644 index 000000000..322a212a8 --- /dev/null +++ b/PKHeX.Core/Saves/Access/ISaveBlockAccessor.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public interface ISaveBlockAccessor where T : BlockInfo + { + IReadOnlyList BlockInfo { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessor5B2W2.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessor5B2W2.cs new file mode 100644 index 000000000..7b50ef521 --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessor5B2W2.cs @@ -0,0 +1,115 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public class SaveBlockAccessor5B2W2 : ISaveBlock5BW, ISaveBlock5B2W2 + { + public static readonly BlockInfoNDS[] BlocksB2W2 = + { + new BlockInfoNDS(0x00000, 0x03e0, 0x003E2, 0x25F00), // 00 Box Names + new BlockInfoNDS(0x00400, 0x0ff0, 0x013F2, 0x25F02), // 01 Box 1 + new BlockInfoNDS(0x01400, 0x0ff0, 0x023F2, 0x25F04), // 02 Box 2 + new BlockInfoNDS(0x02400, 0x0ff0, 0x033F2, 0x25F06), // 03 Box 3 + new BlockInfoNDS(0x03400, 0x0ff0, 0x043F2, 0x25F08), // 04 Box 4 + new BlockInfoNDS(0x04400, 0x0ff0, 0x053F2, 0x25F0A), // 05 Box 5 + new BlockInfoNDS(0x05400, 0x0ff0, 0x063F2, 0x25F0C), // 06 Box 6 + new BlockInfoNDS(0x06400, 0x0ff0, 0x073F2, 0x25F0E), // 07 Box 7 + new BlockInfoNDS(0x07400, 0x0ff0, 0x083F2, 0x25F10), // 08 Box 8 + new BlockInfoNDS(0x08400, 0x0ff0, 0x093F2, 0x25F12), // 09 Box 9 + new BlockInfoNDS(0x09400, 0x0ff0, 0x0A3F2, 0x25F14), // 10 Box 10 + new BlockInfoNDS(0x0A400, 0x0ff0, 0x0B3F2, 0x25F16), // 11 Box 11 + new BlockInfoNDS(0x0B400, 0x0ff0, 0x0C3F2, 0x25F18), // 12 Box 12 + new BlockInfoNDS(0x0C400, 0x0ff0, 0x0D3F2, 0x25F1A), // 13 Box 13 + new BlockInfoNDS(0x0D400, 0x0ff0, 0x0E3F2, 0x25F1C), // 14 Box 14 + new BlockInfoNDS(0x0E400, 0x0ff0, 0x0F3F2, 0x25F1E), // 15 Box 15 + new BlockInfoNDS(0x0F400, 0x0ff0, 0x103F2, 0x25F20), // 16 Box 16 + new BlockInfoNDS(0x10400, 0x0ff0, 0x113F2, 0x25F22), // 17 Box 17 + new BlockInfoNDS(0x11400, 0x0ff0, 0x123F2, 0x25F24), // 18 Box 18 + new BlockInfoNDS(0x12400, 0x0ff0, 0x133F2, 0x25F26), // 19 Box 19 + new BlockInfoNDS(0x13400, 0x0ff0, 0x143F2, 0x25F28), // 20 Box 20 + new BlockInfoNDS(0x14400, 0x0ff0, 0x153F2, 0x25F2A), // 21 Box 21 + new BlockInfoNDS(0x15400, 0x0ff0, 0x163F2, 0x25F2C), // 22 Box 22 + new BlockInfoNDS(0x16400, 0x0ff0, 0x173F2, 0x25F2E), // 23 Box 23 + new BlockInfoNDS(0x17400, 0x0ff0, 0x183F2, 0x25F30), // 24 Box 24 + new BlockInfoNDS(0x18400, 0x09ec, 0x18DEE, 0x25F32), // 25 Inventory + new BlockInfoNDS(0x18E00, 0x0534, 0x19336, 0x25F34), // 26 Party Pokemon + new BlockInfoNDS(0x19400, 0x00b0, 0x194B2, 0x25F36), // 27 Trainer Data + new BlockInfoNDS(0x19500, 0x00a8, 0x195AA, 0x25F38), // 28 Trainer Position + new BlockInfoNDS(0x19600, 0x1338, 0x1A93A, 0x25F3A), // 29 Unity Tower and survey stuff + new BlockInfoNDS(0x1AA00, 0x07c4, 0x1B1C6, 0x25F3C), // 30 Pal Pad Player Data + new BlockInfoNDS(0x1B200, 0x0d54, 0x1BF56, 0x25F3E), // 31 Pal Pad Friend Data + new BlockInfoNDS(0x1C000, 0x0094, 0x1C096, 0x25F40), // 32 Options / Skin Info + new BlockInfoNDS(0x1C100, 0x0658, 0x1C75A, 0x25F42), // 33 Trainer Card + new BlockInfoNDS(0x1C800, 0x0a94, 0x1D296, 0x25F44), // 34 Mystery Gift + new BlockInfoNDS(0x1D300, 0x01ac, 0x1D4AE, 0x25F46), // 35 Dream World Stuff (Catalog) + new BlockInfoNDS(0x1D500, 0x03ec, 0x1D8EE, 0x25F48), // 36 Chatter + new BlockInfoNDS(0x1D900, 0x005c, 0x1D95E, 0x25F4A), // 37 Adventure data + new BlockInfoNDS(0x1DA00, 0x01e0, 0x1DBE2, 0x25F4C), // 38 Record + new BlockInfoNDS(0x1DC00, 0x00a8, 0x1DCAA, 0x25F4E), // 39 ??? + new BlockInfoNDS(0x1DD00, 0x0460, 0x1E162, 0x25F50), // 40 Mail + new BlockInfoNDS(0x1E200, 0x1400, 0x1F602, 0x25F52), // 41 ??? + new BlockInfoNDS(0x1F700, 0x02a4, 0x1F9A6, 0x25F54), // 42 Musical + new BlockInfoNDS(0x1FA00, 0x00e0, 0x1FAE2, 0x25F56), // 43 Fused Reshiram/Zekrom Storage + new BlockInfoNDS(0x1FB00, 0x034c, 0x1FE4E, 0x25F58), // 44 IR + new BlockInfoNDS(0x1FF00, 0x04e0, 0x203E2, 0x25F5A), // 45 EventWork + new BlockInfoNDS(0x20400, 0x00f8, 0x204FA, 0x25F5C), // 46 ??? + new BlockInfoNDS(0x20500, 0x02fc, 0x207FE, 0x25F5E), // 47 Regulation + new BlockInfoNDS(0x20800, 0x0094, 0x20896, 0x25F60), // 48 Gimmick + new BlockInfoNDS(0x20900, 0x035c, 0x20C5E, 0x25F62), // 49 Battle Box + new BlockInfoNDS(0x20D00, 0x01d4, 0x20ED6, 0x25F64), // 50 Daycare + new BlockInfoNDS(0x20F00, 0x01e0, 0x210E2, 0x25F66), // 51 Strength Boulder Status Block + new BlockInfoNDS(0x21100, 0x00f0, 0x211F2, 0x25F68), // 52 Misc (Badge Flags, Money, Trainer Sayings) + new BlockInfoNDS(0x21200, 0x01b4, 0x213B6, 0x25F6A), // 53 Entralink (Level & Powers etc) + new BlockInfoNDS(0x21400, 0x04dc, 0x218DE, 0x25F6C), // 54 Pokedex + new BlockInfoNDS(0x21900, 0x0034, 0x21936, + 0x25F6E), // 55 Encount (Swarm and other overworld info - 2C - swarm, 2D - repel steps, 2E repel type) + new BlockInfoNDS(0x21A00, 0x003c, 0x21A3E, 0x25F70), // 56 Battle Subway Play Info + new BlockInfoNDS(0x21B00, 0x01ac, 0x21CAE, 0x25F72), // 57 Battle Subway Score Info + new BlockInfoNDS(0x21D00, 0x0b90, 0x22892, 0x25F74), // 58 Battle Subway WiFI Info + new BlockInfoNDS(0x22900, 0x00ac, 0x229AE, 0x25F76), // 59 Online Records + new BlockInfoNDS(0x22A00, 0x0850, 0x23252, 0x25F78), // 60 Entralink Forest pokémon data + new BlockInfoNDS(0x23300, 0x0284, 0x23586, 0x25F7A), // 61 ??? + new BlockInfoNDS(0x23600, 0x0010, 0x23612, 0x25F7C), // 62 ??? + new BlockInfoNDS(0x23700, 0x00a8, 0x237AA, 0x25F7E), // 63 PWT related data + new BlockInfoNDS(0x23800, 0x016c, 0x2396E, 0x25F80), // 64 ??? + new BlockInfoNDS(0x23A00, 0x0080, 0x23A82, 0x25F82), // 65 ??? + new BlockInfoNDS(0x23B00, 0x00fc, 0x23BFE, 0x25F84), // 66 Hollow/Rival Block + new BlockInfoNDS(0x23C00, 0x16a8, 0x252AA, 0x25F86), // 67 Join Avenue Block + new BlockInfoNDS(0x25300, 0x0498, 0x2579A, 0x25F88), // 68 Medal + new BlockInfoNDS(0x25800, 0x0060, 0x25862, 0x25F8A), // 69 Key-related data + new BlockInfoNDS(0x25900, 0x00fc, 0x259FE, 0x25F8C), // 70 Festa Missions + new BlockInfoNDS(0x25A00, 0x03e4, 0x25DE6, 0x25F8E), // 71 ??? + new BlockInfoNDS(0x25E00, 0x00f0, 0x25EF2, 0x25F90), // 72 ??? + new BlockInfoNDS(0x25F00, 0x0094, 0x25FA2, 0x25FA2), // 73 Checksum Block + }; + + public SaveBlockAccessor5B2W2(SAV5B2W2 sav) + { + BoxLayout = new BoxLayout5(sav, 0x00000); + Items = new MyItem5B2W2(sav, 0x18400); + PlayerData = new PlayerData5(sav, 0x19400); + MysteryBlock = new MysteryBlock5(sav, 0x1C800); + DaycareBlock = new Daycare5(sav, 0x20D00); + MiscBlock = new Misc5(sav, 0x21100); + Zukan = new Zukan5(sav, 0x21400, 0x328); // forme flags size is + 8 from bw with new formes (therians) + BattleSubwayBlock = new BattleSubway5(sav, 0x21B00); + PWTBlock = new PWTBlock5(sav, 0x23700); + } + + public IReadOnlyList BlockInfo => BlocksB2W2; + public MyItem Items { get; } + public Zukan5 Zukan { get; } + public Misc5 MiscBlock { get; } + public MysteryBlock5 MysteryBlock { get; } + public Daycare5 DaycareBlock { get; } + public BoxLayout5 BoxLayout { get; } + public PlayerData5 PlayerData { get; } + public BattleSubway5 BattleSubwayBlock { get; } + public PWTBlock5 PWTBlock { get; } + } + + public interface ISaveBlock5B2W2 + { + PWTBlock5 PWTBlock { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessor5BW.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessor5BW.cs new file mode 100644 index 000000000..18269b3f4 --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessor5BW.cs @@ -0,0 +1,104 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public class SaveBlockAccessor5BW : ISaveBlockAccessor, ISaveBlock5BW + { + // Offset, Length, chkOffset, ChkMirror + public static readonly BlockInfoNDS[] BlocksBW = + { + new BlockInfoNDS(0x00000, 0x03E0, 0x003E2, 0x23F00), // 00 Box Names + new BlockInfoNDS(0x00400, 0x0FF0, 0x013F2, 0x23F02), // 01 Box 1 + new BlockInfoNDS(0x01400, 0x0FF0, 0x023F2, 0x23F04), // 02 Box 2 + new BlockInfoNDS(0x02400, 0x0FF0, 0x033F2, 0x23F06), // 03 Box 3 + new BlockInfoNDS(0x03400, 0x0FF0, 0x043F2, 0x23F08), // 04 Box 4 + new BlockInfoNDS(0x04400, 0x0FF0, 0x053F2, 0x23F0A), // 05 Box 5 + new BlockInfoNDS(0x05400, 0x0FF0, 0x063F2, 0x23F0C), // 06 Box 6 + new BlockInfoNDS(0x06400, 0x0FF0, 0x073F2, 0x23F0E), // 07 Box 7 + new BlockInfoNDS(0x07400, 0x0FF0, 0x083F2, 0x23F10), // 08 Box 8 + new BlockInfoNDS(0x08400, 0x0FF0, 0x093F2, 0x23F12), // 09 Box 9 + new BlockInfoNDS(0x09400, 0x0FF0, 0x0A3F2, 0x23F14), // 10 Box 10 + new BlockInfoNDS(0x0A400, 0x0FF0, 0x0B3F2, 0x23F16), // 11 Box 11 + new BlockInfoNDS(0x0B400, 0x0FF0, 0x0C3F2, 0x23F18), // 12 Box 12 + new BlockInfoNDS(0x0C400, 0x0FF0, 0x0D3F2, 0x23F1A), // 13 Box 13 + new BlockInfoNDS(0x0D400, 0x0FF0, 0x0E3F2, 0x23F1C), // 14 Box 14 + new BlockInfoNDS(0x0E400, 0x0FF0, 0x0F3F2, 0x23F1E), // 15 Box 15 + new BlockInfoNDS(0x0F400, 0x0FF0, 0x103F2, 0x23F20), // 16 Box 16 + new BlockInfoNDS(0x10400, 0x0FF0, 0x113F2, 0x23F22), // 17 Box 17 + new BlockInfoNDS(0x11400, 0x0FF0, 0x123F2, 0x23F24), // 18 Box 18 + new BlockInfoNDS(0x12400, 0x0FF0, 0x133F2, 0x23F26), // 19 Box 19 + new BlockInfoNDS(0x13400, 0x0FF0, 0x143F2, 0x23F28), // 20 Box 20 + new BlockInfoNDS(0x14400, 0x0FF0, 0x153F2, 0x23F2A), // 21 Box 21 + new BlockInfoNDS(0x15400, 0x0FF0, 0x163F2, 0x23F2C), // 22 Box 22 + new BlockInfoNDS(0x16400, 0x0FF0, 0x173F2, 0x23F2E), // 23 Box 23 + new BlockInfoNDS(0x17400, 0x0FF0, 0x183F2, 0x23F30), // 24 Box 24 + new BlockInfoNDS(0x18400, 0x09C0, 0x18DC2, 0x23F32), // 25 Inventory + new BlockInfoNDS(0x18E00, 0x0534, 0x19336, 0x23F34), // 26 Party Pokemon + new BlockInfoNDS(0x19400, 0x0068, 0x1946A, 0x23F36), // 27 Trainer Data + new BlockInfoNDS(0x19500, 0x009C, 0x1959E, 0x23F38), // 28 Trainer Position + new BlockInfoNDS(0x19600, 0x1338, 0x1A93A, 0x23F3A), // 29 Unity Tower and survey stuff + new BlockInfoNDS(0x1AA00, 0x07C4, 0x1B1C6, 0x23F3C), // 30 Pal Pad Player Data + new BlockInfoNDS(0x1B200, 0x0D54, 0x1BF56, 0x23F3E), // 31 Pal Pad Friend Data + new BlockInfoNDS(0x1C000, 0x002C, 0x1C02E, 0x23F40), // 32 Skin Info + new BlockInfoNDS(0x1C100, 0x0658, 0x1C75A, 0x23F42), // 33 ??? Gym badge data + new BlockInfoNDS(0x1C800, 0x0A94, 0x1D296, 0x23F44), // 34 Mystery Gift + new BlockInfoNDS(0x1D300, 0x01AC, 0x1D4AE, 0x23F46), // 35 Dream World Stuff (Catalog) + new BlockInfoNDS(0x1D500, 0x03EC, 0x1D8EE, 0x23F48), // 36 Chatter + new BlockInfoNDS(0x1D900, 0x005C, 0x1D95E, 0x23F4A), // 37 Adventure Info + new BlockInfoNDS(0x1DA00, 0x01E0, 0x1DBE2, 0x23F4C), // 38 Trainer Card Records + new BlockInfoNDS(0x1DC00, 0x00A8, 0x1DCAA, 0x23F4E), // 39 ??? + new BlockInfoNDS(0x1DD00, 0x0460, 0x1E162, 0x23F50), // 40 ??? + new BlockInfoNDS(0x1E200, 0x1400, 0x1F602, 0x23F52), // 41 ??? + new BlockInfoNDS(0x1F700, 0x02A4, 0x1F9A6, 0x23F54), // 42 Contains flags and references for downloaded data (Musical) + new BlockInfoNDS(0x1FA00, 0x02DC, 0x1FCDE, 0x23F56), // 43 ??? + new BlockInfoNDS(0x1FD00, 0x034C, 0x2004E, 0x23F58), // 44 ??? + new BlockInfoNDS(0x20100, 0x03EC, 0x204EE, 0x23F5A), // 45 ??? + new BlockInfoNDS(0x20500, 0x00F8, 0x205FA, 0x23F5C), // 46 ??? + new BlockInfoNDS(0x20600, 0x02FC, 0x208FE, 0x23F5E), // 47 Tournament Block + new BlockInfoNDS(0x20900, 0x0094, 0x20996, 0x23F60), // 48 ??? + new BlockInfoNDS(0x20A00, 0x035C, 0x20D5E, 0x23F62), // 49 Battle Box Block + new BlockInfoNDS(0x20E00, 0x01CC, 0x20FCE, 0x23F64), // 50 Daycare Block + new BlockInfoNDS(0x21000, 0x0168, 0x2116A, 0x23F66), // 51 Strength Boulder Status Block + new BlockInfoNDS(0x21200, 0x00EC, 0x212EE, 0x23F68), // 52 Badge Flags, Money, Trainer Sayings + new BlockInfoNDS(0x21300, 0x01B0, 0x214B2, 0x23F6A), // 53 Entralink (Level & Powers etc) + new BlockInfoNDS(0x21500, 0x001C, 0x2151E, 0x23F6C), // 54 ??? + new BlockInfoNDS(0x21600, 0x04D4, 0x21AD6, 0x23F6E), // 55 Pokedex + new BlockInfoNDS(0x21B00, 0x0034, 0x21B36, 0x23F70), // 56 Swarm and other overworld info - 2C - swarm, 2D - repel steps, 2E repel type + new BlockInfoNDS(0x21C00, 0x003C, 0x21C3E, 0x23F72), // 57 ??? + new BlockInfoNDS(0x21D00, 0x01AC, 0x21EAE, 0x23F74), // 58 Battle Subway + new BlockInfoNDS(0x21F00, 0x0B90, 0x22A92, 0x23F76), // 59 ??? + new BlockInfoNDS(0x22B00, 0x009C, 0x22B9E, 0x23F78), // 60 Online Records + new BlockInfoNDS(0x22C00, 0x0850, 0x23452, 0x23F7A), // 61 Entralink Forest pokémon data + new BlockInfoNDS(0x23500, 0x0028, 0x2352A, 0x23F7C), // 62 ??? + new BlockInfoNDS(0x23600, 0x0284, 0x23886, 0x23F7E), // 63 ??? + new BlockInfoNDS(0x23900, 0x0010, 0x23912, 0x23F80), // 64 ??? + new BlockInfoNDS(0x23A00, 0x005C, 0x23A5E, 0x23F82), // 65 ??? + new BlockInfoNDS(0x23B00, 0x016C, 0x23C6E, 0x23F84), // 66 ??? + new BlockInfoNDS(0x23D00, 0x0040, 0x23D42, 0x23F86), // 67 ??? + new BlockInfoNDS(0x23E00, 0x00FC, 0x23EFE, 0x23F88), // 68 ??? + new BlockInfoNDS(0x23F00, 0x008C, 0x23F9A, 0x23F9A), // 69 Checksums */ + }; + + public SaveBlockAccessor5BW(SAV5BW sav) + { + BoxLayout = new BoxLayout5(sav, 0x00000); + Items = new MyItem5BW(sav, 0x18400); + PlayerData = new PlayerData5(sav, 0x19400); + MysteryBlock = new MysteryBlock5(sav, 0x1C800); + DaycareBlock = new Daycare5(sav, 0x20E00); + MiscBlock = new Misc5(sav, 0x21200); + Zukan = new Zukan5(sav, 0x21600, 0x320); + BattleSubwayBlock = new BattleSubway5(sav, 0x21D00); + } + + public IReadOnlyList BlockInfo => BlocksBW; + public MyItem Items { get; } + public Zukan5 Zukan { get; } + public Misc5 MiscBlock { get; } + public MysteryBlock5 MysteryBlock { get; } + public Daycare5 DaycareBlock { get; } + public BoxLayout5 BoxLayout { get; } + public PlayerData5 PlayerData { get; } + public BattleSubway5 BattleSubwayBlock { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessor7SM.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessor7SM.cs new file mode 100644 index 000000000..4a0046899 --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessor7SM.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public sealed class SaveBlockAccessor7SM : ISaveBlockAccessor, ISaveBlock7SM + { + public const int boSM = SaveUtil.SIZE_G7SM - 0x200; + + private static readonly BlockInfo7[] BlockInfoSM = + { + new BlockInfo7(boSM, 00, 0x00000, 0x00DE0), // 00 MyItem + new BlockInfo7(boSM, 01, 0x00E00, 0x0007C), // 01 Situation + new BlockInfo7(boSM, 02, 0x01000, 0x00014), // 02 RandomGroup + new BlockInfo7(boSM, 03, 0x01200, 0x000C0), // 03 MyStatus + new BlockInfo7(boSM, 04, 0x01400, 0x0061C), // 04 PokePartySave + new BlockInfo7(boSM, 05, 0x01C00, 0x00E00), // 05 EventWork + new BlockInfo7(boSM, 06, 0x02A00, 0x00F78), // 06 ZukanData + new BlockInfo7(boSM, 07, 0x03A00, 0x00228), // 07 GtsData + new BlockInfo7(boSM, 08, 0x03E00, 0x00104), // 08 UnionPokemon + new BlockInfo7(boSM, 09, 0x04000, 0x00200), // 09 Misc + new BlockInfo7(boSM, 10, 0x04200, 0x00020), // 10 FieldMenu + new BlockInfo7(boSM, 11, 0x04400, 0x00004), // 11 ConfigSave + new BlockInfo7(boSM, 12, 0x04600, 0x00058), // 12 GameTime + new BlockInfo7(boSM, 13, 0x04800, 0x005E6), // 13 BOX + new BlockInfo7(boSM, 14, 0x04E00, 0x36600), // 14 BoxPokemon + new BlockInfo7(boSM, 15, 0x3B400, 0x0572C), // 15 ResortSave + new BlockInfo7(boSM, 16, 0x40C00, 0x00008), // 16 PlayTime + new BlockInfo7(boSM, 17, 0x40E00, 0x01080), // 17 FieldMoveModelSave + new BlockInfo7(boSM, 18, 0x42000, 0x01A08), // 18 Fashion + new BlockInfo7(boSM, 19, 0x43C00, 0x06408), // 19 JoinFestaPersonalSave + new BlockInfo7(boSM, 20, 0x4A200, 0x06408), // 20 JoinFestaPersonalSave + new BlockInfo7(boSM, 21, 0x50800, 0x03998), // 21 JoinFestaDataSave + new BlockInfo7(boSM, 22, 0x54200, 0x00100), // 22 BerrySpot + new BlockInfo7(boSM, 23, 0x54400, 0x00100), // 23 FishingSpot + new BlockInfo7(boSM, 24, 0x54600, 0x10528), // 24 LiveMatchData + new BlockInfo7(boSM, 25, 0x64C00, 0x00204), // 25 BattleSpotData + new BlockInfo7(boSM, 26, 0x65000, 0x00B60), // 26 PokeFinderSave + new BlockInfo7(boSM, 27, 0x65C00, 0x03F50), // 27 MysteryGiftSave + new BlockInfo7(boSM, 28, 0x69C00, 0x00358), // 28 Record + new BlockInfo7(boSM, 29, 0x6A000, 0x00728), // 29 ValidationSave + new BlockInfo7(boSM, 30, 0x6A800, 0x00200), // 30 GameSyncSave + new BlockInfo7(boSM, 31, 0x6AA00, 0x00718), // 31 PokeDiarySave + new BlockInfo7(boSM, 32, 0x6B200, 0x001FC), // 32 BattleInstSave + new BlockInfo7(boSM, 33, 0x6B400, 0x00200), // 33 Sodateya + new BlockInfo7(boSM, 34, 0x6B600, 0x00120), // 34 WeatherSave + new BlockInfo7(boSM, 35, 0x6B800, 0x001C8), // 35 QRReaderSaveData + new BlockInfo7(boSM, 36, 0x6BA00, 0x00200), // 36 TurtleSalmonSave + }; + + public SaveBlockAccessor7SM(SAV7SM sav) + { + var bi = BlockInfo; + + Items = new MyItem7SM(sav, 0); + Situation = new Situation7(sav, bi[01].Offset); + MyStatus = new MyStatus7(sav, bi[03].Offset); + Zukan = new Zukan7(sav, bi[06].Offset, 0x550); + MiscBlock = new Misc7(sav, bi[09].Offset); + FieldMenu = new FieldMenu7(sav, bi[10].Offset); + Config = new ConfigSave7(sav, bi[11].Offset); + GameTime = new GameTime7(sav, bi[12].Offset); + BoxLayout = new BoxLayout7(sav, bi[13].Offset); + ResortSave = new ResortSave7(sav, bi[15].Offset); + Played = new PlayTime6(sav, bi[16].Offset); + OverworldBlock = new FieldMoveModelSave7(sav, bi[17].Offset); + FashionBlock = new FashionBlock7(sav, bi[18].Offset); + Festa = new JoinFesta7(sav, bi[21].Offset); + PokeFinder = new PokeFinder7(sav, bi[26].Offset); + MysteryBlock = new MysteryBlock7(sav, bi[27].Offset); + Records = new Record6(sav, bi[28].Offset); + BattleTreeBlock = new BattleTree7(sav, bi[32].Offset); + DaycareBlock = new Daycare7(sav, bi[33].Offset); + } + + public IReadOnlyList BlockInfo => BlockInfoSM; + + public MyItem Items { get; } + public MysteryBlock7 MysteryBlock { get; } + public PokeFinder7 PokeFinder { get; } + public JoinFesta7 Festa { get; } + public Daycare7 DaycareBlock { get; } + public Record6 Records { get; } + public PlayTime6 Played { get; } + public MyStatus7 MyStatus { get; } + public FieldMoveModelSave7 OverworldBlock { get; } + public Situation7 Situation { get; } + public ConfigSave7 Config { get; } + public GameTime7 GameTime { get; } + public Misc7 MiscBlock { get; } + public Zukan7 Zukan { get; } + public BoxLayout7 BoxLayout { get; } + public BattleTree7 BattleTreeBlock { get; } + public ResortSave7 ResortSave { get; } + public FieldMenu7 FieldMenu { get; } + public FashionBlock7 FashionBlock { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessor7USUM.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessor7USUM.cs new file mode 100644 index 000000000..19d9416dd --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessor7USUM.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public sealed class SaveBlockAccessor7USUM : ISaveBlock7USUM + { + public const int boUU = SaveUtil.SIZE_G7USUM - 0x200; + + private static readonly BlockInfo7[] BlockInfoUSUM = + { + new BlockInfo7(boUU, 00, 0x00000, 0x00E28), // 00 MyItem + new BlockInfo7(boUU, 01, 0x01000, 0x0007C), // 01 Situation + new BlockInfo7(boUU, 02, 0x01200, 0x00014), // 02 RandomGroup + new BlockInfo7(boUU, 03, 0x01400, 0x000C0), // 03 MyStatus + new BlockInfo7(boUU, 04, 0x01600, 0x0061C), // 04 PokePartySave + new BlockInfo7(boUU, 05, 0x01E00, 0x00E00), // 05 EventWork + new BlockInfo7(boUU, 06, 0x02C00, 0x00F78), // 06 ZukanData + new BlockInfo7(boUU, 07, 0x03C00, 0x00228), // 07 GtsData + new BlockInfo7(boUU, 08, 0x04000, 0x0030C), // 08 UnionPokemon + new BlockInfo7(boUU, 09, 0x04400, 0x001FC), // 09 Misc + new BlockInfo7(boUU, 10, 0x04600, 0x0004C), // 10 FieldMenu + new BlockInfo7(boUU, 11, 0x04800, 0x00004), // 11 ConfigSave + new BlockInfo7(boUU, 12, 0x04A00, 0x00058), // 12 GameTime + new BlockInfo7(boUU, 13, 0x04C00, 0x005E6), // 13 BOX + new BlockInfo7(boUU, 14, 0x05200, 0x36600), // 14 BoxPokemon + new BlockInfo7(boUU, 15, 0x3B800, 0x0572C), // 15 ResortSave + new BlockInfo7(boUU, 16, 0x41000, 0x00008), // 16 PlayTime + new BlockInfo7(boUU, 17, 0x41200, 0x01218), // 17 FieldMoveModelSave + new BlockInfo7(boUU, 18, 0x42600, 0x01A08), // 18 Fashion + new BlockInfo7(boUU, 19, 0x44200, 0x06408), // 19 JoinFestaPersonalSave + new BlockInfo7(boUU, 20, 0x4A800, 0x06408), // 20 JoinFestaPersonalSave + new BlockInfo7(boUU, 21, 0x50E00, 0x03998), // 21 JoinFestaDataSave + new BlockInfo7(boUU, 22, 0x54800, 0x00100), // 22 BerrySpot + new BlockInfo7(boUU, 23, 0x54A00, 0x00100), // 23 FishingSpot + new BlockInfo7(boUU, 24, 0x54C00, 0x10528), // 24 LiveMatchData + new BlockInfo7(boUU, 25, 0x65200, 0x00204), // 25 BattleSpotData + new BlockInfo7(boUU, 26, 0x65600, 0x00B60), // 26 PokeFinderSave + new BlockInfo7(boUU, 27, 0x66200, 0x03F50), // 27 MysteryGiftSave + new BlockInfo7(boUU, 28, 0x6A200, 0x00358), // 28 Record + new BlockInfo7(boUU, 29, 0x6A600, 0x00728), // 29 ValidationSave + new BlockInfo7(boUU, 30, 0x6AE00, 0x00200), // 30 GameSyncSave + new BlockInfo7(boUU, 31, 0x6B000, 0x00718), // 31 PokeDiarySave + new BlockInfo7(boUU, 32, 0x6B800, 0x001FC), // 32 BattleInstSave + new BlockInfo7(boUU, 33, 0x6BA00, 0x00200), // 33 Sodateya + new BlockInfo7(boUU, 34, 0x6BC00, 0x00120), // 34 WeatherSave + new BlockInfo7(boUU, 35, 0x6BE00, 0x001C8), // 35 QRReaderSaveData + new BlockInfo7(boUU, 36, 0x6C000, 0x00200), // 36 TurtleSalmonSave + new BlockInfo7(boUU, 37, 0x6C200, 0x0039C), // 37 BattleFesSave + new BlockInfo7(boUU, 38, 0x6C600, 0x00400), // 38 FinderStudioSave + }; + + public SaveBlockAccessor7USUM(SAV7USUM sav) + { + var bi = BlockInfo; + + Items = new MyItem7USUM(sav, 0); + Situation = new Situation7(sav, bi[01].Offset); + MyStatus = new MyStatus7(sav, bi[03].Offset); + Zukan = new Zukan7(sav, bi[06].Offset, 0x550); + MiscBlock = new Misc7(sav, bi[09].Offset); + FieldMenu = new FieldMenu7(sav, bi[10].Offset); + Config = new ConfigSave7(sav, bi[11].Offset); + GameTime = new GameTime7(sav, bi[12].Offset); + BoxLayout = new BoxLayout7(sav, bi[13].Offset); + ResortSave = new ResortSave7(sav, bi[15].Offset); + Played = new PlayTime6(sav, bi[16].Offset); + OverworldBlock = new FieldMoveModelSave7(sav, bi[17].Offset); + FashionBlock = new FashionBlock7(sav, bi[18].Offset); + Festa = new JoinFesta7(sav, bi[21].Offset); + PokeFinder = new PokeFinder7(sav, bi[26].Offset); + MysteryBlock = new MysteryBlock7(sav, bi[27].Offset); + Records = new Record6(sav, bi[28].Offset); + BattleTreeBlock = new BattleTree7(sav, bi[32].Offset); + DaycareBlock = new Daycare7(sav, bi[33].Offset); + } + + public IReadOnlyList BlockInfo => BlockInfoUSUM; + + public MyItem Items { get; } + public MysteryBlock7 MysteryBlock { get; } + public PokeFinder7 PokeFinder { get; } + public JoinFesta7 Festa { get; } + public Daycare7 DaycareBlock { get; } + public Record6 Records { get; } + public PlayTime6 Played { get; } + public MyStatus7 MyStatus { get; } + public FieldMoveModelSave7 OverworldBlock { get; } + public Situation7 Situation { get; } + public ConfigSave7 Config { get; } + public GameTime7 GameTime { get; } + public Misc7 MiscBlock { get; } + public Zukan7 Zukan { get; } + public BoxLayout7 BoxLayout { get; } + public BattleTree7 BattleTreeBlock { get; } + public ResortSave7 ResortSave { get; } + public FieldMenu7 FieldMenu { get; } + public FashionBlock7 FashionBlock { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessor7b.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessor7b.cs new file mode 100644 index 000000000..390b13236 --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessor7b.cs @@ -0,0 +1,61 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public class SaveBlockAccessor7b : ISaveBlockAccessor + { + private const int boGG = 0xB8800 - 0x200; // nowhere near 1MB (savedata.bin size) + + private static readonly BlockInfo7b[] BlockInfoGG = + { + new BlockInfo7b(boGG, 00, 0x00000, 0x00D90), + new BlockInfo7b(boGG, 01, 0x00E00, 0x00200), + new BlockInfo7b(boGG, 02, 0x01000, 0x00168), + new BlockInfo7b(boGG, 03, 0x01200, 0x01800), + new BlockInfo7b(boGG, 04, 0x02A00, 0x020E8), + new BlockInfo7b(boGG, 05, 0x04C00, 0x00930), + new BlockInfo7b(boGG, 06, 0x05600, 0x00004), + new BlockInfo7b(boGG, 07, 0x05800, 0x00130), + new BlockInfo7b(boGG, 08, 0x05A00, 0x00012), + new BlockInfo7b(boGG, 09, 0x05C00, 0x3F7A0), + new BlockInfo7b(boGG, 10, 0x45400, 0x00008), + new BlockInfo7b(boGG, 11, 0x45600, 0x00E90), + new BlockInfo7b(boGG, 12, 0x46600, 0x010A4), + new BlockInfo7b(boGG, 13, 0x47800, 0x000F0), + new BlockInfo7b(boGG, 14, 0x47A00, 0x06010), + new BlockInfo7b(boGG, 15, 0x4DC00, 0x00200), + new BlockInfo7b(boGG, 16, 0x4DE00, 0x00098), + new BlockInfo7b(boGG, 17, 0x4E000, 0x00068), + new BlockInfo7b(boGG, 18, 0x4E200, 0x69780), + new BlockInfo7b(boGG, 19, 0xB7A00, 0x000B0), + new BlockInfo7b(boGG, 20, 0xB7C00, 0x00940), + }; + + public IReadOnlyList BlockInfo => BlockInfoGG; + + public SaveBlockAccessor7b(SAV7b sav) + { + Zukan = new Zukan7b(sav, GetBlockOffset(BelugaBlockIndex.Zukan), 0x550); + Config = new ConfigSave7b(sav, GetBlockOffset(BelugaBlockIndex.ConfigSave)); + Items = new MyItem7b(sav, GetBlockOffset(BelugaBlockIndex.MyItem)); + Storage = new PokeListHeader(sav, GetBlockOffset(BelugaBlockIndex.PokeListHeader)); + Status = new MyStatus7b(sav, GetBlockOffset(BelugaBlockIndex.MyStatus)); + Played = new PlayTime7b(sav, GetBlockOffset(BelugaBlockIndex.PlayTime)); + Misc = new Misc7b(sav, GetBlockOffset(BelugaBlockIndex.Misc)); + EventWork = new EventWork7b(sav, GetBlockOffset(BelugaBlockIndex.EventWork)); + GiftRecords = new WB7Records(sav, GetBlockOffset(BelugaBlockIndex.WB7Record)); + } + + public readonly MyItem Items; + public readonly Misc7b Misc; + public readonly Zukan7b Zukan; + public readonly MyStatus7b Status; + public readonly PlayTime7b Played; + public readonly ConfigSave7b Config; + public readonly EventWork7b EventWork; + public readonly PokeListHeader Storage; + public readonly WB7Records GiftRecords; + public BlockInfo GetBlock(BelugaBlockIndex index) => BlockInfo[(int)index]; + public int GetBlockOffset(BelugaBlockIndex index) => GetBlock(index).Offset; + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessorAO.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessorAO.cs new file mode 100644 index 000000000..fd20e4775 --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessorAO.cs @@ -0,0 +1,110 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public class SaveBlockAccessorAO : ISaveBlockAccessor, ISaveBlock6Main + { + public const int boAO = SaveUtil.SIZE_G6ORAS - 0x200; + + public static readonly BlockInfo6[] BlocksAO = + { + new BlockInfo6(boAO, 00, 0x00000, 0x002C8), // 00 Puff + new BlockInfo6(boAO, 01, 0x00400, 0x00B90), // 01 MyItem + new BlockInfo6(boAO, 02, 0x01000, 0x0002C), // 02 ItemInfo (Select Bound Items) + new BlockInfo6(boAO, 03, 0x01200, 0x00038), // 03 GameTime + new BlockInfo6(boAO, 04, 0x01400, 0x00150), // 04 Situation + new BlockInfo6(boAO, 05, 0x01600, 0x00004), // 05 RandomGroup (rand seeds) + new BlockInfo6(boAO, 06, 0x01800, 0x00008), // 06 PlayTime + new BlockInfo6(boAO, 07, 0x01A00, 0x001C0), // 07 Fashion + new BlockInfo6(boAO, 08, 0x01C00, 0x000BE), // 08 Amie minigame records + new BlockInfo6(boAO, 09, 0x01E00, 0x00024), // 09 temp variables (u32 id + 32 u8) + new BlockInfo6(boAO, 10, 0x02000, 0x02100), // 10 FieldMoveModelSave + new BlockInfo6(boAO, 11, 0x04200, 0x00130), // 11 Misc + new BlockInfo6(boAO, 12, 0x04400, 0x00440), // 12 BOX + new BlockInfo6(boAO, 13, 0x04A00, 0x00574), // 13 BattleBox + new BlockInfo6(boAO, 14, 0x05000, 0x04E28), // 14 PSS1 + new BlockInfo6(boAO, 15, 0x0A000, 0x04E28), // 15 PSS2 + new BlockInfo6(boAO, 16, 0x0F000, 0x04E28), // 16 PSS3 + new BlockInfo6(boAO, 17, 0x14000, 0x00170), // 17 MyStatus + new BlockInfo6(boAO, 18, 0x14200, 0x0061C), // 18 PokePartySave + new BlockInfo6(boAO, 19, 0x14A00, 0x00504), // 19 EventWork + new BlockInfo6(boAO, 20, 0x15000, 0x011CC), // 20 ZukanData + new BlockInfo6(boAO, 21, 0x16200, 0x00644), // 21 hologram clips + new BlockInfo6(boAO, 22, 0x16A00, 0x00104), // 22 UnionPokemon + new BlockInfo6(boAO, 23, 0x16C00, 0x00004), // 23 ConfigSave + new BlockInfo6(boAO, 24, 0x16E00, 0x00420), // 24 Amie decoration stuff + new BlockInfo6(boAO, 25, 0x17400, 0x00064), // 25 OPower = 0x17400; + new BlockInfo6(boAO, 26, 0x17600, 0x003F0), // 26 Strength Rock position (xyz float: 84 entries, 12bytes/entry) + new BlockInfo6(boAO, 27, 0x17A00, 0x0070C), // 27 Trainer PR Video + new BlockInfo6(boAO, 28, 0x18200, 0x00180), // 28 GtsData + new BlockInfo6(boAO, 29, 0x18400, 0x00004), // 29 Packed Menu Bits + new BlockInfo6(boAO, 30, 0x18600, 0x0000C), // 30 PSS Profile Q&A (6*questions, 6*answer) + new BlockInfo6(boAO, 31, 0x18800, 0x00048), // 31 Repel Info, (Swarm?) and other overworld info (roamer) + new BlockInfo6(boAO, 32, 0x18A00, 0x00054), // 32 BOSS data fetch history (serial/mystery gift), 4byte intro & 20*4byte entries + new BlockInfo6(boAO, 33, 0x18C00, 0x00644), // 33 Streetpass history + new BlockInfo6(boAO, 34, 0x19400, 0x005C8), // 34 LiveMatchData/BattleSpotData + new BlockInfo6(boAO, 35, 0x19A00, 0x002F8), // 35 MAC Address & Network Connection Logging (0x98 per entry, 5 entries) + new BlockInfo6(boAO, 36, 0x19E00, 0x01B40), // 36 Dendou (Hall of Fame) + new BlockInfo6(boAO, 37, 0x1BA00, 0x001F4), // 37 BattleInstSave (Maison) + new BlockInfo6(boAO, 38, 0x1BC00, 0x003E0), // 38 Sodateya (Daycare) + new BlockInfo6(boAO, 39, 0x1C000, 0x00216), // 39 BattleInstSave + new BlockInfo6(boAO, 40, 0x1C400, 0x00640), // 40 BerryField + new BlockInfo6(boAO, 41, 0x1CC00, 0x01A90), // 41 MysteryGiftSave + new BlockInfo6(boAO, 42, 0x1E800, 0x00400), // 42 Storyline Records + new BlockInfo6(boAO, 43, 0x1EC00, 0x00618), // 43 PokeDiarySave + new BlockInfo6(boAO, 44, 0x1F400, 0x0025C), // 44 Record + new BlockInfo6(boAO, 45, 0x1F800, 0x00834), // 45 Friend Safari (0x15 per entry, 100 entries) + new BlockInfo6(boAO, 46, 0x20200, 0x00318), // 46 SuperTrain + new BlockInfo6(boAO, 47, 0x20600, 0x007D0), // 47 Unused (lmao) + new BlockInfo6(boAO, 48, 0x20E00, 0x00C48), // 48 LinkInfo + new BlockInfo6(boAO, 49, 0x21C00, 0x00078), // 49 PSS usage info + new BlockInfo6(boAO, 50, 0x21E00, 0x00200), // 50 GameSyncSave + new BlockInfo6(boAO, 51, 0x22000, 0x00C84), // 51 PSS Icon (bool32 data present, 40x40 u16 pic, unused) + new BlockInfo6(boAO, 52, 0x22E00, 0x00628), // 52 ValidationSave (updatabale Public Key for legal check api calls) + new BlockInfo6(boAO, 53, 0x23600, 0x00400), // 53 Contest + new BlockInfo6(boAO, 54, 0x23A00, 0x07AD0), // 54 SecretBase + new BlockInfo6(boAO, 55, 0x2B600, 0x078B0), // 55 EonTicket + new BlockInfo6(boAO, 56, 0x33000, 0x34AD0), // 56 Box + new BlockInfo6(boAO, 57, 0x67C00, 0x0E058), // 57 JPEG + }; + + public IReadOnlyList BlockInfo => BlocksAO; + public MyItem Items { get; } + public ItemInfo6 ItemInfo { get; } + public GameTime6 GameTime { get; } + public Situation6 Situation { get; } + public PlayTime6 Played { get; } + public MyStatus6 Status { get; } + public Record6 Records { get; } + + public Zukan6AO Zukan { get; } + public Puff6 PuffBlock { get; } + public BoxLayout6 BoxLayout { get; } + public BattleBox6 BattleBoxBlock { get; } + public OPower6 OPowerBlock { get; } + public MysteryBlock6 MysteryBlock { get; } + public SangoInfoBlock Sango { get; } + public Link6 LinkBlock { get; } + public Misc6AO Misc { get; } + + public SaveBlockAccessorAO(SAV6AO sav) + { + PuffBlock = new Puff6(sav, 0x0000); + Items = new MyItem6AO(sav, 0x00400); + ItemInfo = new ItemInfo6(sav, 0x1000); + GameTime = new GameTime6(sav, 0x01200); + Situation = new Situation6(sav, 0x01400); + Played = new PlayTime6(sav, 0x01800); + Misc = new Misc6AO(sav, 0x04200); + BoxLayout = new BoxLayout6(sav, 0x04400); + BattleBoxBlock = new BattleBox6(sav, 0x04A00); + Status = new MyStatus6(sav, 0x14000); + Zukan = new Zukan6AO(sav, 0x15000, 0x400); + OPowerBlock = new OPower6(sav, 0x17400); + MysteryBlock = new MysteryBlock6(sav, 0x1CC00); + Records = new Record6(sav, 0x1F400); + Sango = new SangoInfoBlock(sav, 0x2B600); + LinkBlock = new Link6(sav, 0x20E00); + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessorAODemo.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessorAODemo.cs new file mode 100644 index 000000000..3c3b7dc47 --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessorAODemo.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public class SaveBlockAccessorAODemo : ISaveBlockAccessor, ISaveBlock6Core + { + public const int boAOdemo = SaveUtil.SIZE_G6ORASDEMO - 0x200; + + private static readonly BlockInfo6[] BlocksAODemo = + { + new BlockInfo6(boAOdemo, 00, 0x00000, 0x00B90), // MyItem // Bag + new BlockInfo6(boAOdemo, 01, 0x00C00, 0x0002C), // ItemInfo6 + new BlockInfo6(boAOdemo, 02, 0x00E00, 0x00038), // GameTime + new BlockInfo6(boAOdemo, 03, 0x01000, 0x00150), // Situation + new BlockInfo6(boAOdemo, 04, 0x01200, 0x00004), // [00004] RandomGroup (rand seeds) + new BlockInfo6(boAOdemo, 05, 0x01400, 0x00008), // PlayTime + new BlockInfo6(boAOdemo, 06, 0x01600, 0x00024), // [00024] temp variables (u32 id + 32 u8) + new BlockInfo6(boAOdemo, 07, 0x01800, 0x02100), // [02100] FieldMoveModelSave + new BlockInfo6(boAOdemo, 08, 0x03A00, 0x00130), // Misc + new BlockInfo6(boAOdemo, 09, 0x03C00, 0x00170), // MyStatus + new BlockInfo6(boAOdemo, 10, 0x03E00, 0x0061C), // PokePartySave + new BlockInfo6(boAOdemo, 11, 0x04600, 0x00504), // EventWork + new BlockInfo6(boAOdemo, 12, 0x04C00, 0x00004), // [00004] Packed Menu Bits + new BlockInfo6(boAOdemo, 13, 0x04E00, 0x00048), // [00048] Repel Info, (Swarm?) and other overworld info (roamer) + new BlockInfo6(boAOdemo, 14, 0x05000, 0x00400), // PokeDiarySave + new BlockInfo6(boAOdemo, 15, 0x05400, 0x0025C), // Record + }; + + public IReadOnlyList BlockInfo => BlocksAODemo; + public MyItem Items { get; } + public ItemInfo6 ItemInfo { get; } + public GameTime6 GameTime { get; } + public Situation6 Situation { get; } + public PlayTime6 Played { get; } + public MyStatus6 Status { get; } + public Record6 Records { get; } + public Misc6AO Misc { get; } + + public SaveBlockAccessorAODemo(SAV6AODemo sav) + { + Items = new MyItem6AO(sav, 0x00000); + ItemInfo = new ItemInfo6(sav, 0x00C00); + GameTime = new GameTime6(sav, 0x00E00); + Situation = new Situation6(sav, 0x01000); + Played = new PlayTime6(sav, 0x01400); + Status = new MyStatus6(sav, 0x03C00); + Records = new Record6(sav, 0x05400); + Misc = new Misc6AO(sav, 0x03A00); + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessorSWSH.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessorSWSH.cs new file mode 100644 index 000000000..9adb94761 --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessorSWSH.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public class SaveBlockAccessorSWSH : ISaveBlockAccessor, ISaveBlock8Main + { + public const int boGG = -1; + + private static readonly BlockInfo7b[] BlockInfoSWSH = + { + new BlockInfo7b(boGG, 00, 0x00000, 0x00D90), + new BlockInfo7b(boGG, 01, 0x00E00, 0x00200), + new BlockInfo7b(boGG, 02, 0x01000, 0x00168), + new BlockInfo7b(boGG, 03, 0x01200, 0x01800), + new BlockInfo7b(boGG, 04, 0x02A00, 0x020E8), + new BlockInfo7b(boGG, 05, 0x04C00, 0x00930), + new BlockInfo7b(boGG, 06, 0x05600, 0x00004), + new BlockInfo7b(boGG, 07, 0x05800, 0x00130), + new BlockInfo7b(boGG, 08, 0x05A00, 0x00012), + new BlockInfo7b(boGG, 09, 0x05C00, 0x3F7A0), + new BlockInfo7b(boGG, 10, 0x45400, 0x00008), + new BlockInfo7b(boGG, 11, 0x45600, 0x00E90), + new BlockInfo7b(boGG, 12, 0x46600, 0x010A4), + new BlockInfo7b(boGG, 13, 0x47800, 0x000F0), + new BlockInfo7b(boGG, 14, 0x47A00, 0x06010), + new BlockInfo7b(boGG, 15, 0x4DC00, 0x00200), + new BlockInfo7b(boGG, 16, 0x4DE00, 0x00098), + new BlockInfo7b(boGG, 17, 0x4E000, 0x00068), + new BlockInfo7b(boGG, 18, 0x4E200, 0x69780), + new BlockInfo7b(boGG, 19, 0xB7A00, 0x000B0), + new BlockInfo7b(boGG, 20, 0xB7C00, 0x00940), + }; + + public IReadOnlyList BlockInfo => BlockInfoSWSH; + public MyItem Items { get; } + public Record8 Records { get; } + public PlayTime8 Played { get; } + public MyStatus8 MyStatus { get; } + public ConfigSave8 Config { get; } + public GameTime8 GameTime { get; } + public Misc8 MiscBlock { get; } + public Zukan8 Zukan { get; } + public EventWork8 EventWork { get; } + public BoxLayout8 BoxLayout { get; } + public Situation8 Situation { get; } + public FieldMoveModelSave8 OverworldBlock { get; } + + public SaveBlockAccessorSWSH(SAV8SWSH sav) + { + const int langFlagStart = 0x550; // todo + Items = new MyItem8(sav); // todo - at offset 0? + Zukan = new Zukan8(sav, GetBlockOffset(SAV8BlockIndex.Pokedex), langFlagStart); + MyStatus = new MyStatus8(sav, GetBlockOffset(SAV8BlockIndex.MyStatus)); + Played = new PlayTime8(sav, GetBlockOffset(SAV8BlockIndex.PlayTime)); + MiscBlock = new Misc8(sav, GetBlockOffset(SAV8BlockIndex.Misc)); + GameTime = new GameTime8(sav, GetBlockOffset(SAV8BlockIndex.GameTime)); + OverworldBlock = new FieldMoveModelSave8(sav, GetBlockOffset(SAV8BlockIndex.FieldMoveModelSave)); + Records = new Record8(sav, GetBlockOffset(SAV8BlockIndex.Records), Core.Records.MaxType_SWSH); + Situation = new Situation8(sav, GetBlockOffset(SAV8BlockIndex.Situation)); + EventWork = new EventWork8(sav); + BoxLayout = new BoxLayout8(sav, GetBlockOffset(SAV8BlockIndex.BOX)); + Config = new ConfigSave8(sav, GetBlockOffset(SAV8BlockIndex.ConfigSave)); + } + + public BlockInfo GetBlock(SAV8BlockIndex index) => BlockInfo[(int)index]; + public int GetBlockOffset(SAV8BlockIndex index) => GetBlock(index).Offset; + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessorXY.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessorXY.cs new file mode 100644 index 000000000..83eb497d4 --- /dev/null +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessorXY.cs @@ -0,0 +1,109 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public class SaveBlockAccessorXY : ISaveBlockAccessor, ISaveBlock6XY + { + public const int boXY = SaveUtil.SIZE_G6XY - 0x200; + public int FooterOffset => boXY; + + public static readonly BlockInfo6[] BlocksXY = + { + new BlockInfo6(boXY, 00, 0x00000, 0x002C8), + new BlockInfo6(boXY, 01, 0x00400, 0x00B88), + new BlockInfo6(boXY, 02, 0x01000, 0x0002C), + new BlockInfo6(boXY, 03, 0x01200, 0x00038), + new BlockInfo6(boXY, 04, 0x01400, 0x00150), + new BlockInfo6(boXY, 05, 0x01600, 0x00004), + new BlockInfo6(boXY, 06, 0x01800, 0x00008), + new BlockInfo6(boXY, 07, 0x01A00, 0x001C0), + new BlockInfo6(boXY, 08, 0x01C00, 0x000BE), + new BlockInfo6(boXY, 09, 0x01E00, 0x00024), + new BlockInfo6(boXY, 10, 0x02000, 0x02100), + new BlockInfo6(boXY, 11, 0x04200, 0x00140), + new BlockInfo6(boXY, 12, 0x04400, 0x00440), + new BlockInfo6(boXY, 13, 0x04A00, 0x00574), + new BlockInfo6(boXY, 14, 0x05000, 0x04E28), + new BlockInfo6(boXY, 15, 0x0A000, 0x04E28), + new BlockInfo6(boXY, 16, 0x0F000, 0x04E28), + new BlockInfo6(boXY, 17, 0x14000, 0x00170), + new BlockInfo6(boXY, 18, 0x14200, 0x0061C), + new BlockInfo6(boXY, 19, 0x14A00, 0x00504), + new BlockInfo6(boXY, 20, 0x15000, 0x006A0), + new BlockInfo6(boXY, 21, 0x15800, 0x00644), + new BlockInfo6(boXY, 22, 0x16000, 0x00104), + new BlockInfo6(boXY, 23, 0x16200, 0x00004), + new BlockInfo6(boXY, 24, 0x16400, 0x00420), + new BlockInfo6(boXY, 25, 0x16A00, 0x00064), + new BlockInfo6(boXY, 26, 0x16C00, 0x003F0), + new BlockInfo6(boXY, 27, 0x17000, 0x0070C), + new BlockInfo6(boXY, 28, 0x17800, 0x00180), + new BlockInfo6(boXY, 29, 0x17A00, 0x00004), + new BlockInfo6(boXY, 30, 0x17C00, 0x0000C), + new BlockInfo6(boXY, 31, 0x17E00, 0x00048), + new BlockInfo6(boXY, 32, 0x18000, 0x00054), + new BlockInfo6(boXY, 33, 0x18200, 0x00644), + new BlockInfo6(boXY, 34, 0x18A00, 0x005C8), + new BlockInfo6(boXY, 35, 0x19000, 0x002F8), + new BlockInfo6(boXY, 36, 0x19400, 0x01B40), + new BlockInfo6(boXY, 37, 0x1B000, 0x001F4), + new BlockInfo6(boXY, 38, 0x1B200, 0x001F0), + new BlockInfo6(boXY, 39, 0x1B400, 0x00216), + new BlockInfo6(boXY, 40, 0x1B800, 0x00390), + new BlockInfo6(boXY, 41, 0x1BC00, 0x01A90), + new BlockInfo6(boXY, 42, 0x1D800, 0x00308), + new BlockInfo6(boXY, 43, 0x1DC00, 0x00618), + new BlockInfo6(boXY, 44, 0x1E400, 0x0025C), + new BlockInfo6(boXY, 45, 0x1E800, 0x00834), + new BlockInfo6(boXY, 46, 0x1F200, 0x00318), + new BlockInfo6(boXY, 47, 0x1F600, 0x007D0), + new BlockInfo6(boXY, 48, 0x1FE00, 0x00C48), + new BlockInfo6(boXY, 49, 0x20C00, 0x00078), + new BlockInfo6(boXY, 50, 0x20E00, 0x00200), + new BlockInfo6(boXY, 51, 0x21000, 0x00C84), + new BlockInfo6(boXY, 52, 0x21E00, 0x00628), + new BlockInfo6(boXY, 53, 0x22600, 0x34AD0), + new BlockInfo6(boXY, 54, 0x57200, 0x0E058), + }; + + public IReadOnlyList BlockInfo => BlocksXY; + public MyItem Items { get; } + public ItemInfo6 ItemInfo { get; } + public GameTime6 GameTime { get; } + public Situation6 Situation { get; } + public PlayTime6 Played { get; } + public MyStatus6 Status { get; } + public Record6 Records { get; } + + public SaveBlockAccessorXY(SAV6XY sav) + { + PuffBlock = new Puff6(sav, 0x00000); + Items = new MyItem6XY(sav, 0x00400); + ItemInfo = new ItemInfo6(sav, 0x01000); + GameTime = new GameTime6(sav, 0x01200); + Situation = new Situation6(sav, 0x01400); + Played = new PlayTime6(sav, 0x01800); + Fashion6XY = new Fashion6XY(sav, 0x1A00); + Misc = new Misc6XY(sav, 0x4200); + BoxLayout = new BoxLayout6(sav, 0x4400); + BattleBoxBlock = new BattleBox6(sav, 0x04A00); + Status = new MyStatus6XY(sav, 0x14000); + Zukan = new Zukan6XY(sav, 0x15000, 0x3C8); + OPowerBlock = new OPower6(sav, 0x16A00); + MysteryBlock = new MysteryBlock6(sav, 0x1BC00); + Records = new Record6(sav, 0x1E400); + LinkBlock = new Link6(sav, 0x1FE00); + } + + public Puff6 PuffBlock { get; } + public BoxLayout6 BoxLayout { get; } + public BattleBox6 BattleBoxBlock { get; } + public OPower6 OPowerBlock { get; } + public MysteryBlock6 MysteryBlock { get; } + public Link6 LinkBlock { get; } + + public Misc6XY Misc { get; } + public Zukan6XY Zukan { get; } + public Fashion6XY Fashion6XY { get; } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Blocks/BlockInfoNDS.cs b/PKHeX.Core/Saves/Blocks/BlockInfoNDS.cs index b38ecc144..4e0959703 100644 --- a/PKHeX.Core/Saves/Blocks/BlockInfoNDS.cs +++ b/PKHeX.Core/Saves/Blocks/BlockInfoNDS.cs @@ -10,7 +10,7 @@ public sealed class BlockInfoNDS : BlockInfo private readonly int ChecksumOffset; private readonly int ChecksumMirror; - private BlockInfoNDS(int offset, int length, int chkOffset, int chkMirror) + public BlockInfoNDS(int offset, int length, int chkOffset, int chkMirror) { Offset = offset; Length = length; @@ -37,158 +37,5 @@ protected override void SetChecksum(byte[] data) bytes.CopyTo(data, ChecksumOffset); bytes.CopyTo(data, ChecksumMirror); } - - // Offset, Length, chkOffset, ChkMirror - public static readonly BlockInfoNDS[] BlocksBW = - { - new BlockInfoNDS(0x00000, 0x03E0, 0x003E2, 0x23F00), // Box Names - new BlockInfoNDS(0x00400, 0x0FF0, 0x013F2, 0x23F02), // Box 1 - new BlockInfoNDS(0x01400, 0x0FF0, 0x023F2, 0x23F04), // Box 2 - new BlockInfoNDS(0x02400, 0x0FF0, 0x033F2, 0x23F06), // Box 3 - new BlockInfoNDS(0x03400, 0x0FF0, 0x043F2, 0x23F08), // Box 4 - new BlockInfoNDS(0x04400, 0x0FF0, 0x053F2, 0x23F0A), // Box 5 - new BlockInfoNDS(0x05400, 0x0FF0, 0x063F2, 0x23F0C), // Box 6 - new BlockInfoNDS(0x06400, 0x0FF0, 0x073F2, 0x23F0E), // Box 7 - new BlockInfoNDS(0x07400, 0x0FF0, 0x083F2, 0x23F10), // Box 8 - new BlockInfoNDS(0x08400, 0x0FF0, 0x093F2, 0x23F12), // Box 9 - new BlockInfoNDS(0x09400, 0x0FF0, 0x0A3F2, 0x23F14), // Box 10 - new BlockInfoNDS(0x0A400, 0x0FF0, 0x0B3F2, 0x23F16), // Box 11 - new BlockInfoNDS(0x0B400, 0x0FF0, 0x0C3F2, 0x23F18), // Box 12 - new BlockInfoNDS(0x0C400, 0x0FF0, 0x0D3F2, 0x23F1A), // Box 13 - new BlockInfoNDS(0x0D400, 0x0FF0, 0x0E3F2, 0x23F1C), // Box 14 - new BlockInfoNDS(0x0E400, 0x0FF0, 0x0F3F2, 0x23F1E), // Box 15 - new BlockInfoNDS(0x0F400, 0x0FF0, 0x103F2, 0x23F20), // Box 16 - new BlockInfoNDS(0x10400, 0x0FF0, 0x113F2, 0x23F22), // Box 17 - new BlockInfoNDS(0x11400, 0x0FF0, 0x123F2, 0x23F24), // Box 18 - new BlockInfoNDS(0x12400, 0x0FF0, 0x133F2, 0x23F26), // Box 19 - new BlockInfoNDS(0x13400, 0x0FF0, 0x143F2, 0x23F28), // Box 20 - new BlockInfoNDS(0x14400, 0x0FF0, 0x153F2, 0x23F2A), // Box 21 - new BlockInfoNDS(0x15400, 0x0FF0, 0x163F2, 0x23F2C), // Box 22 - new BlockInfoNDS(0x16400, 0x0FF0, 0x173F2, 0x23F2E), // Box 23 - new BlockInfoNDS(0x17400, 0x0FF0, 0x183F2, 0x23F30), // Box 24 - new BlockInfoNDS(0x18400, 0x09C0, 0x18DC2, 0x23F32), // Inventory - new BlockInfoNDS(0x18E00, 0x0534, 0x19336, 0x23F34), // Party Pokemon - new BlockInfoNDS(0x19400, 0x0068, 0x1946A, 0x23F36), // Trainer Data - new BlockInfoNDS(0x19500, 0x009C, 0x1959E, 0x23F38), // Trainer Position - new BlockInfoNDS(0x19600, 0x1338, 0x1A93A, 0x23F3A), // Unity Tower and survey stuff - new BlockInfoNDS(0x1AA00, 0x07C4, 0x1B1C6, 0x23F3C), // Pal Pad Player Data - new BlockInfoNDS(0x1B200, 0x0D54, 0x1BF56, 0x23F3E), // Pal Pad Friend Data - new BlockInfoNDS(0x1C000, 0x002C, 0x1C02E, 0x23F40), // Skin Info - new BlockInfoNDS(0x1C100, 0x0658, 0x1C75A, 0x23F42), // ??? Gym badge data - new BlockInfoNDS(0x1C800, 0x0A94, 0x1D296, 0x23F44), // Mystery Gift - new BlockInfoNDS(0x1D300, 0x01AC, 0x1D4AE, 0x23F46), // Dream World Stuff (Catalog) - new BlockInfoNDS(0x1D500, 0x03EC, 0x1D8EE, 0x23F48), // Chatter - new BlockInfoNDS(0x1D900, 0x005C, 0x1D95E, 0x23F4A), // Adventure Info - new BlockInfoNDS(0x1DA00, 0x01E0, 0x1DBE2, 0x23F4C), // Trainer Card Records - new BlockInfoNDS(0x1DC00, 0x00A8, 0x1DCAA, 0x23F4E), // ??? - new BlockInfoNDS(0x1DD00, 0x0460, 0x1E162, 0x23F50), // (40d) - new BlockInfoNDS(0x1E200, 0x1400, 0x1F602, 0x23F52), // ??? - new BlockInfoNDS(0x1F700, 0x02A4, 0x1F9A6, 0x23F54), // Contains flags and references for downloaded data (Musical) - new BlockInfoNDS(0x1FA00, 0x02DC, 0x1FCDE, 0x23F56), // ??? - new BlockInfoNDS(0x1FD00, 0x034C, 0x2004E, 0x23F58), // ??? - new BlockInfoNDS(0x20100, 0x03EC, 0x204EE, 0x23F5A), // ??? - new BlockInfoNDS(0x20500, 0x00F8, 0x205FA, 0x23F5C), // ??? - new BlockInfoNDS(0x20600, 0x02FC, 0x208FE, 0x23F5E), // Tournament Block - new BlockInfoNDS(0x20900, 0x0094, 0x20996, 0x23F60), // ??? - new BlockInfoNDS(0x20A00, 0x035C, 0x20D5E, 0x23F62), // Battle Box Block - new BlockInfoNDS(0x20E00, 0x01CC, 0x20FCE, 0x23F64), // Daycare Block - new BlockInfoNDS(0x21000, 0x0168, 0x2116A, 0x23F66), // Strength Boulder Status Block - new BlockInfoNDS(0x21200, 0x00EC, 0x212EE, 0x23F68), // Badge Flags, Money, Trainer Sayings - new BlockInfoNDS(0x21300, 0x01B0, 0x214B2, 0x23F6A), // Entralink (Level & Powers etc) - new BlockInfoNDS(0x21500, 0x001C, 0x2151E, 0x23F6C), // ??? - new BlockInfoNDS(0x21600, 0x04D4, 0x21AD6, 0x23F6E), // Pokedex - new BlockInfoNDS(0x21B00, 0x0034, 0x21B36, 0x23F70), // Swarm and other overworld info - 2C - swarm, 2D - repel steps, 2E repel type - new BlockInfoNDS(0x21C00, 0x003C, 0x21C3E, 0x23F72), // ??? - new BlockInfoNDS(0x21D00, 0x01AC, 0x21EAE, 0x23F74), // Battle Subway - new BlockInfoNDS(0x21F00, 0x0B90, 0x22A92, 0x23F76), // ??? - new BlockInfoNDS(0x22B00, 0x009C, 0x22B9E, 0x23F78), // Online Records - new BlockInfoNDS(0x22C00, 0x0850, 0x23452, 0x23F7A), // Entralink Forest pokmon data - new BlockInfoNDS(0x23500, 0x0028, 0x2352A, 0x23F7C), // ??? - new BlockInfoNDS(0x23600, 0x0284, 0x23886, 0x23F7E), // ??? - new BlockInfoNDS(0x23900, 0x0010, 0x23912, 0x23F80), // ??? - new BlockInfoNDS(0x23A00, 0x005C, 0x23A5E, 0x23F82), // ??? - new BlockInfoNDS(0x23B00, 0x016C, 0x23C6E, 0x23F84), // ??? - new BlockInfoNDS(0x23D00, 0x0040, 0x23D42, 0x23F86), // ??? - new BlockInfoNDS(0x23E00, 0x00FC, 0x23EFE, 0x23F88), // ??? - new BlockInfoNDS(0x23F00, 0x008C, 0x23F9A, 0x23F9A), // Checksums */ - }; - - public static readonly BlockInfoNDS[] BlocksB2W2 = - { - new BlockInfoNDS(0x00000, 0x03e0, 0x003E2, 0x25F00), // Box Names - new BlockInfoNDS(0x00400, 0x0ff0, 0x013F2, 0x25F02), // Box 1 - new BlockInfoNDS(0x01400, 0x0ff0, 0x023F2, 0x25F04), // Box 2 - new BlockInfoNDS(0x02400, 0x0ff0, 0x033F2, 0x25F06), // Box 3 - new BlockInfoNDS(0x03400, 0x0ff0, 0x043F2, 0x25F08), // Box 4 - new BlockInfoNDS(0x04400, 0x0ff0, 0x053F2, 0x25F0A), // Box 5 - new BlockInfoNDS(0x05400, 0x0ff0, 0x063F2, 0x25F0C), // Box 6 - new BlockInfoNDS(0x06400, 0x0ff0, 0x073F2, 0x25F0E), // Box 7 - new BlockInfoNDS(0x07400, 0x0ff0, 0x083F2, 0x25F10), // Box 8 - new BlockInfoNDS(0x08400, 0x0ff0, 0x093F2, 0x25F12), // Box 9 - new BlockInfoNDS(0x09400, 0x0ff0, 0x0A3F2, 0x25F14), // Box 10 - new BlockInfoNDS(0x0A400, 0x0ff0, 0x0B3F2, 0x25F16), // Box 11 - new BlockInfoNDS(0x0B400, 0x0ff0, 0x0C3F2, 0x25F18), // Box 12 - new BlockInfoNDS(0x0C400, 0x0ff0, 0x0D3F2, 0x25F1A), // Box 13 - new BlockInfoNDS(0x0D400, 0x0ff0, 0x0E3F2, 0x25F1C), // Box 14 - new BlockInfoNDS(0x0E400, 0x0ff0, 0x0F3F2, 0x25F1E), // Box 15 - new BlockInfoNDS(0x0F400, 0x0ff0, 0x103F2, 0x25F20), // Box 16 - new BlockInfoNDS(0x10400, 0x0ff0, 0x113F2, 0x25F22), // Box 17 - new BlockInfoNDS(0x11400, 0x0ff0, 0x123F2, 0x25F24), // Box 18 - new BlockInfoNDS(0x12400, 0x0ff0, 0x133F2, 0x25F26), // Box 19 - new BlockInfoNDS(0x13400, 0x0ff0, 0x143F2, 0x25F28), // Box 20 - new BlockInfoNDS(0x14400, 0x0ff0, 0x153F2, 0x25F2A), // Box 21 - new BlockInfoNDS(0x15400, 0x0ff0, 0x163F2, 0x25F2C), // Box 22 - new BlockInfoNDS(0x16400, 0x0ff0, 0x173F2, 0x25F2E), // Box 23 - new BlockInfoNDS(0x17400, 0x0ff0, 0x183F2, 0x25F30), // Box 24 - new BlockInfoNDS(0x18400, 0x09ec, 0x18DEE, 0x25F32), // Inventory - new BlockInfoNDS(0x18E00, 0x0534, 0x19336, 0x25F34), // Party Pokemon - new BlockInfoNDS(0x19400, 0x00b0, 0x194B2, 0x25F36), // Trainer Data - new BlockInfoNDS(0x19500, 0x00a8, 0x195AA, 0x25F38), // Trainer Position - new BlockInfoNDS(0x19600, 0x1338, 0x1A93A, 0x25F3A), // Unity Tower and survey stuff - new BlockInfoNDS(0x1AA00, 0x07c4, 0x1B1C6, 0x25F3C), // Pal Pad Player Data (30d) - new BlockInfoNDS(0x1B200, 0x0d54, 0x1BF56, 0x25F3E), // Pal Pad Friend Data - new BlockInfoNDS(0x1C000, 0x0094, 0x1C096, 0x25F40), // Options / Skin Info - new BlockInfoNDS(0x1C100, 0x0658, 0x1C75A, 0x25F42), // Trainer Card - new BlockInfoNDS(0x1C800, 0x0a94, 0x1D296, 0x25F44), // Mystery Gift - new BlockInfoNDS(0x1D300, 0x01ac, 0x1D4AE, 0x25F46), // Dream World Stuff (Catalog) - new BlockInfoNDS(0x1D500, 0x03ec, 0x1D8EE, 0x25F48), // Chatter - new BlockInfoNDS(0x1D900, 0x005c, 0x1D95E, 0x25F4A), // Adventure data - new BlockInfoNDS(0x1DA00, 0x01e0, 0x1DBE2, 0x25F4C), // Record - new BlockInfoNDS(0x1DC00, 0x00a8, 0x1DCAA, 0x25F4E), // ??? - new BlockInfoNDS(0x1DD00, 0x0460, 0x1E162, 0x25F50), // Mail (40d) - new BlockInfoNDS(0x1E200, 0x1400, 0x1F602, 0x25F52), // ??? - new BlockInfoNDS(0x1F700, 0x02a4, 0x1F9A6, 0x25F54), // Musical - new BlockInfoNDS(0x1FA00, 0x00e0, 0x1FAE2, 0x25F56), // Fused Reshiram/Zekrom Storage - new BlockInfoNDS(0x1FB00, 0x034c, 0x1FE4E, 0x25F58), // IR - new BlockInfoNDS(0x1FF00, 0x04e0, 0x203E2, 0x25F5A), // EventWork - new BlockInfoNDS(0x20400, 0x00f8, 0x204FA, 0x25F5C), // ??? - new BlockInfoNDS(0x20500, 0x02fc, 0x207FE, 0x25F5E), // Regulation - new BlockInfoNDS(0x20800, 0x0094, 0x20896, 0x25F60), // Gimmick - new BlockInfoNDS(0x20900, 0x035c, 0x20C5E, 0x25F62), // Battle Box - new BlockInfoNDS(0x20D00, 0x01d4, 0x20ED6, 0x25F64), // Daycare (50d) - new BlockInfoNDS(0x20F00, 0x01e0, 0x210E2, 0x25F66), // Strength Boulder Status Block - new BlockInfoNDS(0x21100, 0x00f0, 0x211F2, 0x25F68), // Misc (Badge Flags, Money, Trainer Sayings) - new BlockInfoNDS(0x21200, 0x01b4, 0x213B6, 0x25F6A), // Entralink (Level & Powers etc) - new BlockInfoNDS(0x21400, 0x04dc, 0x218DE, 0x25F6C), // Pokedex - new BlockInfoNDS(0x21900, 0x0034, 0x21936, 0x25F6E), // Encount (Swarm and other overworld info - 2C - swarm, 2D - repel steps, 2E repel type) - new BlockInfoNDS(0x21A00, 0x003c, 0x21A3E, 0x25F70), // Battle Subway Play Info - new BlockInfoNDS(0x21B00, 0x01ac, 0x21CAE, 0x25F72), // Battle Subway Score Info - new BlockInfoNDS(0x21D00, 0x0b90, 0x22892, 0x25F74), // Battle Subway WiFI Info - new BlockInfoNDS(0x22900, 0x00ac, 0x229AE, 0x25F76), // Online Records - new BlockInfoNDS(0x22A00, 0x0850, 0x23252, 0x25F78), // Entralink Forest pokmon data (60d) - new BlockInfoNDS(0x23300, 0x0284, 0x23586, 0x25F7A), // ??? - new BlockInfoNDS(0x23600, 0x0010, 0x23612, 0x25F7C), // ??? - new BlockInfoNDS(0x23700, 0x00a8, 0x237AA, 0x25F7E), // PWT related data - new BlockInfoNDS(0x23800, 0x016c, 0x2396E, 0x25F80), // ??? - new BlockInfoNDS(0x23A00, 0x0080, 0x23A82, 0x25F82), // ??? - new BlockInfoNDS(0x23B00, 0x00fc, 0x23BFE, 0x25F84), // Hollow/Rival Block - new BlockInfoNDS(0x23C00, 0x16a8, 0x252AA, 0x25F86), // Join Avenue Block - new BlockInfoNDS(0x25300, 0x0498, 0x2579A, 0x25F88), // Medal - new BlockInfoNDS(0x25800, 0x0060, 0x25862, 0x25F8A), // Key-related data - new BlockInfoNDS(0x25900, 0x00fc, 0x259FE, 0x25F8C), // Festa Missions (70d) - new BlockInfoNDS(0x25A00, 0x03e4, 0x25DE6, 0x25F8E), // ??? - new BlockInfoNDS(0x25E00, 0x00f0, 0x25EF2, 0x25F90), // ??? - new BlockInfoNDS(0x25F00, 0x0094, 0x25FA2, 0x25FA2), // Checksum Block (73d) - }; } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/MemeCrypto/MemeCrypto.cs b/PKHeX.Core/Saves/MemeCrypto/MemeCrypto.cs index c16d2aa86..cc8e10b7c 100644 --- a/PKHeX.Core/Saves/MemeCrypto/MemeCrypto.cs +++ b/PKHeX.Core/Saves/MemeCrypto/MemeCrypto.cs @@ -32,7 +32,7 @@ public static bool VerifyMemePOKE(byte[] input, out byte[] output) return true; } - output = null; + output = input; return false; } @@ -43,37 +43,37 @@ public static bool VerifyMemeData(byte[] input, out byte[] output) if (VerifyMemeData(input, out output, keyIndex)) return true; } - output = null; + output = input; return false; } public static bool VerifyMemeData(byte[] input, out byte[] output, MemeKeyIndex keyIndex) { - output = null; if (input.Length < 0x60) + { + output = input; return false; + } var memekey = new MemeKey(keyIndex); output = (byte[])input.Clone(); var sigBuffer = new byte[0x60]; Array.Copy(input, input.Length - 0x60, sigBuffer, 0, 0x60); sigBuffer = memekey.RsaPublic(sigBuffer); - using (var sha1 = SHA1.Create()) + using var sha1 = SHA1.Create(); + foreach (var orVal in new byte[] { 0, 0x80 }) { - foreach (var orVal in new byte[] { 0, 0x80 }) - { - sigBuffer[0x0] |= orVal; - sigBuffer.CopyTo(output, output.Length - 0x60); - memekey.AesDecrypt(output).CopyTo(output, 0); - // Check for 8-byte equality. - var computed = BitConverter.ToUInt64(sha1.ComputeHash(output, 0, output.Length - 0x8), 0); - var existing = BitConverter.ToUInt64(output, output.Length - 0x8); - if (computed == existing) - return true; - } + sigBuffer[0x0] |= orVal; + sigBuffer.CopyTo(output, output.Length - 0x60); + memekey.AesDecrypt(output).CopyTo(output, 0); + // Check for 8-byte equality. + var computed = BitConverter.ToUInt64(sha1.ComputeHash(output, 0, output.Length - 0x8), 0); + var existing = BitConverter.ToUInt64(output, output.Length - 0x8); + if (computed == existing) + return true; } - output = null; + output = input; return false; } @@ -88,7 +88,7 @@ public static bool VerifyMemeData(byte[] input, out byte[] output, int offset, i output = newOutput; return true; } - output = null; + output = input; return false; } @@ -103,7 +103,7 @@ public static bool VerifyMemeData(byte[] input, out byte[] output, int offset, i output = newOutput; return true; } - output = null; + output = input; return false; } @@ -141,7 +141,7 @@ public static byte[] SignMemeData(byte[] input, MemeKeyIndex keyIndex = MemeKeyI /// The resigned save data. Invalid input returns null. public static byte[] Resign7(byte[] sav7) { - if (sav7 == null || (sav7.Length != SaveUtil.SIZE_G7SM && sav7.Length != SaveUtil.SIZE_G7USUM)) + if (sav7.Length != SaveUtil.SIZE_G7SM && sav7.Length != SaveUtil.SIZE_G7USUM) throw new ArgumentException("Should not be using this for unsupported saves."); // Save Chunks are 0x200 bytes each; Memecrypto signature is 0x100 bytes into the 2nd to last chunk. diff --git a/PKHeX.Core/Saves/SAV1.cs b/PKHeX.Core/Saves/SAV1.cs index ed8417a6d..e0c84c064 100644 --- a/PKHeX.Core/Saves/SAV1.cs +++ b/PKHeX.Core/Saves/SAV1.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; namespace PKHeX.Core @@ -14,6 +15,9 @@ public sealed class SAV1 : SaveFile, ILangDeviantSave public bool Japanese { get; } public bool Korean => false; + public override PersonalTable Personal { get; } + public override IReadOnlyList HeldItems => Array.Empty(); + public override string[] PKMExtensions => PKM.Extensions.Where(f => { int gen = f.Last() - 0x30; @@ -25,20 +29,21 @@ public SAV1(GameVersion version = GameVersion.RBY, bool japanese = false) : base Version = version; Japanese = japanese; Offsets = Japanese ? SAV1Offsets.JPN : SAV1Offsets.INT; - + Personal = version == GameVersion.Y ? PersonalTable.Y : PersonalTable.RB; Initialize(version); ClearBoxes(); } public SAV1(byte[] data, GameVersion versionOverride = GameVersion.Any) : base(data) { - Version = versionOverride != GameVersion.Any ? versionOverride : SaveUtil.GetIsG1SAV(data); - if (Version == GameVersion.Invalid) - return; - Japanese = SaveUtil.GetIsG1SAVJ(Data); Offsets = Japanese ? SAV1Offsets.JPN : SAV1Offsets.INT; + Version = versionOverride != GameVersion.Any ? versionOverride : SaveUtil.GetIsG1SAV(data); + Personal = Version == GameVersion.Y ? PersonalTable.Y : PersonalTable.RB; + if (Version == GameVersion.Invalid) + return; + Initialize(versionOverride); } @@ -52,8 +57,6 @@ private void Initialize(GameVersion versionOverride) Array.Resize(ref Data, Data.Length + SIZE_RESERVED); Party = GetPartyOffset(0); - Personal = Version == GameVersion.Y ? PersonalTable.Y : PersonalTable.RB; - // Stash boxes after the save file's end. int stored = SIZE_STOREDBOX; int baseDest = Data.Length - SIZE_RESERVED; diff --git a/PKHeX.Core/Saves/SAV2.cs b/PKHeX.Core/Saves/SAV2.cs index 72dc8ba61..79678c783 100644 --- a/PKHeX.Core/Saves/SAV2.cs +++ b/PKHeX.Core/Saves/SAV2.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; namespace PKHeX.Core @@ -14,6 +15,9 @@ public sealed class SAV2 : SaveFile, ILangDeviantSave public bool Japanese { get; } public bool Korean { get; } + public override PersonalTable Personal { get; } + public override IReadOnlyList HeldItems => Legal.HeldItems_GSC; + public override string[] PKMExtensions => PKM.Extensions.Where(f => { int gen = f.Last() - 0x30; @@ -36,6 +40,7 @@ public SAV2(GameVersion version = GameVersion.C, LanguageID lang = LanguageID.En // otherwise, both false } Offsets = new SAV2Offsets(this); + Personal = Version == GameVersion.GS ? PersonalTable.GS : PersonalTable.C; Initialize(); ClearBoxes(); } @@ -43,13 +48,12 @@ public SAV2(GameVersion version = GameVersion.C, LanguageID lang = LanguageID.En public SAV2(byte[] data, GameVersion versionOverride = GameVersion.Any) : base(data) { Version = versionOverride != GameVersion.Any ? versionOverride : SaveUtil.GetIsG2SAV(Data); - if (Version == GameVersion.Invalid) - return; Japanese = SaveUtil.GetIsG2SAVJ(Data) != GameVersion.Invalid; if (!Japanese) Korean = SaveUtil.GetIsG2SAVK(Data) != GameVersion.Invalid; Offsets = new SAV2Offsets(this); + Personal = Version == GameVersion.GS ? PersonalTable.GS : PersonalTable.C; Initialize(); } @@ -59,14 +63,6 @@ private void Initialize() Array.Resize(ref Data, Data.Length + SIZE_RESERVED); Party = GetPartyOffset(0); - Personal = Version == GameVersion.GS ? PersonalTable.GS : PersonalTable.C; - - LegalItems = Legal.Pouch_Items_GSC; - LegalBalls = Legal.Pouch_Ball_GSC; - LegalKeyItems = Version == GameVersion.C ? Legal.Pouch_Key_C : Legal.Pouch_Key_GS; - LegalTMHMs = Legal.Pouch_TMHM_GSC; - HeldItems = Legal.HeldItems_GSC; - // Stash boxes after the save file's end. int splitAtIndex = (Japanese ? 6 : 7); int stored = SIZE_STOREDBOX; @@ -452,10 +448,10 @@ public uint Coin } } - private ushort[] LegalItems; - private ushort[] LegalKeyItems; - private ushort[] LegalBalls; - private ushort[] LegalTMHMs; + private ushort[] LegalItems => Legal.Pouch_Items_GSC; + private ushort[] LegalKeyItems => Legal.Pouch_Ball_GSC; + private ushort[] LegalBalls => Version == GameVersion.C ? Legal.Pouch_Key_C : Legal.Pouch_Key_GS; + private ushort[] LegalTMHMs => Legal.Pouch_TMHM_GSC; public override InventoryPouch[] Inventory { diff --git a/PKHeX.Core/Saves/SAV3.cs b/PKHeX.Core/Saves/SAV3.cs index 23fb343b7..357966a41 100644 --- a/PKHeX.Core/Saves/SAV3.cs +++ b/PKHeX.Core/Saves/SAV3.cs @@ -69,6 +69,10 @@ public static int GetLargeBlockOffset(int chunk, int chunkOffset) return chunkOffset; } + private PersonalTable _personal { get; set; } + public override PersonalTable Personal => _personal; + public override IReadOnlyList HeldItems => Legal.HeldItems_RS; + public SAV3(GameVersion version = GameVersion.FRLG, bool japanese = false) : base(SaveUtil.SIZE_G3RAW) { if (version == GameVersion.FR || version == GameVersion.LG) @@ -77,28 +81,51 @@ public SAV3(GameVersion version = GameVersion.FRLG, bool japanese = false) : bas Version = GameVersion.RS; else Version = version; - Personal = SaveUtil.GetG3Personal(Version) ?? PersonalTable.RS; + _personal = SaveUtil.GetG3Personal(Version) ?? PersonalTable.RS; Japanese = japanese; - LoadBlocks(); + LoadBlocks(out BlockOrder, out BlockOfs); // spoof block offsets BlockOfs = Enumerable.Range(0, BLOCK_COUNT).ToArray(); + LegalKeyItems = Version switch + { + GameVersion.RS => Legal.Pouch_Key_RS, + GameVersion.E => Legal.Pouch_Key_E, + _ => Legal.Pouch_Key_RS + }; + SeenFlagOffsets = Array.Empty(); + Initialize(); ClearBoxes(); } public SAV3(byte[] data, GameVersion versionOverride = GameVersion.Any) : base(data) { - LoadBlocks(); + LoadBlocks(out BlockOrder, out BlockOfs); Version = versionOverride != GameVersion.Any ? versionOverride : GetVersion(Data, BlockOfs[0]); - Personal = SaveUtil.GetG3Personal(Version) ?? PersonalTable.RS; + _personal = SaveUtil.GetG3Personal(Version) ?? PersonalTable.RS; // Japanese games are limited to 5 character OT names; any unused characters are 0xFF. // 5 for JP, 7 for INT. There's always 1 terminator, thus we can check 0x6-0x7 being 0xFFFF = INT // OT name is stored at the top of the first block. Japanese = BitConverter.ToInt16(Data, BlockOfs[0] + 0x6) == 0; + LegalKeyItems = Version switch + { + GameVersion.RS => Legal.Pouch_Key_RS, + GameVersion.E => Legal.Pouch_Key_E, + _ => Legal.Pouch_Key_RS + }; + + PokeDex = BlockOfs[0] + 0x18; + SeenFlagOffsets = Version switch + { + GameVersion.RS => new[] { PokeDex + 0x44, BlockOfs[1] + 0x938, BlockOfs[4] + 0xC0C }, + GameVersion.E => new[] { PokeDex + 0x44, BlockOfs[1] + 0x988, BlockOfs[4] + 0xCA4 }, + _ => new[] { PokeDex + 0x44, BlockOfs[1] + 0x5F8, BlockOfs[4] + 0xB98 } + }; + Initialize(); } @@ -117,81 +144,71 @@ private void Initialize() Array.Copy(Data, (blockIndex * SIZE_BLOCK) + ABO, Data, Box + ((i - 5) * 0xF80), chunkLength[i]); } - PokeDex = BlockOfs[0] + 0x18; switch (Version) { case GameVersion.RS: - LegalKeyItems = Legal.Pouch_Key_RS; OFS_PCItem = BlockOfs[1] + 0x0498; OFS_PouchHeldItem = BlockOfs[1] + 0x0560; OFS_PouchKeyItem = BlockOfs[1] + 0x05B0; OFS_PouchBalls = BlockOfs[1] + 0x0600; OFS_PouchTMHM = BlockOfs[1] + 0x0640; OFS_PouchBerry = BlockOfs[1] + 0x0740; - SeenFlagOffsets = new[] {PokeDex + 0x44, BlockOfs[1] + 0x938, BlockOfs[4] + 0xC0C}; EventFlag = BlockOfs[2] + 0x2A0; EventConst = EventFlag + (EventFlagMax / 8); Daycare = BlockOfs[4] + 0x11C; break; case GameVersion.E: - LegalKeyItems = Legal.Pouch_Key_E; OFS_PCItem = BlockOfs[1] + 0x0498; OFS_PouchHeldItem = BlockOfs[1] + 0x0560; OFS_PouchKeyItem = BlockOfs[1] + 0x05D8; OFS_PouchBalls = BlockOfs[1] + 0x0650; OFS_PouchTMHM = BlockOfs[1] + 0x0690; OFS_PouchBerry = BlockOfs[1] + 0x0790; - SeenFlagOffsets = new[] {PokeDex + 0x44, BlockOfs[1] + 0x988, BlockOfs[4] + 0xCA4}; EventFlag = BlockOfs[2] + 0x2F0; EventConst = EventFlag + (EventFlagMax / 8); Daycare = BlockOfs[4] + 0x1B0; break; case GameVersion.FRLG: - LegalKeyItems = Legal.Pouch_Key_FRLG; OFS_PCItem = BlockOfs[1] + 0x0298; OFS_PouchHeldItem = BlockOfs[1] + 0x0310; OFS_PouchKeyItem = BlockOfs[1] + 0x03B8; OFS_PouchBalls = BlockOfs[1] + 0x0430; OFS_PouchTMHM = BlockOfs[1] + 0x0464; OFS_PouchBerry = BlockOfs[1] + 0x054C; - SeenFlagOffsets = new[] {PokeDex + 0x44, BlockOfs[1] + 0x5F8, BlockOfs[4] + 0xB98}; EventFlag = BlockOfs[1] + 0xEE0; EventConst = BlockOfs[2] + 0x80; Daycare = BlockOfs[4] + 0x100; break; + default: + throw new ArgumentException(nameof(Version)); } LoadEReaderBerryData(); - LegalItems = Legal.Pouch_Items_RS; - LegalBalls = Legal.Pouch_Ball_RS; - LegalTMHMs = Legal.Pouch_TMHM_RS; - LegalBerries = Legal.Pouch_Berries_RS; - HeldItems = Legal.HeldItems_RS; // Sanity Check SeenFlagOffsets -- early saves may not have block 4 initialized yet - SeenFlagOffsets = SeenFlagOffsets?.Where(z => z >= 0).ToArray(); + SeenFlagOffsets = SeenFlagOffsets.Where(z => z >= 0).ToArray(); } - private void LoadBlocks() + private void LoadBlocks(out int[] blockOrder, out int[] blockOfs) { - int[] BlockOrder1 = GetBlockOrder(0); + int[] o1 = GetBlockOrder(0); if (Data.Length > SaveUtil.SIZE_G3RAWHALF) { - int[] BlockOrder2 = GetBlockOrder(0xE000); - ActiveSAV = GetActiveSaveIndex(BlockOrder1, BlockOrder2); - BlockOrder = ActiveSAV == 0 ? BlockOrder1 : BlockOrder2; + int[] o2 = GetBlockOrder(0xE000); + ActiveSAV = GetActiveSaveIndex(o1, o2); + blockOrder = ActiveSAV == 0 ? o1 : o2; } else { ActiveSAV = 0; - BlockOrder = BlockOrder1; + blockOrder = o1; } - BlockOfs = new int[BLOCK_COUNT]; + blockOfs = new int[BLOCK_COUNT]; for (int i = 0; i < BLOCK_COUNT; i++) { - int index = Array.IndexOf(BlockOrder, i); - BlockOfs[i] = index < 0 ? int.MinValue : (index * SIZE_BLOCK) + ABO; + int index = Array.IndexOf(blockOrder, i); + blockOfs[i] = index < 0 ? int.MinValue : (index * SIZE_BLOCK) + ABO; } } @@ -594,7 +611,12 @@ public uint BerryPowder } } - private ushort[] LegalItems, LegalKeyItems, LegalBalls, LegalTMHMs, LegalBerries; + private readonly ushort[] LegalKeyItems; + private static ushort[] LegalItems => Legal.Pouch_Items_RS; + private static ushort[] LegalBalls => Legal.Pouch_Ball_RS; + private static ushort[] LegalTMHMs => Legal.Pouch_TMHM_RS; + private static ushort[] LegalBerries => Legal.Pouch_Berries_RS; + private int OFS_PCItem, OFS_PouchHeldItem, OFS_PouchKeyItem, OFS_PouchBalls, OFS_PouchTMHM, OFS_PouchBerry; public override InventoryPouch[] Inventory @@ -899,12 +921,7 @@ public sealed class RTC3 public readonly byte[] Data; private const int Size = 8; - public RTC3(byte[] data = null) - { - if (data == null || data.Length != Size) - data = new byte[8]; - Data = data; - } + public RTC3(byte[] data) => Data = data; public int Day { get => BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } public int Hour { get => Data[2]; set => Data[2] = (byte)value; } @@ -917,13 +934,13 @@ public RTC3 ClockInitial get { if (FRLG) - return null; + throw new ArgumentException(nameof(ClockInitial)); int block0 = GetBlockOffset(0); return new RTC3(GetData(block0 + 0x98, 8)); } set { - if (value?.Data == null || FRLG) + if (FRLG) return; int block0 = GetBlockOffset(0); SetData(value.Data, block0 + 0x98); @@ -935,13 +952,13 @@ public RTC3 ClockElapsed get { if (FRLG) - return null; + throw new ArgumentException(nameof(ClockElapsed)); int block0 = GetBlockOffset(0); return new RTC3(GetData(block0 + 0xA0, 8)); } set { - if (value?.Data == null || FRLG) + if (FRLG) return; int block0 = GetBlockOffset(0); SetData(value.Data, block0 + 0xA0); @@ -972,6 +989,38 @@ private int PokeBlockOffset } } + public int GetMailOffset(int index) + { + GetMailBlockOffset(Version, ref index, out int block, out int offset); + return (index * Mail3.SIZE) + GetBlockOffset(block) + offset; + } + + private static void GetMailBlockOffset(GameVersion game, ref int index, out int block, out int offset) + { + block = 3; + if (game == GameVersion.E) + { + offset = 0xCE0; + } + else if (GameVersion.RS.Contains(game)) + { + offset = 0xC4C; + } + else // FRLG + { + if (index >= 12) + { + block = 4; + offset = 0; + index -= 12; + } + else + { + offset = 0xDD0; + } + } + } + public bool HasReceivedWishmkrJirachi { get => GameVersion.RS.Contains(Version) && GetFlag(BlockOfs[4] + 0x2B1, 0); @@ -987,7 +1036,7 @@ public bool ResetPersonal(GameVersion g) var pt = SaveUtil.GetG3Personal(g); if (pt == null) return false; - Personal = pt; + _personal = pt; return true; } } diff --git a/PKHeX.Core/Saves/SAV3Colosseum.cs b/PKHeX.Core/Saves/SAV3Colosseum.cs index ac4e06d17..8d1c000fd 100644 --- a/PKHeX.Core/Saves/SAV3Colosseum.cs +++ b/PKHeX.Core/Saves/SAV3Colosseum.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; @@ -12,8 +13,10 @@ public sealed class SAV3Colosseum : SaveFile, IDisposable, IGCSaveFile protected override string BAKText => $"{OT} ({Version}) - {PlayTimeString}"; public override string Filter => this.GCFilter(); public override string Extension => this.GCExtension(); + public override PersonalTable Personal => PersonalTable.RS; + public override IReadOnlyList HeldItems => Legal.HeldItems_COLO; public bool IsMemoryCardSave => MC != null; - private readonly SAV3GCMemoryCard MC; + private readonly SAV3GCMemoryCard? MC; // 3 Save files are stored // 0x0000-0x6000 contains memory card data @@ -29,54 +32,32 @@ public sealed class SAV3Colosseum : SaveFile, IDisposable, IGCSaveFile private int SaveCount = -1; private int SaveIndex = -1; - private StrategyMemo StrategyMemo; + private readonly StrategyMemo StrategyMemo; public int MaxShadowID => 0x80; // 128 private int Memo; - private ushort[] LegalItems; - private ushort[] LegalKeyItems; - private ushort[] LegalBalls; - private ushort[] LegalTMHMs; - private ushort[] LegalBerries; - private ushort[] LegalCologne; - private int OFS_PouchHeldItem, OFS_PouchKeyItem, OFS_PouchBalls, OFS_PouchTMHM, OFS_PouchBerry, OFS_PouchCologne; - public SAV3Colosseum(byte[] data, SAV3GCMemoryCard MC) : this(data) { this.MC = MC; BAK = MC.Data; } + public SAV3Colosseum(byte[] data, SAV3GCMemoryCard MC) : this(data, MC.Data) { this.MC = MC; } + public SAV3Colosseum(byte[] data) : this(data, (byte[])data.Clone()) { } public SAV3Colosseum() : base(SaveUtil.SIZE_G3COLO) { - Initialize(); + StrategyMemo = Initialize(); ClearBoxes(); } - public SAV3Colosseum(byte[] data) : base(data) + private SAV3Colosseum(byte[] data, byte[] bak) : base(data, bak) { InitializeData(); - Initialize(); + StrategyMemo = Initialize(); } - private void Initialize() + private StrategyMemo Initialize() { - Personal = PersonalTable.RS; - HeldItems = Legal.HeldItems_COLO; Trainer1 = 0x00078; Party = 0x000A8; - OFS_PouchHeldItem = 0x007F8; - OFS_PouchKeyItem = 0x00848; - OFS_PouchBalls = 0x008F4; - OFS_PouchTMHM = 0x00934; - OFS_PouchBerry = 0x00A34; - OFS_PouchCologne = 0x00AEC; // Cologne Box = 0x00B90; Daycare = 0x08170; Memo = 0x082B0; - StrategyMemo = new StrategyMemo(Data, Memo, xd: false); - - LegalItems = Legal.Pouch_Items_COLO; - LegalKeyItems = Legal.Pouch_Key_COLO; - LegalBalls = Legal.Pouch_Ball_RS; - LegalTMHMs = Legal.Pouch_TM_RS; // not HMs - LegalBerries = Legal.Pouch_Berries_RS; - LegalCologne = Legal.Pouch_Cologne_COLO; // Since PartyCount is not stored in the save file, // Count up how many party slots are active. @@ -85,6 +66,9 @@ private void Initialize() if (GetPartySlot(GetPartyOffset(i)).Species != 0) PartyCount++; } + + var memo = new StrategyMemo(Data, Memo, xd: false); + return memo; } private void InitializeData() @@ -122,7 +106,7 @@ protected override byte[] GetFinalData() if (!IsMemoryCardSave) return newFile; - MC.SelectedSaveData = newFile; + MC!.SelectedSaveData = newFile; return MC.Data; } @@ -145,7 +129,7 @@ private byte[] GetInnerData() public override SaveFile Clone() { var data = GetInnerData(); - var sav = IsMemoryCardSave ? new SAV3Colosseum(data, MC) : new SAV3Colosseum(data); + var sav = IsMemoryCardSave ? new SAV3Colosseum(data, MC!) : new SAV3Colosseum(data); sav.Header = (byte[])Header.Clone(); return sav; } @@ -179,7 +163,7 @@ public override SaveFile Clone() private byte[] EncryptColosseum(byte[] input, byte[] digest) { if (input.Length != SLOT_SIZE) - return null; + throw new ArgumentException(nameof(input)); byte[] d = (byte[])input.Clone(); byte[] k = (byte[])digest.Clone(); // digest @@ -200,7 +184,7 @@ private byte[] EncryptColosseum(byte[] input, byte[] digest) private byte[] DecryptColosseum(byte[] input, byte[] digest) { if (input.Length != SLOT_SIZE) - return null; + throw new ArgumentException(nameof(input)); byte[] d = (byte[])input.Clone(); byte[] k = (byte[])digest.Clone(); @@ -391,12 +375,12 @@ public override InventoryPouch[] Inventory { InventoryPouch[] pouch = { - new InventoryPouch3GC(InventoryType.Items, LegalItems, 999, OFS_PouchHeldItem, 20), // 20 COLO, 30 XD - new InventoryPouch3GC(InventoryType.KeyItems, LegalKeyItems, 1, OFS_PouchKeyItem, 43), - new InventoryPouch3GC(InventoryType.Balls, LegalBalls, 999, OFS_PouchBalls, 16), - new InventoryPouch3GC(InventoryType.TMHMs, LegalTMHMs, 999, OFS_PouchTMHM, 64), - new InventoryPouch3GC(InventoryType.Berries, LegalBerries, 999, OFS_PouchBerry, 46), - new InventoryPouch3GC(InventoryType.Medicine, LegalCologne, 999, OFS_PouchCologne, 3), // Cologne + new InventoryPouch3GC(InventoryType.Items, Legal.Pouch_Items_COLO, 999, 0x007F8, 20), // 20 COLO, 30 XD + new InventoryPouch3GC(InventoryType.KeyItems, Legal.Pouch_Key_COLO, 1, 0x00848, 43), + new InventoryPouch3GC(InventoryType.Balls, Legal.Pouch_Ball_RS, 999, 0x008F4, 16), + new InventoryPouch3GC(InventoryType.TMHMs, Legal.Pouch_TM_RS, 999, 0x00934, 64), // no HMs + new InventoryPouch3GC(InventoryType.Berries, Legal.Pouch_Berries_RS, 999, 0x00A34, 46), + new InventoryPouch3GC(InventoryType.Medicine, Legal.Pouch_Cologne_COLO, 999, 0x00AEC, 3), // Cologne }; return pouch.LoadAll(Data); } diff --git a/PKHeX.Core/Saves/SAV3RSBox.cs b/PKHeX.Core/Saves/SAV3RSBox.cs index 3fe0ba45b..b5d407ba0 100644 --- a/PKHeX.Core/Saves/SAV3RSBox.cs +++ b/PKHeX.Core/Saves/SAV3RSBox.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; namespace PKHeX.Core @@ -11,40 +12,30 @@ public sealed class SAV3RSBox : SaveFile, IGCSaveFile protected override string BAKText => $"{Version} #{SaveCount:0000}"; public override string Filter => this.GCFilter(); public override string Extension => this.GCExtension(); + public override PersonalTable Personal => PersonalTable.RS; + public override IReadOnlyList HeldItems => Legal.HeldItems_RS; public bool IsMemoryCardSave => MC != null; - private readonly SAV3GCMemoryCard MC; - public readonly bool Japanese; // todo? + private readonly SAV3GCMemoryCard? MC; + public readonly bool Japanese = false; // todo? - public SAV3RSBox(byte[] data, SAV3GCMemoryCard MC) : this(data) { this.MC = MC; BAK = MC.Data; } + public SAV3RSBox(byte[] data, SAV3GCMemoryCard MC) : this(data, MC.Data) { this.MC = MC; } + public SAV3RSBox(byte[] data) : this(data, (byte[])data.Clone()) { } public SAV3RSBox() : base(SaveUtil.SIZE_G3BOX) { Box = 0; + Blocks = Array.Empty(); ClearBoxes(); - Initialize(); } - public SAV3RSBox(byte[] data) : base(data) + private SAV3RSBox(byte[] data, byte[] bak) : base(data, bak) { + Blocks = ReadBlocks(data); InitializeData(); - Initialize(); - } - - private void Initialize() - { - Personal = PersonalTable.RS; - HeldItems = Legal.HeldItems_RS; } private void InitializeData() { - Blocks = new BlockInfoRSBOX[2 * BLOCK_COUNT]; - for (int i = 0; i < Blocks.Length; i++) - { - int offset = BLOCK_SIZE + (i * BLOCK_SIZE); - Blocks[i] = new BlockInfoRSBOX(Data, offset); - } - // Detect active save int[] SaveCounts = Blocks.Select(block => (int) block.SaveCount).ToArray(); SaveCount = SaveCounts.Max(); @@ -61,6 +52,18 @@ private void InitializeData() Array.Copy(Data, b.Offset + 0xC, Data, (int) (Box + (b.ID * copySize)), copySize); } + private static BlockInfoRSBOX[] ReadBlocks(byte[] data) + { + var blocks = new BlockInfoRSBOX[2 * BLOCK_COUNT]; + for (int i = 0; i < blocks.Length; i++) + { + int offset = BLOCK_SIZE + (i * BLOCK_SIZE); + blocks[i] = new BlockInfoRSBOX(data, offset); + } + + return blocks; + } + private BlockInfoRSBOX[] Blocks; private int SaveCount; private const int BLOCK_COUNT = 23; @@ -75,7 +78,7 @@ protected override byte[] GetFinalData() if (!IsMemoryCardSave) return newFile; - MC.SelectedSaveData = newFile; + MC!.SelectedSaveData = newFile; return MC.Data; } @@ -95,7 +98,7 @@ private byte[] GetInnerData() public override SaveFile Clone() { var data = GetInnerData(); - var sav = IsMemoryCardSave ? new SAV3RSBox(data, MC) : new SAV3RSBox(data); + var sav = IsMemoryCardSave ? new SAV3RSBox(data, MC!) : new SAV3RSBox(data); sav.Header = (byte[])Header.Clone(); return sav; } diff --git a/PKHeX.Core/Saves/SAV3XD.cs b/PKHeX.Core/Saves/SAV3XD.cs index ea65e03d0..082c4e8d9 100644 --- a/PKHeX.Core/Saves/SAV3XD.cs +++ b/PKHeX.Core/Saves/SAV3XD.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; namespace PKHeX.Core @@ -12,7 +13,7 @@ public sealed class SAV3XD : SaveFile, IGCSaveFile public override string Filter => this.GCFilter(); public override string Extension => this.GCExtension(); public bool IsMemoryCardSave => MC != null; - private readonly SAV3GCMemoryCard MC; + private readonly SAV3GCMemoryCard? MC; private const int SLOT_SIZE = 0x28000; private const int SLOT_START = 0x6000; @@ -22,26 +23,33 @@ public sealed class SAV3XD : SaveFile, IGCSaveFile private int SaveIndex = -1; private int Memo; private int Shadow; - private StrategyMemo StrategyMemo; - private ShadowInfoTableXD ShadowInfo; + private readonly StrategyMemo StrategyMemo; + private readonly ShadowInfoTableXD ShadowInfo; public int MaxShadowID => ShadowInfo.Count; private int OFS_PouchHeldItem, OFS_PouchKeyItem, OFS_PouchBalls, OFS_PouchTMHM, OFS_PouchBerry, OFS_PouchCologne, OFS_PouchDisc; private readonly int[] subOffsets = new int[16]; - public SAV3XD(byte[] data, SAV3GCMemoryCard MC) : this(data) { this.MC = MC; BAK = MC.Data; } + public SAV3XD(byte[] data, SAV3GCMemoryCard MC) : this(data, MC.Data) { this.MC = MC; } + public SAV3XD(byte[] data) : this(data, (byte[])data.Clone()) { } public SAV3XD() : base(SaveUtil.SIZE_G3XD) { + // create fake objects + StrategyMemo = new StrategyMemo(); + ShadowInfo = new ShadowInfoTableXD(); Initialize(); ClearBoxes(); } - public SAV3XD(byte[] data) : base(data) + private SAV3XD(byte[] data, byte[] bak) : base(data, bak) { - InitializeData(); + InitializeData(out StrategyMemo, out ShadowInfo); Initialize(); } - private void InitializeData() + public override PersonalTable Personal => PersonalTable.RS; + public override IReadOnlyList HeldItems => Legal.HeldItems_XD; + + private void InitializeData(out StrategyMemo memo, out ShadowInfoTableXD info) { // Scan all 3 save slots for the highest counter for (int i = 0; i < SLOT_COUNT; i++) @@ -86,8 +94,8 @@ private void InitializeData() Shadow = subOffsets[7] + 0xA8; // Purifier = subOffsets[14] + 0xA8; - StrategyMemo = new StrategyMemo(Data, Memo, xd: true); - ShadowInfo = new ShadowInfoTableXD(Data.Slice(Shadow, subLength[7])); + memo = new StrategyMemo(Data, Memo, xd: true); + info = new ShadowInfoTableXD(Data.Slice(Shadow, subLength[7])); } private void Initialize() @@ -99,8 +107,6 @@ private void Initialize() OFS_PouchBerry = Trainer1 + 0x72C; OFS_PouchCologne = Trainer1 + 0x7E4; OFS_PouchDisc = Trainer1 + 0x7F0; - Personal = PersonalTable.RS; - HeldItems = Legal.HeldItems_XD; // Since PartyCount is not stored in the save file, // Count up how many party slots are active. @@ -119,7 +125,7 @@ protected override byte[] GetFinalData() if (!IsMemoryCardSave) return newFile; - MC.SelectedSaveData = newFile; + MC!.SelectedSaveData = newFile; return MC.Data; } @@ -146,7 +152,7 @@ private byte[] GetInnerData() public override SaveFile Clone() { var data = GetInnerData(); - var sav = IsMemoryCardSave ? new SAV3XD(data, MC) : new SAV3XD(data); + var sav = IsMemoryCardSave ? new SAV3XD(data, MC!) : new SAV3XD(data); sav.Header = (byte[]) Header.Clone(); return sav; } diff --git a/PKHeX.Core/Saves/SAV4.cs b/PKHeX.Core/Saves/SAV4.cs index 64c1e1dab..3f4fa8c99 100644 --- a/PKHeX.Core/Saves/SAV4.cs +++ b/PKHeX.Core/Saves/SAV4.cs @@ -43,7 +43,6 @@ public abstract class SAV4 : SaveFile protected SAV4() { - Data = BAK = Array.Empty(); Storage = new byte[StorageSize]; General = new byte[GeneralSize]; ClearBoxes(); @@ -188,31 +187,7 @@ private int GetActiveStorageBlock() protected int AdventureInfo = int.MinValue; protected int Seal = int.MinValue; public int GTS { get; protected set; } = int.MinValue; - - // Inventory - protected int OFS_PouchHeldItem, OFS_PouchKeyItem, OFS_PouchTMHM, OFS_MailItems, OFS_PouchMedicine, OFS_PouchBerry, OFS_PouchBalls, OFS_BattleItems; - protected ushort[] LegalItems, LegalKeyItems, LegalTMHMs, LegalMedicine, LegalBerries, LegalBalls, LegalBattleItems, LegalMailItems; - - public override InventoryPouch[] Inventory - { - get - { - InventoryPouch[] pouch = - { - new InventoryPouch4(InventoryType.Items, LegalItems, 999, OFS_PouchHeldItem), - new InventoryPouch4(InventoryType.KeyItems, LegalKeyItems, 1, OFS_PouchKeyItem), - new InventoryPouch4(InventoryType.TMHMs, LegalTMHMs, 99, OFS_PouchTMHM), - new InventoryPouch4(InventoryType.Medicine, LegalMedicine, 999, OFS_PouchMedicine), - new InventoryPouch4(InventoryType.Berries, LegalBerries, 999, OFS_PouchBerry), - new InventoryPouch4(InventoryType.Balls, LegalBalls, 999, OFS_PouchBalls), - new InventoryPouch4(InventoryType.BattleItems, LegalBattleItems, 999, OFS_BattleItems), - new InventoryPouch4(InventoryType.MailItems, LegalMailItems, 999, OFS_MailItems), - }; - return pouch.LoadAll(General); - } - set => value.SaveAll(General); - } - + // Storage public override int PartyCount { @@ -494,11 +469,8 @@ public override void SetDaycareOccupied(int loc, int slot, bool occupied) // Mystery Gift private bool MysteryGiftActive { get => (General[72] & 1) == 1; set => General[72] = (byte)((General[72] & 0xFE) | (value ? 1 : 0)); } - private static bool IsMysteryGiftAvailable(MysteryGift[] value) + private static bool IsMysteryGiftAvailable(DataMysteryGift[] value) { - if (value == null) - return false; - for (int i = 0; i < 8; i++) // 8 PGT { if (value[i] is PGT g && g.CardType != 0) @@ -512,11 +484,8 @@ private static bool IsMysteryGiftAvailable(MysteryGift[] value) return false; } - private int[] MatchMysteryGifts(MysteryGift[] value) + private int[] MatchMysteryGifts(DataMysteryGift[] value) { - if (value == null) - return Array.Empty(); - int[] cardMatch = new int[8]; for (int i = 0; i < 8; i++) { @@ -552,11 +521,7 @@ public override MysteryGiftAlbum GiftAlbum { get { - var album = new MysteryGiftAlbum - { - Flags = MysteryGiftReceivedFlags, - Gifts = MysteryGiftCards, - }; + var album = new MysteryGiftAlbum(MysteryGiftCards, MysteryGiftReceivedFlags); album.Flags[2047] = false; return album; } @@ -612,11 +577,11 @@ protected override bool[] MysteryGiftReceivedFlags } } - protected override MysteryGift[] MysteryGiftCards + protected override DataMysteryGift[] MysteryGiftCards { get { - MysteryGift[] cards = new MysteryGift[8 + 3]; + DataMysteryGift[] cards = new DataMysteryGift[8 + 3]; for (int i = 0; i < 8; i++) // 8 PGT cards[i] = new PGT(General.Slice(WondercardData + (i * PGT.Size), PGT.Size)); for (int i = 8; i < 11; i++) // 3 PCD @@ -625,9 +590,6 @@ protected override MysteryGift[] MysteryGiftCards } set { - if (value == null) - return; - var Matches = MatchMysteryGifts(value); // automatically applied if (Matches.Length == 0) return; @@ -1012,5 +974,18 @@ public void SetAllSeals(byte count, bool unreleased = false) for (int i = 0; i < sealIndexCount; i++) General[Seal + i] = val; } + + public int GetMailOffset(int index) + { + int ofs = (index * Mail4.SIZE); + return Version switch + { + GameVersion.DP => (ofs + 0x4BEC), + GameVersion.Pt => (ofs + 0x4E80), + _ => (ofs + 0x3FA8) + }; + } + + public byte[] GetMailData(int ofs) => General.Slice(ofs, Mail4.SIZE); } } diff --git a/PKHeX.Core/Saves/SAV4BR.cs b/PKHeX.Core/Saves/SAV4BR.cs index b11ef41eb..a734a3078 100644 --- a/PKHeX.Core/Saves/SAV4BR.cs +++ b/PKHeX.Core/Saves/SAV4BR.cs @@ -13,25 +13,19 @@ public sealed class SAV4BR : SaveFile protected override string BAKText => $"{Version} #{SaveCount:0000}"; public override string Filter => "PbrSaveData|*"; public override string Extension => string.Empty; + public override PersonalTable Personal => PersonalTable.DP; + public override IReadOnlyList HeldItems => Legal.HeldItems_DP; private const int SAVE_COUNT = 4; public SAV4BR() : base(SaveUtil.SIZE_G4BR) { ClearBoxes(); - Initialize(); } public SAV4BR(byte[] data) : base(data) { InitializeData(data); - Initialize(); - } - - private void Initialize() - { - Personal = PersonalTable.DP; - HeldItems = Legal.HeldItems_DP; } private void InitializeData(byte[] data) diff --git a/PKHeX.Core/Saves/SAV4DP.cs b/PKHeX.Core/Saves/SAV4DP.cs index bc8c028f6..403c0a382 100644 --- a/PKHeX.Core/Saves/SAV4DP.cs +++ b/PKHeX.Core/Saves/SAV4DP.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -10,6 +11,8 @@ public sealed class SAV4DP : SAV4Sinnoh public SAV4DP() => Initialize(); public SAV4DP(byte[] data) : base(data) => Initialize(); protected override SAV4 CloneInternal() => Exportable ? new SAV4DP(Data) : new SAV4DP(); + public override PersonalTable Personal => PersonalTable.DP; + public override IReadOnlyList HeldItems => Legal.HeldItems_DP; protected override int GeneralSize => 0xC100; protected override int StorageSize => 0x121E0; // Start 0xC100, +4 starts box data @@ -17,7 +20,6 @@ public sealed class SAV4DP : SAV4Sinnoh private void Initialize() { Version = GameVersion.DP; - Personal = PersonalTable.DP; GetSAVOffsets(); } @@ -30,24 +32,6 @@ private void GetSAVOffsets() WondercardFlags = 0xA6D0; WondercardData = 0xA7fC; - OFS_PouchHeldItem = 0x624; - OFS_PouchKeyItem = 0x8B8; - OFS_PouchTMHM = 0x980; - OFS_MailItems = 0xB10; - OFS_PouchMedicine = 0xB40; - OFS_PouchBerry = 0xBE0; - OFS_PouchBalls = 0xCE0; - OFS_BattleItems = 0xD1C; - LegalItems = Legal.Pouch_Items_DP; - LegalKeyItems = Legal.Pouch_Key_DP; - LegalTMHMs = Legal.Pouch_TMHM_DP; - LegalMedicine = Legal.Pouch_Medicine_DP; - LegalBerries = Legal.Pouch_Berries_DP; - LegalBalls = Legal.Pouch_Ball_DP; - LegalBattleItems = Legal.Pouch_Battle_DP; - LegalMailItems = Legal.Pouch_Mail_DP; - - HeldItems = Legal.HeldItems_DP; EventConst = 0xD9C; EventFlag = 0xFDC; Daycare = 0x141C; @@ -79,6 +63,26 @@ public override void SetBoxWallpaper(int box, int value) } #endregion + public override InventoryPouch[] Inventory + { + get + { + InventoryPouch[] pouch = + { + new InventoryPouch4(InventoryType.Items, Legal.Pouch_Items_DP, 999, 0x624), + new InventoryPouch4(InventoryType.KeyItems, Legal.Pouch_Key_DP, 1, 0x8B8), + new InventoryPouch4(InventoryType.TMHMs, Legal.Pouch_TMHM_DP, 99, 0x980), + new InventoryPouch4(InventoryType.MailItems, Legal.Pouch_Mail_DP, 999, 0xB10), + new InventoryPouch4(InventoryType.Medicine, Legal.Pouch_Medicine_DP, 999, 0xB40), + new InventoryPouch4(InventoryType.Berries, Legal.Pouch_Berries_DP, 999, 0xBE0), + new InventoryPouch4(InventoryType.Balls, Legal.Pouch_Ball_DP, 999, 0xCE0), + new InventoryPouch4(InventoryType.BattleItems, Legal.Pouch_Battle_DP, 999, 0xD1C), + }; + return pouch.LoadAll(General); + } + set => value.SaveAll(General); + } + private const uint MysteryGiftDPSlotActive = 0xEDB88320; private bool[] MysteryGiftDPSlotActiveFlags diff --git a/PKHeX.Core/Saves/SAV4HGSS.cs b/PKHeX.Core/Saves/SAV4HGSS.cs index 6447408a8..3a3c236ff 100644 --- a/PKHeX.Core/Saves/SAV4HGSS.cs +++ b/PKHeX.Core/Saves/SAV4HGSS.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -11,6 +12,8 @@ public sealed class SAV4HGSS : SAV4 public SAV4HGSS(byte[] data) : base(data) => Initialize(); protected override SAV4 CloneInternal() => Exportable ? new SAV4HGSS(Data) : new SAV4HGSS(); + public override PersonalTable Personal => PersonalTable.HGSS; + public override IReadOnlyList HeldItems => Legal.HeldItems_HGSS; protected override int GeneralSize => 0xF628; protected override int StorageSize => 0x12310; // Start 0xF700, +0 starts box data protected override int StorageStart => 0xF700; // unused section right after GeneralSize, alignment? @@ -19,7 +22,6 @@ public sealed class SAV4HGSS : SAV4 private void Initialize() { Version = GameVersion.HGSS; - Personal = PersonalTable.HGSS; GetSAVOffsets(); } @@ -32,24 +34,6 @@ private void GetSAVOffsets() WondercardFlags = 0x9D3C; WondercardData = 0x9E3C; - OFS_PouchHeldItem = 0x644; // 0x644-0x8D7 (0x8CB) - OFS_PouchKeyItem = 0x8D8; // 0x8D8-0x99F (0x979) - OFS_PouchTMHM = 0x9A0; // 0x9A0-0xB33 (0xB2F) - OFS_MailItems = 0xB34; // 0xB34-0xB63 (0xB63) - OFS_PouchMedicine = 0xB64; // 0xB64-0xC03 (0xBFB) - OFS_PouchBerry = 0xC04; // 0xC04-0xD03 - OFS_PouchBalls = 0xD04; // 0xD04-0xD63 - OFS_BattleItems = 0xD64; // 0xD64-0xD97 - LegalItems = Legal.Pouch_Items_HGSS; - LegalKeyItems = Legal.Pouch_Key_HGSS; - LegalTMHMs = Legal.Pouch_TMHM_HGSS; - LegalMedicine = Legal.Pouch_Medicine_HGSS; - LegalBerries = Legal.Pouch_Berries_HGSS; - LegalBalls = Legal.Pouch_Ball_HGSS; - LegalBattleItems = Legal.Pouch_Battle_HGSS; - LegalMailItems = Legal.Pouch_Mail_HGSS; - - HeldItems = Legal.HeldItems_HGSS; EventConst = 0xDE4; EventFlag = 0x10C4; Daycare = 0x15FC; @@ -127,6 +111,26 @@ public override void SetBoxWallpaper(int box, int value) } #endregion + public override InventoryPouch[] Inventory + { + get + { + InventoryPouch[] pouch = + { + new InventoryPouch4(InventoryType.Items, Legal.Pouch_Items_HGSS, 999, 0x644), // 0x644-0x8D7 (0x8CB) + new InventoryPouch4(InventoryType.KeyItems, Legal.Pouch_Key_HGSS, 1, 0x8D8), // 0x8D8-0x99F (0x979) + new InventoryPouch4(InventoryType.TMHMs, Legal.Pouch_TMHM_HGSS, 99, 0x9A0), // 0x9A0-0xB33 (0xB2F) + new InventoryPouch4(InventoryType.MailItems, Legal.Pouch_Mail_HGSS, 999, 0xB34), // 0xB34-0xB63 (0xB63) + new InventoryPouch4(InventoryType.Medicine, Legal.Pouch_Medicine_HGSS, 999, 0xB64), // 0xB64-0xC03 (0xBFB) + new InventoryPouch4(InventoryType.Berries, Legal.Pouch_Berries_HGSS, 999, 0xC04), // 0xC04-0xD03 + new InventoryPouch4(InventoryType.Balls, Legal.Pouch_Ball_HGSS, 999, 0xD04), // 0xD04-0xD63 + new InventoryPouch4(InventoryType.BattleItems, Legal.Pouch_Battle_HGSS, 999, 0xD64), // 0xD64-0xD97 + }; + return pouch.LoadAll(General); + } + set => value.SaveAll(General); + } + public int Badges16 { get => General[Trainer1 + 0x1F]; diff --git a/PKHeX.Core/Saves/SAV4Pt.cs b/PKHeX.Core/Saves/SAV4Pt.cs index be3d8cdaf..83ca17c17 100644 --- a/PKHeX.Core/Saves/SAV4Pt.cs +++ b/PKHeX.Core/Saves/SAV4Pt.cs @@ -1,4 +1,6 @@ -namespace PKHeX.Core +using System.Collections.Generic; + +namespace PKHeX.Core { /// /// format for @@ -8,6 +10,8 @@ public sealed class SAV4Pt : SAV4Sinnoh public SAV4Pt() => Initialize(); public SAV4Pt(byte[] data) : base(data) => Initialize(); protected override SAV4 CloneInternal() => Exportable ? new SAV4Pt(Data) : new SAV4Pt(); + public override PersonalTable Personal => PersonalTable.Pt; + public override IReadOnlyList HeldItems => Legal.HeldItems_Pt; protected override int GeneralSize => 0xCF2C; protected override int StorageSize => 0x121E4; // Start 0xCF2C, +4 starts box data @@ -15,7 +19,6 @@ public sealed class SAV4Pt : SAV4Sinnoh private void Initialize() { Version = GameVersion.Pt; - Personal = PersonalTable.Pt; GetSAVOffsets(); } @@ -28,24 +31,6 @@ private void GetSAVOffsets() WondercardFlags = 0xB4C0; WondercardData = 0xB5C0; - OFS_PouchHeldItem = 0x630; - OFS_PouchKeyItem = 0x8C4; - OFS_PouchTMHM = 0x98C; - OFS_MailItems = 0xB1C; - OFS_PouchMedicine = 0xB4C; - OFS_PouchBerry = 0xBEC; - OFS_PouchBalls = 0xCEC; - OFS_BattleItems = 0xD28; - LegalItems = Legal.Pouch_Items_Pt; - LegalKeyItems = Legal.Pouch_Key_Pt; - LegalTMHMs = Legal.Pouch_TMHM_Pt; - LegalMedicine = Legal.Pouch_Medicine_Pt; - LegalBerries = Legal.Pouch_Berries_Pt; - LegalBalls = Legal.Pouch_Ball_Pt; - LegalBattleItems = Legal.Pouch_Battle_Pt; - LegalMailItems = Legal.Pouch_Mail_Pt; - - HeldItems = Legal.HeldItems_Pt; EventConst = 0xDAC; EventFlag = 0xFEC; Daycare = 0x1654; @@ -87,5 +72,25 @@ public override void SetBoxWallpaper(int box, int value) Storage[GetBoxWallpaperOffset(box)] = (byte)value; } #endregion + + public override InventoryPouch[] Inventory + { + get + { + InventoryPouch[] pouch = + { + new InventoryPouch4(InventoryType.Items, Legal.Pouch_Items_Pt, 999, 0x630), + new InventoryPouch4(InventoryType.KeyItems, Legal.Pouch_Key_Pt, 1, 0x8C4), + new InventoryPouch4(InventoryType.TMHMs, Legal.Pouch_TMHM_Pt, 99, 0x98C), + new InventoryPouch4(InventoryType.MailItems, Legal.Pouch_Mail_Pt, 999, 0xB1C), + new InventoryPouch4(InventoryType.Medicine, Legal.Pouch_Medicine_Pt, 999, 0xB4C), + new InventoryPouch4(InventoryType.Berries, Legal.Pouch_Berries_Pt, 999, 0xBEC), + new InventoryPouch4(InventoryType.Balls, Legal.Pouch_Ball_Pt, 999, 0xCEC), + new InventoryPouch4(InventoryType.BattleItems, Legal.Pouch_Battle_Pt, 999, 0xD28), + }; + return pouch.LoadAll(General); + } + set => value.SaveAll(General); + } } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/SAV4Sinnoh.cs b/PKHeX.Core/Saves/SAV4Sinnoh.cs index e0683a282..cae16d8f4 100644 --- a/PKHeX.Core/Saves/SAV4Sinnoh.cs +++ b/PKHeX.Core/Saves/SAV4Sinnoh.cs @@ -117,7 +117,7 @@ public byte[] PoketchDotArtistData public HoneyTree GetHoneyTree(int index) { if ((uint)index > 21) - return null; + throw new ArgumentException(nameof(index)); return new HoneyTree(General.Slice(OFS_HONEY + (HONEY_SIZE * index), HONEY_SIZE)); } diff --git a/PKHeX.Core/Saves/SAV5.cs b/PKHeX.Core/Saves/SAV5.cs index 99d0ccacf..7066a246a 100644 --- a/PKHeX.Core/Saves/SAV5.cs +++ b/PKHeX.Core/Saves/SAV5.cs @@ -6,7 +6,7 @@ namespace PKHeX.Core /// /// Generation 5 object. /// - public abstract class SAV5 : SaveFile + public abstract class SAV5 : SaveFile, ISaveBlock5BW { protected override PKM GetPKM(byte[] data) => new PK5(data); protected override byte[] DecryptPKM(byte[] data) => PKX.DecryptArray45(data); @@ -15,6 +15,7 @@ public abstract class SAV5 : SaveFile public override string Filter => (Footer.Length != 0 ? "DeSmuME DSV|*.dsv|" : string.Empty) + "SAV File|*.sav|All Files|*.*"; public override string Extension => ".sav"; + public override IReadOnlyList HeldItems => Legal.HeldItems_BW; public override int SIZE_STORED => PKX.SIZE_5STORED; protected override int SIZE_PARTY => PKX.SIZE_5PARTY; public override PKM BlankPKM => new PK5(); @@ -52,43 +53,20 @@ public override GameVersion Version private void Initialize() { - // First blocks are always the same position/size - PCLayout = 0x0; Box = 0x400; Party = 0x18E00; - Trainer1 = 0x19400; - WondercardData = 0x1C800; AdventureInfo = 0x1D900; - - HeldItems = Legal.HeldItems_BW; - BoxLayout = new BoxLayout5(this, PCLayout); - MysteryBlock = new MysteryBlock5(this, WondercardData); - PlayerData = new PlayerData5(this, Trainer1); } // Blocks & Offsets - protected IReadOnlyList Blocks; - protected override void SetChecksums() => Blocks.SetChecksums(Data); - public override bool ChecksumsValid => Blocks.GetChecksumsValid(Data); - public override string ChecksumInfo => Blocks.GetChecksumInfo(Data); - - protected MyItem Items { get; set; } - public Zukan Zukan { get; protected set; } - public Misc5 MiscBlock { get; protected set; } - private MysteryBlock5 MysteryBlock { get; set; } - protected Daycare5 DaycareBlock { get; set; } - public BoxLayout5 BoxLayout { get; private set; } - public PlayerData5 PlayerData { get; private set; } - public BattleSubway5 BattleSubwayBlock { get; protected set; } + protected override void SetChecksums() => AllBlocks.SetChecksums(Data); + public override bool ChecksumsValid => AllBlocks.GetChecksumsValid(Data); + public override string ChecksumInfo => AllBlocks.GetChecksumInfo(Data); protected int CGearInfoOffset; protected int CGearDataOffset; protected int EntreeForestOffset; - protected int Trainer2; private int AdventureInfo; - protected int BattleSubway; - protected int PokeDexLanguageFlags; - private int PCLayout; public int GTS { get; protected set; } = int.MinValue; public int Fused { get; protected set; } = int.MinValue; @@ -97,7 +75,7 @@ private void Initialize() public override bool? IsDaycareOccupied(int loc, int slot) => DaycareBlock.IsOccupied(slot); public override int GetDaycareSlotOffset(int loc, int slot) => DaycareBlock.GetPKMOffset(slot); public override uint? GetDaycareEXP(int loc, int slot) => DaycareBlock.GetEXP(slot); - public override string GetDaycareRNGSeed(int loc) => DaycareBlock.GetSeed()?.ToString("X16"); + public override string GetDaycareRNGSeed(int loc) => DaycareBlock.GetSeed()?.ToString("X16") ?? string.Empty; public override void SetDaycareEXP(int loc, int slot, uint EXP) => DaycareBlock.SetEXP(slot, EXP); public override void SetDaycareOccupied(int loc, int slot, bool occupied) => DaycareBlock.SetOccupied(slot, occupied); public override void SetDaycareRNGSeed(int loc, string seed) => DaycareBlock.SetSeed(seed); @@ -147,7 +125,7 @@ protected override void SetPKM(PKM pkm) public override uint Money { get => MiscBlock.Money; set => MiscBlock.Money = value; } public override uint SecondsToStart { get => BitConverter.ToUInt32(Data, AdventureInfo + 0x34); set => BitConverter.GetBytes(value).CopyTo(Data, AdventureInfo + 0x34); } public override uint SecondsToFame { get => BitConverter.ToUInt32(Data, AdventureInfo + 0x3C); set => BitConverter.GetBytes(value).CopyTo(Data, AdventureInfo + 0x3C); } - public override MysteryGiftAlbum GiftAlbum { get => MysteryBlock.GiftAlbum; set => MysteryBlock.GiftAlbum = value; } + public override MysteryGiftAlbum GiftAlbum { get => MysteryBlock.GiftAlbum; set => MysteryBlock.GiftAlbum = (EncryptedMysteryGiftAlbum)value; } public override InventoryPouch[] Inventory { get => Items.Inventory; set => Items.Inventory = value; } protected override void SetDex(PKM pkm) => Zukan.SetDex(pkm); @@ -183,8 +161,6 @@ public byte[] CGearSkinData } set { - if (value == null) - return; // no clearing byte[] dlcfooter = { 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x27, 0x00, 0x00, 0x27, 0x35, 0x05, 0x31, 0x00, 0x00 }; byte[] bgdata = value; @@ -216,5 +192,18 @@ public EntreeForest EntreeData get => new EntreeForest(GetData(EntreeForestOffset, 0x850)); set => SetData(value.Write(), EntreeForestOffset); } + + public abstract IReadOnlyList AllBlocks { get; } + public abstract MyItem Items { get; } + public abstract Zukan5 Zukan { get; } + public abstract Misc5 MiscBlock { get; } + public abstract MysteryBlock5 MysteryBlock { get; } + public abstract Daycare5 DaycareBlock { get; } + public abstract BoxLayout5 BoxLayout { get; } + public abstract PlayerData5 PlayerData { get; } + public abstract BattleSubway5 BattleSubwayBlock { get; } + + public int GetMailOffset(int index) => (index * Mail5.SIZE) + 0x1DD00; + public byte[] GetMailData(int offset) => GetData(offset, Mail5.SIZE); } } diff --git a/PKHeX.Core/Saves/SAV5B2W2.cs b/PKHeX.Core/Saves/SAV5B2W2.cs index ee3915c16..88300b9f3 100644 --- a/PKHeX.Core/Saves/SAV5B2W2.cs +++ b/PKHeX.Core/Saves/SAV5B2W2.cs @@ -1,9 +1,23 @@ -namespace PKHeX.Core +using System.Collections.Generic; + +namespace PKHeX.Core { - public sealed class SAV5B2W2 : SAV5 + public sealed class SAV5B2W2 : SAV5, ISaveBlock5B2W2 { - public SAV5B2W2() : base(SaveUtil.SIZE_G5RAW) => Initialize(); - public SAV5B2W2(byte[] data) : base(data) => Initialize(); + public SAV5B2W2() : base(SaveUtil.SIZE_G5RAW) + { + Blocks = new SaveBlockAccessor5B2W2(this); + Initialize(); + } + + public SAV5B2W2(byte[] data) : base(data) + { + Blocks = new SaveBlockAccessor5B2W2(this); + Initialize(); + } + + public override PersonalTable Personal => PersonalTable.B2W2; + public SaveBlockAccessor5B2W2 Blocks { get; } public override SaveFile Clone() => new SAV5B2W2((byte[])Data.Clone()) { Footer = (byte[])Footer.Clone() }; protected override int EventConstMax => 0x1AF; // this doesn't seem right? protected override int EventFlagMax => 0xBF8; @@ -11,30 +25,24 @@ public sealed class SAV5B2W2 : SAV5 private void Initialize() { - Blocks = BlockInfoNDS.BlocksB2W2; - Personal = PersonalTable.B2W2; - - Items = new MyItem5B2W2(this, 0x18400); BattleBox = 0x20900; - Trainer2 = 0x21100; EventConst = 0x1FF00; EventFlag = EventConst + 0x35E; - Daycare = 0x20D00; - PokeDex = 0x21400; - PokeDexLanguageFlags = 0x328; // forme flags size is + 8 from bw with new formes (therians) - BattleSubway = 0x21B00; CGearInfoOffset = 0x1C000; CGearDataOffset = 0x52800; EntreeForestOffset = 0x22A00; - Zukan = new Zukan5(this, PokeDex, PokeDexLanguageFlags); - DaycareBlock = new Daycare5(this, Daycare); - - MiscBlock = new Misc5(this, Trainer2); - PWTBlock = new PWTBlock5(this, 0x23700); - DaycareBlock = new Daycare5(this, Daycare); - BattleSubwayBlock = new BattleSubway5(this, BattleSubway); + PokeDex = Blocks.Zukan.PokeDex; } - public PWTBlock5 PWTBlock { get; private set; } + public override IReadOnlyList AllBlocks => Blocks.BlockInfo; + public override MyItem Items => Blocks.Items; + public override Zukan5 Zukan => Blocks.Zukan; + public override Misc5 MiscBlock => Blocks.MiscBlock; + public override MysteryBlock5 MysteryBlock => Blocks.MysteryBlock; + public override Daycare5 DaycareBlock => Blocks.DaycareBlock; + public override BoxLayout5 BoxLayout => Blocks.BoxLayout; + public override PlayerData5 PlayerData => Blocks.PlayerData; + public override BattleSubway5 BattleSubwayBlock => Blocks.BattleSubwayBlock; + public PWTBlock5 PWTBlock => Blocks.PWTBlock; } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/SAV5BW.cs b/PKHeX.Core/Saves/SAV5BW.cs index e3dc91f1f..62c0ec49e 100644 --- a/PKHeX.Core/Saves/SAV5BW.cs +++ b/PKHeX.Core/Saves/SAV5BW.cs @@ -1,9 +1,23 @@ -namespace PKHeX.Core +using System.Collections.Generic; + +namespace PKHeX.Core { public sealed class SAV5BW : SAV5 { - public SAV5BW() : base(SaveUtil.SIZE_G5RAW) => Initialize(); - public SAV5BW(byte[] data) : base(data) => Initialize(); + public SAV5BW() : base(SaveUtil.SIZE_G5RAW) + { + Blocks = new SaveBlockAccessor5BW(this); + Initialize(); + } + + public SAV5BW(byte[] data) : base(data) + { + Blocks = new SaveBlockAccessor5BW(this); + Initialize(); + } + + public override PersonalTable Personal => PersonalTable.BW; + public SaveBlockAccessor5BW Blocks { get; } public override SaveFile Clone() => new SAV5BW((byte[])Data.Clone()) { Footer = (byte[])Footer.Clone() }; protected override int EventConstMax => 0x13E; protected override int EventFlagMax => 0xB60; @@ -11,27 +25,23 @@ public sealed class SAV5BW : SAV5 private void Initialize() { - Blocks = BlockInfoNDS.BlocksBW; - Personal = PersonalTable.BW; - - Items = new MyItem5BW(this, 0x18400); - BattleBox = 0x20A00; - Trainer2 = 0x21200; EventConst = 0x20100; EventFlag = EventConst + 0x27C; - Daycare = 0x20E00; - PokeDex = 0x21600; - PokeDexLanguageFlags = 0x320; - BattleSubway = 0x21D00; CGearInfoOffset = 0x1C000; CGearDataOffset = 0x52000; EntreeForestOffset = 0x22C00; - MiscBlock = new Misc5(this, Trainer2); - Zukan = new Zukan5(this, PokeDex, PokeDexLanguageFlags); - DaycareBlock = new Daycare5(this, Daycare); - BattleSubwayBlock = new BattleSubway5(this, BattleSubway); - // Inventory offsets are the same for each game. + PokeDex = Blocks.Zukan.PokeDex; } + + public override IReadOnlyList AllBlocks => Blocks.BlockInfo; + public override MyItem Items => Blocks.Items; + public override Zukan5 Zukan => Blocks.Zukan; + public override Misc5 MiscBlock => Blocks.MiscBlock; + public override MysteryBlock5 MysteryBlock => Blocks.MysteryBlock; + public override Daycare5 DaycareBlock => Blocks.DaycareBlock; + public override BoxLayout5 BoxLayout => Blocks.BoxLayout; + public override PlayerData5 PlayerData => Blocks.PlayerData; + public override BattleSubway5 BattleSubwayBlock => Blocks.BattleSubwayBlock; } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/SAV6.cs b/PKHeX.Core/Saves/SAV6.cs index 4a3d0e267..df2572955 100644 --- a/PKHeX.Core/Saves/SAV6.cs +++ b/PKHeX.Core/Saves/SAV6.cs @@ -6,15 +6,15 @@ namespace PKHeX.Core /// /// Generation 6 object. /// - public abstract class SAV6 : SAV_BEEF, ITrainerStatRecord + public abstract class SAV6 : SAV_BEEF, ITrainerStatRecord, ISaveBlock6Core { // Save Data Attributes protected override string BAKText => $"{OT} ({Version}) - {Played.LastSavedTime}"; public override string Filter => "Main SAV|*.*"; public override string Extension => string.Empty; - protected SAV6(byte[] data, BlockInfo[] blocks, int biOffset) : base(data, blocks, biOffset) { } - protected SAV6(int size, BlockInfo[] blocks, int biOffset) : base(size, blocks, biOffset) { } + protected SAV6(byte[] data, int biOffset) : base(data, biOffset) { } + protected SAV6(int size, int biOffset) : base(size, biOffset) { } // Configuration public override int SIZE_STORED => PKX.SIZE_6STORED; @@ -39,23 +39,11 @@ public abstract class SAV6 : SAV_BEEF, ITrainerStatRecord protected override PKM GetPKM(byte[] data) => new PK6(data); protected override byte[] DecryptPKM(byte[] data) => PKX.DecryptArray6(data); - public MyItem Items { get; protected set; } - public ItemInfo6 ItemInfo { get; protected set; } - public GameTime6 GameTime { get; protected set; } - public Situation6 Situation { get; protected set; } - public PlayTime6 Played { get; protected set; } - public MyStatus6 Status { get; protected set; } - public Record6 Records { get; set; } - protected int Trainer2 { get; set; } - - // XY/AO protected int WondercardFlags { get; set; } = int.MinValue; - protected int LinkInfo { get; set; } = int.MinValue; protected int JPEG { get; set; } = int.MinValue; public int SuperTrain { get; protected set; } = int.MinValue; public int MaisonStats { get; protected set; } = int.MinValue; - public int Accessories { get; protected set; } = int.MinValue; public int PSS { get; protected set; } = int.MinValue; public int SUBE { get; protected set; } = int.MinValue; public int BerryField { get; protected set; } = int.MinValue; @@ -78,55 +66,15 @@ public abstract class SAV6 : SAV_BEEF, ITrainerStatRecord public override int SubRegion { get => Status.SubRegion; set => Status.SubRegion = value; } public override int Country { get => Status.Country; set => Status.Country = value; } public override int ConsoleRegion { get => Status.ConsoleRegion; set => Status.ConsoleRegion = value; } - - public override uint Money - { - get => BitConverter.ToUInt32(Data, Trainer2 + 0x8); - set => BitConverter.GetBytes(value).CopyTo(Data, Trainer2 + 0x8); - } - - public int Badges - { - get => Data[Trainer2 + 0xC]; - set => Data[Trainer2 + 0xC] = (byte)value; - } - - public int BP - { - get - { - int offset = Trainer2 + 0x3C; - if (this is SAV6AO) offset -= 0xC; // 0x30 - return BitConverter.ToUInt16(Data, offset); - } - set - { - int offset = Trainer2 + 0x3C; - if (this is SAV6AO) offset -= 0xC; // 0x30 - BitConverter.GetBytes((ushort)value).CopyTo(Data, offset); - } - } - - public int Vivillon - { - get - { - int offset = Trainer2 + 0x50; - if (this is SAV6AO) offset -= 0xC; // 0x44 - return Data[offset]; - } - set - { - int offset = Trainer2 + 0x50; - if (this is SAV6AO) offset -= 0xC; // 0x44 - Data[offset] = (byte)value; - } - } - public override int PlayedHours { get => Played.PlayedHours; set => Played.PlayedHours = value; } public override int PlayedMinutes { get => Played.PlayedMinutes; set => Played.PlayedMinutes = value; } public override int PlayedSeconds { get => Played.PlayedSeconds; set => Played.PlayedSeconds = value; } + public abstract int Badges { get; set; } + public abstract int Vivillon { get; set; } + public abstract int BP { get; set; } + // Money + public override uint SecondsToStart { get => GameTime.SecondsToStart; set => GameTime.SecondsToStart = value; } public override uint SecondsToFame { get => GameTime.SecondsToFame; set => GameTime.SecondsToFame = value; } public override InventoryPouch[] Inventory { get => Items.Inventory; set => Items.Inventory = value; } @@ -223,5 +171,12 @@ public override byte[] SetString(string value, int maxLength, int PadToSize = 0, public int GetRecordMax(int recordID) => Records.GetRecordMax(recordID); public void SetRecord(int recordID, int value) => Records.SetRecord(recordID, value); public int RecordCount => Record6.RecordCount; + public abstract MyItem Items { get; } + public abstract ItemInfo6 ItemInfo { get; } + public abstract GameTime6 GameTime { get; } + public abstract Situation6 Situation { get; } + public abstract PlayTime6 Played { get; } + public abstract MyStatus6 Status { get; } + public abstract Record6 Records { get; } } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/SAV6AO.cs b/PKHeX.Core/Saves/SAV6AO.cs index da1778233..1f1c51726 100644 --- a/PKHeX.Core/Saves/SAV6AO.cs +++ b/PKHeX.Core/Saves/SAV6AO.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Text; @@ -8,166 +9,56 @@ namespace PKHeX.Core /// Generation 6 object for . /// /// - public sealed class SAV6AO : SAV6, IPokePuff, IOPower, ILink + public sealed class SAV6AO : SAV6, ISaveBlock6AO { - public SAV6AO(byte[] data) : base(data, BlocksAO, boAO) => Initialize(); - - public SAV6AO() : base(SaveUtil.SIZE_G6ORAS, BlocksAO, boAO) + public SAV6AO(byte[] data) : base(data, SaveBlockAccessorAO.boAO) { + Blocks = new SaveBlockAccessorAO(this); + Initialize(); + } + + public SAV6AO() : base(SaveUtil.SIZE_G6ORAS, SaveBlockAccessorAO.boAO) + { + Blocks = new SaveBlockAccessorAO(this); Initialize(); ClearBoxes(); } + public override PersonalTable Personal => PersonalTable.AO; + public override IReadOnlyList HeldItems => Legal.HeldItem_AO; + public SaveBlockAccessorAO Blocks { get; } public override SaveFile Clone() => new SAV6AO((byte[])Data.Clone()); public override int MaxMoveID => Legal.MaxMoveID_6_AO; public override int MaxItemID => Legal.MaxItemID_6_AO; public override int MaxAbilityID => Legal.MaxAbilityID_6_AO; - private const int boAO = SaveUtil.SIZE_G6ORAS - 0x200; - - public static readonly BlockInfo[] BlocksAO = - { - new BlockInfo6 (boAO, 00, 0x00000, 0x002C8), - new BlockInfo6 (boAO, 01, 0x00400, 0x00B90), - new BlockInfo6 (boAO, 02, 0x01000, 0x0002C), - new BlockInfo6 (boAO, 03, 0x01200, 0x00038), - new BlockInfo6 (boAO, 04, 0x01400, 0x00150), - new BlockInfo6 (boAO, 05, 0x01600, 0x00004), - new BlockInfo6 (boAO, 06, 0x01800, 0x00008), - new BlockInfo6 (boAO, 07, 0x01A00, 0x001C0), - new BlockInfo6 (boAO, 08, 0x01C00, 0x000BE), - new BlockInfo6 (boAO, 09, 0x01E00, 0x00024), - new BlockInfo6 (boAO, 10, 0x02000, 0x02100), - new BlockInfo6 (boAO, 11, 0x04200, 0x00130), - new BlockInfo6 (boAO, 12, 0x04400, 0x00440), - new BlockInfo6 (boAO, 13, 0x04A00, 0x00574), - new BlockInfo6 (boAO, 14, 0x05000, 0x04E28), - new BlockInfo6 (boAO, 15, 0x0A000, 0x04E28), - new BlockInfo6 (boAO, 16, 0x0F000, 0x04E28), - new BlockInfo6 (boAO, 17, 0x14000, 0x00170), - new BlockInfo6 (boAO, 18, 0x14200, 0x0061C), - new BlockInfo6 (boAO, 19, 0x14A00, 0x00504), - new BlockInfo6 (boAO, 20, 0x15000, 0x011CC), - new BlockInfo6 (boAO, 21, 0x16200, 0x00644), - new BlockInfo6 (boAO, 22, 0x16A00, 0x00104), - new BlockInfo6 (boAO, 23, 0x16C00, 0x00004), - new BlockInfo6 (boAO, 24, 0x16E00, 0x00420), - new BlockInfo6 (boAO, 25, 0x17400, 0x00064), - new BlockInfo6 (boAO, 26, 0x17600, 0x003F0), - new BlockInfo6 (boAO, 27, 0x17A00, 0x0070C), - new BlockInfo6 (boAO, 28, 0x18200, 0x00180), - new BlockInfo6 (boAO, 29, 0x18400, 0x00004), - new BlockInfo6 (boAO, 30, 0x18600, 0x0000C), - new BlockInfo6 (boAO, 31, 0x18800, 0x00048), - new BlockInfo6 (boAO, 32, 0x18A00, 0x00054), - new BlockInfo6 (boAO, 33, 0x18C00, 0x00644), - new BlockInfo6 (boAO, 34, 0x19400, 0x005C8), - new BlockInfo6 (boAO, 35, 0x19A00, 0x002F8), - new BlockInfo6 (boAO, 36, 0x19E00, 0x01B40), - new BlockInfo6 (boAO, 37, 0x1BA00, 0x001F4), - new BlockInfo6 (boAO, 38, 0x1BC00, 0x003E0), - new BlockInfo6 (boAO, 39, 0x1C000, 0x00216), - new BlockInfo6 (boAO, 40, 0x1C400, 0x00640), - new BlockInfo6 (boAO, 41, 0x1CC00, 0x01A90), - new BlockInfo6 (boAO, 42, 0x1E800, 0x00400), - new BlockInfo6 (boAO, 43, 0x1EC00, 0x00618), - new BlockInfo6 (boAO, 44, 0x1F400, 0x0025C), - new BlockInfo6 (boAO, 45, 0x1F800, 0x00834), - new BlockInfo6 (boAO, 46, 0x20200, 0x00318), - new BlockInfo6 (boAO, 47, 0x20600, 0x007D0), - new BlockInfo6 (boAO, 48, 0x20E00, 0x00C48), - new BlockInfo6 (boAO, 49, 0x21C00, 0x00078), - new BlockInfo6 (boAO, 50, 0x21E00, 0x00200), - new BlockInfo6 (boAO, 51, 0x22000, 0x00C84), - new BlockInfo6 (boAO, 52, 0x22E00, 0x00628), - new BlockInfo6 (boAO, 53, 0x23600, 0x00400), - new BlockInfo6 (boAO, 54, 0x23A00, 0x07AD0), - new BlockInfo6 (boAO, 55, 0x2B600, 0x078B0), - new BlockInfo6 (boAO, 56, 0x33000, 0x34AD0), - new BlockInfo6 (boAO, 57, 0x67C00, 0x0E058), - }; - private void Initialize() { - /* 00: 00000-002C8, 002C8 */ // Puff = 0x00000; - /* 01: 00400-00F90, 00B90 */ // MyItem = 0x00400; // Bag - /* 02: 01000-0102C, 0002C */ // ItemInfo = 0x1000; // Select Bound Items - /* 03: 01200-01238, 00038 */ // GameTime = 0x01200; - /* 04: 01400-01550, 00150 */ Trainer1 = 0x01400; // Situation - /* 05: 01600-01604, 00004 */ // RandomGroup (rand seeds) - /* 06: 01800-01808, 00008 */ // PlayTime = 0x1800; // PlayTime - /* 07: 01A00-01BC0, 001C0 */ Accessories = 0x1A00; // Fashion - /* 08: 01C00-01CBE, 000BE */ // amie minigame records - /* 09: 01E00-01E24, 00024 */ // temp variables (u32 id + 32 u8) - /* 10: 02000-04100, 02100 */ // FieldMoveModelSave - /* 11: 04200-04330, 00130 */ Trainer2 = 0x04200; // Misc - /* 12: 04400-04840, 00440 */ PCLayout = 0x04400; // BOX - /* 13: 04A00-04F74, 00574 */ BattleBox = 0x04A00; // BattleBox - /* 14: 05000-09E28, 04E28 */ PSS = 0x05000; - /* 15: 0A000-0EE28, 04E28 */ // PSS2 - /* 16: 0F000-13E28, 04E28 */ // PSS3 - /* 17: 14000-14170, 00170 */ // MyStatus - /* 18: 14200-1481C, 0061C */ Party = 0x14200; // PokePartySave - /* 19: 14A00-14F04, 00504 */ EventConst = 0x14A00; // EventWork - /* 20: 15000-161CC, 011CC */ PokeDex = 0x15000; // ZukanData - /* 21: 16200-16844, 00644 */ // hologram clips - /* 22: 16A00-16B04, 00104 */ Fused = 0x16A00; // UnionPokemon - /* 23: 16C00-16C04, 00004 */ // ConfigSave - /* 24: 16E00-17220, 00420 */ // Amie decoration stuff - /* 25: 17400-17464, 00064 */ // OPower = 0x17400; - /* 26: 17600-179F0, 003F0 */ // Strength Rock position (xyz float: 84 entries, 12bytes/entry) - /* 27: 17A00-1810C, 0070C */ // Trainer PR Video - /* 28: 18200-18380, 00180 */ GTS = 0x18200; // GtsData - /* 29: 18400-18404, 00004 */ // Packed Menu Bits - /* 30: 18600-1860C, 0000C */ // PSS Profile Q&A (6*questions, 6*answer) - /* 31: 18800-18848, 00048 */ // Repel Info, (Swarm?) and other overworld info (roamer) - /* 32: 18A00-18A54, 00054 */ // BOSS data fetch history (serial/mystery gift), 4byte intro & 20*4byte entries - /* 33: 18C00-19244, 00644 */ // Streetpass history - /* 34: 19400-199C8, 005C8 */ // LiveMatchData/BattleSpotData - /* 35: 19A00-19CF8, 002F8 */ // MAC Address & Network Connection Logging (0x98 per entry, 5 entries) - /* 36: 19E00-1B940, 01B40 */ HoF = 0x19E00; // Dendou - /* 37: 1BA00-1BBF4, 001F4 */ MaisonStats = 0x1BBC0; // BattleInstSave - /* 38: 1BC00-1BFE0, 003E0 */ Daycare = 0x1BC00; // Sodateya - /* 39: 1C000-1C216, 00216 */ // BattleInstSave - /* 40: 1C400-1CA40, 00640 */ BerryField = 0x1C400; - /* 41: 1CC00-1E690, 01A90 */ WondercardFlags = 0x1CC00; // MysteryGiftSave - /* 42: 1E800-1EC00, 00400 */ // Storyline Records - /* 43: 1EC00-1F218, 00618 */ SUBE = 0x1D890; // PokeDiarySave - /* 44: 1F400-1F65C, 0025C */ // Record = 0x1F400; - /* 45: 1F800-20034, 00834 */ // Friend Safari (0x15 per entry, 100 entries) - /* 46: 20200-20518, 00318 */ SuperTrain = 0x20200; - /* 47: 20600-20DD0, 007D0 */ // Unused (lmao) - /* 48: 20E00-21A48, 00C48 */ LinkInfo = 0x20E00; - /* 49: 21C00-21C78, 00078 */ // PSS usage info - /* 50: 21E00-22000, 00200 */ // GameSyncSave - /* 51: 22000-22C84, 00C84 */ // PSS Icon (bool32 data present, 40x40 u16 pic, unused) - /* 52: 22E00-23428, 00628 */ // ValidationSave (updatabale Public Key for legal check api calls) - /* 53: 23600-23A00, 00400 */ Contest = 0x23600; - /* 54: 23A00-2B4D0, 07AD0 */ SecretBase = 0x23A00; - /* 55: 2B600-32EB0, 078B0 */ EonTicket = 0x319B8; - /* 56: 33000-67AD0, 34AD0 */ Box = 0x33000; - /* 57: 67C00-75C58, 0E058 */ JPEG = 0x67C00; + GTS = 0x18200; // GtsData + Fused = 0x16A00; // UnionPokemon + SUBE = 0x1D890; // PokeDiarySave - Items = new MyItem6AO(this, 0x00400); - PuffBlock = new Puff6(this, 0x0000); - GameTime = new GameTime6(this, 0x01200); - Situation = new Situation6(this, 0x01400); - Played = new PlayTime6(this, 0x01800); - BoxLayout = new BoxLayout6(this, 0x04400); - BattleBoxBlock = new BattleBox6(this, 0x04A00); - Status = new MyStatus6(this, 0x14000); - Zukan = new Zukan6AO(this, 0x15000, 0x400); - OPowerBlock = new OPower6(this, 0x17400); - MysteryBlock = new MysteryBlock6(this, 0x1CC00); - Records = new Record6(this, 0x1F400, Core.Records.MaxType_AO); - Sango = new SangoInfoBlock(this, 0x2B600); + PCLayout = 0x04400; + BattleBox = 0x04A00; + PSS = 0x05000; + Party = 0x14200; + EventConst = 0x14A00; + PokeDex = 0x15000; + HoF = 0x19E00; + MaisonStats = 0x1BBC0; + Daycare = 0x1BC00; + BerryField = 0x1C400; + WondercardFlags = 0x1CC00; + SuperTrain = 0x20200; + Contest = 0x23600; + SecretBase = 0x23A00; + EonTicket = 0x319B8; + Box = 0x33000; + JPEG = 0x67C00; EventFlag = EventConst + 0x2FC; WondercardData = WondercardFlags + 0x100; Daycare2 = Daycare + 0x1F0; - - HeldItems = Legal.HeldItem_AO; - Personal = PersonalTable.AO; } public int EonTicket { get; private set; } @@ -177,13 +68,25 @@ private void Initialize() public int GTS { get; private set; } public int Fused { get; private set; } - public Zukan6 Zukan { get; private set; } - public Puff6 PuffBlock { get; private set; } - public OPower6 OPowerBlock { get; private set; } - public BoxLayout6 BoxLayout { get; private set; } - public MysteryBlock6 MysteryBlock { get; private set; } - public SangoInfoBlock Sango { get; set; } - public BattleBox6 BattleBoxBlock { get; private set; } + #region Blocks + public override IReadOnlyList AllBlocks => Blocks.BlockInfo; + public override MyItem Items => Blocks.Items; + public override ItemInfo6 ItemInfo => Blocks.ItemInfo; + public override GameTime6 GameTime => Blocks.GameTime; + public override Situation6 Situation => Blocks.Situation; + public override PlayTime6 Played => Blocks.Played; + public override MyStatus6 Status => Blocks.Status; + public override Record6 Records => Blocks.Records; + public Puff6 PuffBlock => Blocks.PuffBlock; + public OPower6 OPowerBlock => Blocks.OPowerBlock; + public Link6 LinkBlock => Blocks.LinkBlock; + public BoxLayout6 BoxLayout => Blocks.BoxLayout; + public BattleBox6 BattleBoxBlock => Blocks.BattleBoxBlock; + public MysteryBlock6 MysteryBlock => Blocks.MysteryBlock; + + public Misc6AO Misc => Blocks.Misc; + public Zukan6AO Zukan => Blocks.Zukan; + #endregion public override GameVersion Version { @@ -198,11 +101,16 @@ public override GameVersion Version } } - public override bool GetCaught(int species) => Zukan.GetCaught(species); - public override bool GetSeen(int species) => Zukan.GetSeen(species); - public override void SetSeen(int species, bool seen) => Zukan.SetSeen(species, seen); - public override void SetCaught(int species, bool caught) => Zukan.SetCaught(species, caught); - protected override void SetDex(PKM pkm) => Zukan.SetDex(pkm); + public override bool GetCaught(int species) => Blocks.Zukan.GetCaught(species); + public override bool GetSeen(int species) => Blocks.Zukan.GetSeen(species); + public override void SetSeen(int species, bool seen) => Blocks.Zukan.SetSeen(species, seen); + public override void SetCaught(int species, bool caught) => Blocks.Zukan.SetCaught(species, caught); + protected override void SetDex(PKM pkm) => Blocks.Zukan.SetDex(pkm); + + public override uint Money { get => Blocks.Misc.Money; set => Blocks.Misc.Money = value; } + public override int Vivillon { get => Blocks.Misc.Vivillon; set => Blocks.Misc.Vivillon = value; } + public override int Badges { get => Blocks.Misc.Badges; set => Blocks.Misc.Badges = value; } + public override int BP { get => Blocks.Misc.BP; set => Blocks.Misc.BP = value; } // Daycare public override int DaycareSeedSize => 16; @@ -211,33 +119,24 @@ public override GameVersion Version public override int GetDaycareSlotOffset(int loc, int slot) { int ofs = loc == 0 ? Daycare : Daycare2; - if (ofs < 0) - return -1; return ofs + 8 + (slot * (SIZE_STORED + 8)); } public override uint? GetDaycareEXP(int loc, int slot) { int ofs = loc == 0 ? Daycare : Daycare2; - if (ofs > -1) - return BitConverter.ToUInt32(Data, ofs + ((SIZE_STORED + 8) * slot) + 4); - return null; + return BitConverter.ToUInt32(Data, ofs + ((SIZE_STORED + 8) * slot) + 4); } public override bool? IsDaycareOccupied(int loc, int slot) { int ofs = loc == 0 ? Daycare : Daycare2; - if (ofs > -1) - return Data[ofs + ((SIZE_STORED + 8) * slot)] == 1; - return null; + return Data[ofs + ((SIZE_STORED + 8) * slot)] == 1; } public override string GetDaycareRNGSeed(int loc) { int ofs = loc == 0 ? Daycare : Daycare2; - if (ofs <= 0) - return null; - var data = Data.Skip(ofs + 0x1E8).Take(DaycareSeedSize / 2).Reverse().ToArray(); return BitConverter.ToString(data).Replace("-", string.Empty); } @@ -245,23 +144,19 @@ public override string GetDaycareRNGSeed(int loc) public override bool? IsDaycareHasEgg(int loc) { int ofs = loc == 0 ? Daycare : Daycare2; - if (ofs > -1) - return Data[ofs + 0x1E0] == 1; - return null; + return Data[ofs + 0x1E0] == 1; } public override void SetDaycareEXP(int loc, int slot, uint EXP) { int ofs = loc == 0 ? Daycare : Daycare2; - if (ofs > -1) - BitConverter.GetBytes(EXP).CopyTo(Data, ofs + ((SIZE_STORED + 8) * slot) + 4); + BitConverter.GetBytes(EXP).CopyTo(Data, ofs + ((SIZE_STORED + 8) * slot) + 4); } public override void SetDaycareOccupied(int loc, int slot, bool occupied) { int ofs = loc == 0 ? Daycare : Daycare2; - if (ofs > -1) - Data[ofs + ((SIZE_STORED + 8) * slot)] = (byte)(occupied ? 1 : 0); + Data[ofs + ((SIZE_STORED + 8) * slot)] = (byte)(occupied ? 1 : 0); } public override void SetDaycareRNGSeed(int loc, string seed) @@ -270,8 +165,6 @@ public override void SetDaycareRNGSeed(int loc, string seed) return; if (Daycare < 0) return; - if (seed == null) - return; if (seed.Length > DaycareSeedSize) return; @@ -281,8 +174,7 @@ public override void SetDaycareRNGSeed(int loc, string seed) public override void SetDaycareHasEgg(int loc, bool hasEgg) { int ofs = loc == 0 ? Daycare : Daycare2; - if (ofs > -1) - Data[ofs + 0x1E0] = (byte)(hasEgg ? 1 : 0); + Data[ofs + 0x1E0] = (byte)(hasEgg ? 1 : 0); } public override string JPEGTitle => HasJPPEGData ? string.Empty : Util.TrimFromZero(Encoding.Unicode.GetString(Data, JPEG, 0x1A)); @@ -290,8 +182,8 @@ public override void SetDaycareHasEgg(int loc, bool hasEgg) private bool HasJPPEGData => Data[JPEG + 0x54] == 0xFF; - protected override bool[] MysteryGiftReceivedFlags { get => MysteryBlock.MysteryGiftReceivedFlags; set => MysteryBlock.MysteryGiftReceivedFlags = value; } - protected override MysteryGift[] MysteryGiftCards { get => MysteryBlock.MysteryGiftCards; set => MysteryBlock.MysteryGiftCards = value; } + protected override bool[] MysteryGiftReceivedFlags { get => Blocks.MysteryBlock.MysteryGiftReceivedFlags; set => Blocks.MysteryBlock.MysteryGiftReceivedFlags = value; } + protected override DataMysteryGift[] MysteryGiftCards { get => Blocks.MysteryBlock.MysteryGiftCards; set => Blocks.MysteryBlock.MysteryGiftCards = value; } // Gym History public ushort[][] GymTeams @@ -321,26 +213,15 @@ public ushort[][] GymTeams } } - public byte[] LinkBlock - { - get => GetData(LinkInfo, 0xC48); - set - { - if (value.Length != 0xC48) - throw new ArgumentException(nameof(value)); - SetData(value, LinkInfo); - } - } - - public override int CurrentBox { get => BoxLayout.CurrentBox; set => BoxLayout.CurrentBox = value; } - protected override int GetBoxWallpaperOffset(int box) => BoxLayout.GetBoxWallpaperOffset(box); - public override int BoxesUnlocked { get => BoxLayout.BoxesUnlocked; set => BoxLayout.BoxesUnlocked = value; } - public override byte[] BoxFlags { get => BoxLayout.BoxFlags; set => BoxLayout.BoxFlags = value; } + public override int CurrentBox { get => Blocks.BoxLayout.CurrentBox; set => Blocks.BoxLayout.CurrentBox = value; } + protected override int GetBoxWallpaperOffset(int box) => Blocks.BoxLayout.GetBoxWallpaperOffset(box); + public override int BoxesUnlocked { get => Blocks.BoxLayout.BoxesUnlocked; set => Blocks.BoxLayout.BoxesUnlocked = value; } + public override byte[] BoxFlags { get => Blocks.BoxLayout.BoxFlags; set => Blocks.BoxLayout.BoxFlags = value; } public override bool BattleBoxLocked { - get => BattleBoxBlock.Locked; - set => BattleBoxBlock.Locked = value; + get => Blocks.BattleBoxBlock.Locked; + set => Blocks.BattleBoxBlock.Locked = value; } } } diff --git a/PKHeX.Core/Saves/SAV6AODemo.cs b/PKHeX.Core/Saves/SAV6AODemo.cs index 505ac1aee..f8b10f883 100644 --- a/PKHeX.Core/Saves/SAV6AODemo.cs +++ b/PKHeX.Core/Saves/SAV6AODemo.cs @@ -1,4 +1,6 @@ -namespace PKHeX.Core +using System.Collections.Generic; + +namespace PKHeX.Core { /// /// Generation 6 object for . @@ -6,65 +8,32 @@ /// public sealed class SAV6AODemo : SAV6 { - public SAV6AODemo(byte[] data) : base(data, BlocksAODemo, boAOdemo) => Initialize(); - public SAV6AODemo() : base(SaveUtil.SIZE_G6ORASDEMO, BlocksAODemo, boAOdemo) => Initialize(); + public SAV6AODemo(byte[] data) : base(data, SaveBlockAccessorAODemo.boAOdemo) + { + Blocks = new SaveBlockAccessorAODemo(this); + Initialize(); + } + + public SAV6AODemo() : base(SaveUtil.SIZE_G6ORASDEMO, SaveBlockAccessorAODemo.boAOdemo) + { + Blocks = new SaveBlockAccessorAODemo(this); + Initialize(); + } + + public override PersonalTable Personal => PersonalTable.AO; + public override IReadOnlyList HeldItems => Legal.HeldItem_AO; public override SaveFile Clone() => new SAV6AODemo((byte[])Data.Clone()); public override int MaxMoveID => Legal.MaxMoveID_6_AO; public override int MaxItemID => Legal.MaxItemID_6_AO; public override int MaxAbilityID => Legal.MaxAbilityID_6_AO; - - private const int boAOdemo = SaveUtil.SIZE_G6ORASDEMO - 0x200; - - public static readonly BlockInfo[] BlocksAODemo = - { - new BlockInfo6 (boAOdemo, 00, 0x00000, 0x00B90), - new BlockInfo6 (boAOdemo, 01, 0x00C00, 0x0002C), - new BlockInfo6 (boAOdemo, 02, 0x00E00, 0x00038), - new BlockInfo6 (boAOdemo, 03, 0x01000, 0x00150), - new BlockInfo6 (boAOdemo, 04, 0x01200, 0x00004), - new BlockInfo6 (boAOdemo, 05, 0x01400, 0x00008), - new BlockInfo6 (boAOdemo, 06, 0x01600, 0x00024), - new BlockInfo6 (boAOdemo, 07, 0x01800, 0x02100), - new BlockInfo6 (boAOdemo, 08, 0x03A00, 0x00130), - new BlockInfo6 (boAOdemo, 09, 0x03C00, 0x00170), - new BlockInfo6 (boAOdemo, 10, 0x03E00, 0x0061C), - new BlockInfo6 (boAOdemo, 11, 0x04600, 0x00504), - new BlockInfo6 (boAOdemo, 12, 0x04C00, 0x00004), - new BlockInfo6 (boAOdemo, 13, 0x04E00, 0x00048), - new BlockInfo6 (boAOdemo, 14, 0x05000, 0x00400), - new BlockInfo6 (boAOdemo, 15, 0x05400, 0x0025C), - }; + public SaveBlockAccessorAODemo Blocks { get; } private void Initialize() { - /* 00: */ // MyItem = 0x00000; // MyItem // Bag - /* 01: */ // ItemInfo = 0x00C00; // ItemInfo6 - /* 02: */ // GameTime = 0x00E00; // GameTime - /* 03: */ // Trainer1 = 0x01000; // Situation - /* 04: */ // = 0x01200; // [00004] RandomGroup (rand seeds) - /* 05: */ // PlayTime = 0x01400; // PlayTime - /* 06: */ // = 0x01600; // [00024] temp variables (u32 id + 32 u8) - /* 07: */ // = 0x01800; // [02100] FieldMoveModelSave - /* 08: */ Trainer2 = 0x03A00; // Misc - /* 09: */ // = 0x03C00; // MyStatus - /* 10: */ Party = 0x03E00; // PokePartySave - /* 11: */ EventConst = 0x04600; // EventWork - /* 12: */ // = 0x04C00; // [00004] Packed Menu Bits - /* 13: */ // = 0x04E00; // [00048] Repel Info, (Swarm?) and other overworld info (roamer) - /* 14: */ SUBE = 0x05000; // PokeDiarySave - /* 15: */ // Record = 0x05400; // Record + Party = 0x03E00; + EventConst = 0x04600; - Items = new MyItem6AO( this, 0x00000); - ItemInfo = new ItemInfo6( this, 0x00C00); - GameTime = new GameTime6( this, 0x00E00); - Situation = new Situation6(this, 0x01000); - Played = new PlayTime6( this, 0x01400); - Status = new MyStatus6( this, 0x03C00); - Records = new Record6(this, 0x05400, Core.Records.MaxType_AO); EventFlag = EventConst + 0x2FC; - - HeldItems = Legal.HeldItem_AO; - Personal = PersonalTable.AO; } public override GameVersion Version @@ -79,5 +48,18 @@ public override GameVersion Version return GameVersion.Invalid; } } + + public override uint Money { get => Blocks.Misc.Money; set => Blocks.Misc.Money = value; } + public override int Vivillon { get => Blocks.Misc.Vivillon; set => Blocks.Misc.Vivillon = value; } // unused + public override int Badges { get => Blocks.Misc.Badges; set => Blocks.Misc.Badges = value; } // unused + public override int BP { get => Blocks.Misc.BP; set => Blocks.Misc.BP = value; } // unused + public override MyItem Items => Blocks.Items; + public override ItemInfo6 ItemInfo => Blocks.ItemInfo; + public override GameTime6 GameTime => Blocks.GameTime; + public override Situation6 Situation => Blocks.Situation; + public override PlayTime6 Played => Blocks.Played; + public override MyStatus6 Status => Blocks.Status; + public override Record6 Records => Blocks.Records; + public override IReadOnlyList AllBlocks => Blocks.BlockInfo; } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/SAV6XY.cs b/PKHeX.Core/Saves/SAV6XY.cs index 591cd17a7..5fdc8ffe6 100644 --- a/PKHeX.Core/Saves/SAV6XY.cs +++ b/PKHeX.Core/Saves/SAV6XY.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Text; namespace PKHeX.Core @@ -7,170 +8,77 @@ namespace PKHeX.Core /// Generation 6 object for . /// /// - public sealed class SAV6XY : SAV6, IPokePuff, IOPower, ILink + public sealed class SAV6XY : SAV6, ISaveBlock6Main { - public SAV6XY(byte[] data) : base(data, BlocksXY, boXY) => Initialize(); - - public SAV6XY() : base(SaveUtil.SIZE_G6XY, BlocksXY, boXY) + public SAV6XY(byte[] data) : base(data, SaveBlockAccessorXY.boXY) { + Blocks = new SaveBlockAccessorXY(this); + Initialize(); + } + + public SAV6XY() : base(SaveUtil.SIZE_G6XY, SaveBlockAccessorXY.boXY) + { + Blocks = new SaveBlockAccessorXY(this); Initialize(); ClearBoxes(); } + public override PersonalTable Personal => PersonalTable.XY; + public override IReadOnlyList HeldItems => Legal.HeldItem_XY; + public SaveBlockAccessorXY Blocks { get; } public override SaveFile Clone() => new SAV6XY((byte[])Data.Clone()); public override int MaxMoveID => Legal.MaxMoveID_6_XY; public override int MaxItemID => Legal.MaxItemID_6_XY; public override int MaxAbilityID => Legal.MaxAbilityID_6_XY; - private const int boXY = SaveUtil.SIZE_G6XY - 0x200; - - public static readonly BlockInfo[] BlocksXY = - { - new BlockInfo6(boXY, 00, 0x00000, 0x002C8), - new BlockInfo6(boXY, 01, 0x00400, 0x00B88), - new BlockInfo6(boXY, 02, 0x01000, 0x0002C), - new BlockInfo6(boXY, 03, 0x01200, 0x00038), - new BlockInfo6(boXY, 04, 0x01400, 0x00150), - new BlockInfo6(boXY, 05, 0x01600, 0x00004), - new BlockInfo6(boXY, 06, 0x01800, 0x00008), - new BlockInfo6(boXY, 07, 0x01A00, 0x001C0), - new BlockInfo6(boXY, 08, 0x01C00, 0x000BE), - new BlockInfo6(boXY, 09, 0x01E00, 0x00024), - new BlockInfo6(boXY, 10, 0x02000, 0x02100), - new BlockInfo6(boXY, 11, 0x04200, 0x00140), - new BlockInfo6(boXY, 12, 0x04400, 0x00440), - new BlockInfo6(boXY, 13, 0x04A00, 0x00574), - new BlockInfo6(boXY, 14, 0x05000, 0x04E28), - new BlockInfo6(boXY, 15, 0x0A000, 0x04E28), - new BlockInfo6(boXY, 16, 0x0F000, 0x04E28), - new BlockInfo6(boXY, 17, 0x14000, 0x00170), - new BlockInfo6(boXY, 18, 0x14200, 0x0061C), - new BlockInfo6(boXY, 19, 0x14A00, 0x00504), - new BlockInfo6(boXY, 20, 0x15000, 0x006A0), - new BlockInfo6(boXY, 21, 0x15800, 0x00644), - new BlockInfo6(boXY, 22, 0x16000, 0x00104), - new BlockInfo6(boXY, 23, 0x16200, 0x00004), - new BlockInfo6(boXY, 24, 0x16400, 0x00420), - new BlockInfo6(boXY, 25, 0x16A00, 0x00064), - new BlockInfo6(boXY, 26, 0x16C00, 0x003F0), - new BlockInfo6(boXY, 27, 0x17000, 0x0070C), - new BlockInfo6(boXY, 28, 0x17800, 0x00180), - new BlockInfo6(boXY, 29, 0x17A00, 0x00004), - new BlockInfo6(boXY, 30, 0x17C00, 0x0000C), - new BlockInfo6(boXY, 31, 0x17E00, 0x00048), - new BlockInfo6(boXY, 32, 0x18000, 0x00054), - new BlockInfo6(boXY, 33, 0x18200, 0x00644), - new BlockInfo6(boXY, 34, 0x18A00, 0x005C8), - new BlockInfo6(boXY, 35, 0x19000, 0x002F8), - new BlockInfo6(boXY, 36, 0x19400, 0x01B40), - new BlockInfo6(boXY, 37, 0x1B000, 0x001F4), - new BlockInfo6(boXY, 38, 0x1B200, 0x001F0), - new BlockInfo6(boXY, 39, 0x1B400, 0x00216), - new BlockInfo6(boXY, 40, 0x1B800, 0x00390), - new BlockInfo6(boXY, 41, 0x1BC00, 0x01A90), - new BlockInfo6(boXY, 42, 0x1D800, 0x00308), - new BlockInfo6(boXY, 43, 0x1DC00, 0x00618), - new BlockInfo6(boXY, 44, 0x1E400, 0x0025C), - new BlockInfo6(boXY, 45, 0x1E800, 0x00834), - new BlockInfo6(boXY, 46, 0x1F200, 0x00318), - new BlockInfo6(boXY, 47, 0x1F600, 0x007D0), - new BlockInfo6(boXY, 48, 0x1FE00, 0x00C48), - new BlockInfo6(boXY, 49, 0x20C00, 0x00078), - new BlockInfo6(boXY, 50, 0x20E00, 0x00200), - new BlockInfo6(boXY, 51, 0x21000, 0x00C84), - new BlockInfo6(boXY, 52, 0x21E00, 0x00628), - new BlockInfo6(boXY, 53, 0x22600, 0x34AD0), - new BlockInfo6(boXY, 54, 0x57200, 0x0E058), - }; - private void Initialize() { - /* 00: 00000-002C8, 002C8 */ // Puff = 0x00000; - /* 01: 00400-00F88, 00B88 */ // MyItem = 0x00400; // Bag - /* 02: 01000-0102C, 0002C */ // ItemInfo = 0x1000; // Select Bound Items - /* 03: 01200-01238, 00038 */ // GameTime = 0x01200; - /* 04: 01400-01550, 00150 */ Trainer1 = 0x1400; // Situation - /* 05: 01600-01604, 00004 */ // RandomGroup (rand seeds) - /* 06: 01800-01808, 00008 */ // PlayTime - /* 07: 01A00-01BC0, 001C0 */ Accessories = 0x1A00; // Fashion - /* 08: 01C00-01CBE, 000BE */ // amie minigame records - /* 09: 01E00-01E24, 00024 */ // temp variables (u32 id + 32 u8) - /* 10: 02000-04100, 02100 */ // FieldMoveModelSave - /* 11: 04200-04340, 00140 */ Trainer2 = 0x4200; // Misc - /* 12: 04400-04840, 00440 */ PCLayout = 0x4400; // BOX - /* 13: 04A00-04F74, 00574 */ BattleBox = 0x04A00; // BattleBox - /* 14: 05000-09E28, 04E28 */ PSS = 0x05000; - /* 15: 0A000-0EE28, 04E28 */ // PSS2 - /* 16: 0F000-13E28, 04E28 */ // PSS3 - /* 17: 14000-14170, 00170 */ // MyStatus - /* 18: 14200-1481C, 0061C */ Party = 0x14200; // PokePartySave - /* 19: 14A00-14F04, 00504 */ EventConst = 0x14A00; // EventWork - /* 20: 15000-156A0, 006A0 */ PokeDex = 0x15000; // ZukanData - /* 21: 15800-15E44, 00644 */ // hologram clips - /* 22: 16000-16104, 00104 */ Fused = 0x16000; // UnionPokemon - /* 23: 16200-16204, 00004 */ // ConfigSave - /* 24: 16400-16820, 00420 */ // Amie decoration stuff - /* 25: 16A00-16A64, 00064 */ // OPower = 0x16A00; - /* 26: 16C00-16FF0, 003F0 */ // Strength Rock position (xyz float: 84 entries, 12bytes/entry) - /* 27: 17000-1770C, 0070C */ // Trainer PR Video - /* 28: 17800-17980, 00180 */ GTS = 0x17800; // GtsData - /* 29: 17A00-17A04, 00004 */ // Packed Menu Bits - /* 30: 17C00-17C0C, 0000C */ // PSS Profile Q&A (6*questions, 6*answer) - /* 31: 17E00-17E48, 00048 */ // Repel Info, (Swarm?) and other overworld info (roamer) - /* 32: 18000-18054, 00054 */ // BOSS data fetch history (serial/mystery gift), 4byte intro & 20*4byte entries - /* 33: 18200-18844, 00644 */ // Streetpass history (4 byte intro, 20*4byte entries, 20*76 byte entries) - /* 34: 18A00-18FC8, 005C8 */ // LiveMatchData/BattleSpotData - /* 35: 19000-192F8, 002F8 */ // MAC Address & Network Connection Logging (0x98 per entry, 5 entries) - /* 36: 19400-1AF40, 01B40 */ HoF = 0x19400; // Dendou - /* 37: 1B000-1B1F4, 001F4 */ MaisonStats = 0x1B1C0; // BattleInstSave - /* 38: 1B200-1B3F0, 001F0 */ Daycare = 0x1B200; // Sodateya - /* 39: 1B400-1B616, 00216 */ // BattleInstSave - /* 40: 1B800-1BB90, 00390 */ BerryField = 0x1B800; - /* 41: 1BC00-1D690, 01A90 */ WondercardFlags = 0x1BC00; // MysteryGiftSave - /* 42: 1D800-1DB08, 00308 */ SUBE = 0x1D890; // PokeDiarySave - /* 43: 1DC00-1E218, 00618 */ // Storyline Records - /* 44: 1E400-1E65C, 0025C */ // Record = 0x1E400; - /* 45: 1E800-1F034, 00834 */ // Friend Safari (0x15 per entry, 100 entries) - /* 46: 1F200-1F518, 00318 */ SuperTrain = 0x1F200; - /* 47: 1F600-1FDD0, 007D0 */ // Unused (lmao) - /* 48: 1FE00-20A48, 00C48 */ LinkInfo = 0x1FE00; - /* 49: 20C00-20C78, 00078 */ // PSS usage info - /* 50: 20E00-21000, 00200 */ // GameSyncSave - /* 51: 21000-21C84, 00C84 */ // PSS Icon (bool32 data present, 40x40 u16 pic, unused) - /* 52: 21E00-22428, 00628 */ // ValidationSave (updatabale Public Key for legal check api calls) - /* 53: 22600-570D0, 34AD0 */ Box = 0x22600; - /* 54: 57200-65258, 0E058 */ JPEG = 0x57200; - - Items = new MyItem6XY(this, 0x00400); - PuffBlock = new Puff6(this, 0x00000); - GameTime = new GameTime6(this, 0x01200); - Situation = new Situation6(this, 0x01400); - Played = new PlayTime6(this, 0x01800); - BoxLayout = new BoxLayout6(this, 0x4400); - BattleBoxBlock = new BattleBox6(this, 0x04A00); - Status = new MyStatus6XY(this, 0x14000); - Zukan = new Zukan6XY(this, 0x15000, 0x3C8); - OPowerBlock = new OPower6(this, 0x16A00); - MysteryBlock = new MysteryBlock6(this, 0x1BC00); - Records = new Record6(this, 0x1E400, Core.Records.MaxType_XY); + // Enable Features + Party = 0x14200; + PCLayout = 0x4400; + BattleBox = 0x04A00; + PSS = 0x05000; + EventConst = 0x14A00; + PokeDex = 0x15000; + HoF = 0x19400; + MaisonStats = 0x1B1C0; + Daycare = 0x1B200; + BerryField = 0x1B800; + WondercardFlags = 0x1BC00; + SuperTrain = 0x1F200; + Box = 0x22600; + JPEG = 0x57200; EventFlag = EventConst + 0x2FC; WondercardData = WondercardFlags + 0x100; - HeldItems = Legal.HeldItem_XY; - Personal = PersonalTable.XY; + // Extra Viewable Slots + Fused = 0x16000; + GTS = 0x17800; + SUBE = 0x1D890; } - public Zukan6 Zukan { get; private set; } - public Puff6 PuffBlock { get; private set; } - public OPower6 OPowerBlock { get; private set; } - public BoxLayout6 BoxLayout { get; private set; } - public MysteryBlock6 MysteryBlock { get; private set; } - public BattleBox6 BattleBoxBlock { get; private set; } public int GTS { get; private set; } = int.MinValue; public int Fused { get; private set; } = int.MinValue; - protected override void SetDex(PKM pkm) => Zukan.SetDex(pkm); + #region Blocks + public override IReadOnlyList AllBlocks => Blocks.BlockInfo; + public override MyItem Items => Blocks.Items; + public override ItemInfo6 ItemInfo => Blocks.ItemInfo; + public override GameTime6 GameTime => Blocks.GameTime; + public override Situation6 Situation => Blocks.Situation; + public override PlayTime6 Played => Blocks.Played; + public override MyStatus6 Status => Blocks.Status; + public override Record6 Records => Blocks.Records; + public Puff6 PuffBlock => Blocks.PuffBlock; + public OPower6 OPowerBlock => Blocks.OPowerBlock; + public Link6 LinkBlock => Blocks.LinkBlock; + public BoxLayout6 BoxLayout => Blocks.BoxLayout; + public BattleBox6 BattleBoxBlock => Blocks.BattleBoxBlock; + public MysteryBlock6 MysteryBlock => Blocks.MysteryBlock; + #endregion + + protected override void SetDex(PKM pkm) => Blocks.Zukan.SetDex(pkm); // Daycare public override int DaycareSeedSize => 16; @@ -190,8 +98,6 @@ public override void SetDaycareRNGSeed(int loc, string seed) return; if (Daycare < 0) return; - if (seed == null) - return; if (seed.Length > DaycareSeedSize) return; @@ -244,23 +150,7 @@ public void UnlockAllFriendSafariSlots() } Edited = true; } - - public void UnlockAllAccessories() - { - SetData(AllAccessories, Accessories); - } - - private static readonly byte[] AllAccessories = - { - 0xFE,0xFF,0xFF,0x7E,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xEF,0xFF,0xFF,0xFF,0xF9,0xFF,0xFB,0xFF,0xF7,0xFF,0xFF,0x0F,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF, - 0xFF,0x7E,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF, - 0xFF,0xFF,0xFF,0xF9,0xFF,0xFB,0xFF,0xF7,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 - }; - + public override GameVersion Version { get @@ -274,34 +164,28 @@ public override GameVersion Version } } - protected override bool[] MysteryGiftReceivedFlags { get => MysteryBlock.MysteryGiftReceivedFlags; set => MysteryBlock.MysteryGiftReceivedFlags = value; } - protected override MysteryGift[] MysteryGiftCards { get => MysteryBlock.MysteryGiftCards; set => MysteryBlock.MysteryGiftCards = value; } + protected override bool[] MysteryGiftReceivedFlags { get => Blocks.MysteryBlock.MysteryGiftReceivedFlags; set => Blocks.MysteryBlock.MysteryGiftReceivedFlags = value; } + protected override DataMysteryGift[] MysteryGiftCards { get => Blocks.MysteryBlock.MysteryGiftCards; set => Blocks.MysteryBlock.MysteryGiftCards = value; } + + public override bool GetCaught(int species) => Blocks.Zukan.GetCaught(species); + public override bool GetSeen(int species) => Blocks.Zukan.GetSeen(species); + public override void SetSeen(int species, bool seen) => Blocks.Zukan.SetSeen(species, seen); + public override void SetCaught(int species, bool caught) => Blocks.Zukan.SetCaught(species, caught); - public byte[] LinkBlock - { - get => GetData(LinkInfo, 0xC48); - set - { - if (value.Length != 0xC48) - throw new ArgumentException(nameof(value)); - value.CopyTo(Data, LinkInfo); - } - } - - public override bool GetCaught(int species) => Zukan.GetCaught(species); - public override bool GetSeen(int species) => Zukan.GetSeen(species); - public override void SetSeen(int species, bool seen) => Zukan.SetSeen(species, seen); - public override void SetCaught(int species, bool caught) => Zukan.SetCaught(species, caught); - - public override int CurrentBox { get => BoxLayout.CurrentBox; set => BoxLayout.CurrentBox = value; } - protected override int GetBoxWallpaperOffset(int box) => BoxLayout.GetBoxWallpaperOffset(box); - public override int BoxesUnlocked { get => BoxLayout.BoxesUnlocked; set => BoxLayout.BoxesUnlocked = value; } - public override byte[] BoxFlags { get => BoxLayout.BoxFlags; set => BoxLayout.BoxFlags = value; } + public override int CurrentBox { get => Blocks.BoxLayout.CurrentBox; set => Blocks.BoxLayout.CurrentBox = value; } + protected override int GetBoxWallpaperOffset(int box) => Blocks.BoxLayout.GetBoxWallpaperOffset(box); + public override int BoxesUnlocked { get => Blocks.BoxLayout.BoxesUnlocked; set => Blocks.BoxLayout.BoxesUnlocked = value; } + public override byte[] BoxFlags { get => Blocks.BoxLayout.BoxFlags; set => Blocks.BoxLayout.BoxFlags = value; } public override bool BattleBoxLocked { - get => BattleBoxBlock.Locked; - set => BattleBoxBlock.Locked = value; + get => Blocks.BattleBoxBlock.Locked; + set => Blocks.BattleBoxBlock.Locked = value; } + + public override uint Money { get => Blocks.Misc.Money; set => Blocks.Misc.Money = value; } + public override int Vivillon { get => Blocks.Misc.Vivillon; set => Blocks.Misc.Vivillon = value; } + public override int Badges { get => Blocks.Misc.Badges; set => Blocks.Misc.Badges = value; } + public override int BP { get => Blocks.Misc.BP; set => Blocks.Misc.BP = value; } } } diff --git a/PKHeX.Core/Saves/SAV7.cs b/PKHeX.Core/Saves/SAV7.cs index de3e88ea0..393d43019 100644 --- a/PKHeX.Core/Saves/SAV7.cs +++ b/PKHeX.Core/Saves/SAV7.cs @@ -7,7 +7,7 @@ namespace PKHeX.Core /// /// Generation 7 object. /// - public abstract class SAV7 : SAV_BEEF, ITrainerStatRecord + public abstract class SAV7 : SAV_BEEF, ITrainerStatRecord, ISaveBlock7Main { // Save Data Attributes protected override string BAKText => $"{OT} ({Version}) - {Played.LastSavedTime}"; @@ -20,27 +20,17 @@ public abstract class SAV7 : SAV_BEEF, ITrainerStatRecord return gen <= 7 && f[1] != 'b'; // ignore PB7 }).ToArray(); - protected SAV7(byte[] data, BlockInfo[] blocks, int biOffset) : base(data, blocks, biOffset) + protected SAV7(byte[] data, int biOffset) : base(data, biOffset) { - Initialize(); - ClearMemeCrypto(); } - protected SAV7(int size, BlockInfo[] blocks, int biOffset) : base(size, blocks, biOffset) + protected SAV7(int size, int biOffset) : base(size, biOffset) { - Initialize(); - ClearBoxes(); } - private void Initialize() + protected void ReloadBattleTeams() { - GetSAVOffsets(); - ReloadBattleTeams(); - } - - private void ReloadBattleTeams() - { - var demo = this is SAV7SM && Data.IsRangeAll(0, PCLayout, 0x4C4); // up to Battle Box values + var demo = this is SAV7SM && Data.IsRangeAll(0, BoxLayout.Offset, 0x4C4); // up to Battle Box values if (demo || !Exportable) { BoxLayout.ClearBattleTeams(); @@ -51,6 +41,28 @@ private void ReloadBattleTeams() } } + #region Blocks + public abstract MyItem Items { get; } + public abstract MysteryBlock7 MysteryBlock { get; } + public abstract PokeFinder7 PokeFinder { get; } + public abstract JoinFesta7 Festa { get; } + public abstract Daycare7 DaycareBlock { get; } + public abstract Record6 Records { get; } + public abstract PlayTime6 Played { get; } + public abstract MyStatus7 MyStatus { get; } + public abstract FieldMoveModelSave7 OverworldBlock { get; } + public abstract Situation7 Situation { get; } + public abstract ConfigSave7 Config { get; } + public abstract GameTime7 GameTime { get; } + public abstract Misc7 MiscBlock { get; } + public abstract Zukan7 Zukan { get; } + public abstract BoxLayout7 BoxLayout { get; } + public abstract BattleTree7 BattleTreeBlock { get; } + public abstract ResortSave7 ResortSave { get; } + public abstract FieldMenu7 FieldMenu { get; } + public abstract FashionBlock7 FashionBlock { get; } + #endregion + // Configuration public override int SIZE_STORED => PKX.SIZE_6STORED; protected override int SIZE_PARTY => PKX.SIZE_6PARTY; @@ -76,15 +88,15 @@ private void ReloadBattleTeams() // Blocks & Offsets private const int MemeCryptoBlock = 36; - private void ClearMemeCrypto() + protected void ClearMemeCrypto() { - new byte[0x80].CopyTo(Data, Blocks[MemeCryptoBlock].Offset + 0x100); + new byte[0x80].CopyTo(Data, AllBlocks[MemeCryptoBlock].Offset + 0x100); } protected override void SetChecksums() { BoxLayout.SaveBattleTeams(); - Blocks.SetChecksums(Data); + AllBlocks.SetChecksums(Data); } protected override byte[] GetFinalData() @@ -95,120 +107,7 @@ protected override byte[] GetFinalData() return result; } - private void GetSAVOffsets() - { - /* 00 */ Bag = Blocks[00].Offset; // 0x00000 // [DE0] MyItem - /* 01 */ Trainer1 = Blocks[01].Offset; // 0x00E00 // [07C] Situation - /* 02 */ // = Blocks[02].Offset; // 0x01000 // [014] RandomGroup - /* 03 */ TrainerCard = Blocks[03].Offset; // 0x01200 // [0C0] MyStatus - /* 04 */ Party = Blocks[04].Offset; // 0x01400 // [61C] PokePartySave - /* 05 */ EventConst = Blocks[05].Offset; // 0x01C00 // [E00] EventWork - /* 06 */ PokeDex = Blocks[06].Offset; // 0x02A00 // [F78] ZukanData - /* 07 */ GTS = Blocks[07].Offset; // 0x03A00 // [228] GtsData - /* 08 */ Fused = Blocks[08].Offset; // 0x03E00 // [104] UnionPokemon - /* 09 */ Misc = Blocks[09].Offset; // 0x04000 // [200] Misc - /* 10 */ Trainer2 = Blocks[10].Offset; // 0x04200 // [020] FieldMenu - /* 11 */ ConfigSave = Blocks[11].Offset; // 0x04400 // [004] ConfigSave - /* 12 */ AdventureInfo = Blocks[12].Offset; // 0x04600 // [058] GameTime - /* 13 */ PCLayout = Blocks[13].Offset; // 0x04800 // [5E6] BOX - /* 14 */ Box = Blocks[14].Offset; // 0x04E00 // [36600] BoxPokemon - /* 15 */ Resort = Blocks[15].Offset; // 0x3B400 // [572C] ResortSave - /* 16 */ PlayTime = Blocks[16].Offset; // 0x40C00 // [008] PlayTime - /* 17 */ Overworld = Blocks[17].Offset; // 0x40E00 // [1080] FieldMoveModelSave - /* 18 */ Fashion = Blocks[18].Offset; // 0x42000 // [1A08] Fashion - /* 19 */ // = Blocks[19].Offset; // 0x43C00 // [6408] JoinFestaPersonalSave - /* 20 */ // = Blocks[20].Offset; // 0x4A200 // [6408] JoinFestaPersonalSave - /* 21 */ JoinFestaData = Blocks[21].Offset; // 0x50800 // [3998] JoinFestaDataSave - /* 22 */ // = Blocks[22].Offset; // 0x54200 // [100] BerrySpot - /* 23 */ // = Blocks[23].Offset; // 0x54400 // [100] FishingSpot - /* 24 */ // = Blocks[24].Offset; // 0x54600 // [10528] LiveMatchData - /* 25 */ // = Blocks[25].Offset; // 0x64C00 // [204] BattleSpotData - /* 26 */ PokeFinderSave = Blocks[26].Offset; // 0x65000 // [B60] PokeFinderSave - /* 27 */ WondercardFlags= Blocks[27].Offset; // 0x65C00 // [3F50] MysteryGiftSave - /* 28 */ Record = Blocks[28].Offset; // 0x69C00 // [358] Record - /* 29 */ // = Blocks[29].Offset; // 0x6A000 // [728] ValidationSave - /* 30 */ // = Blocks[30].Offset; // 0x6A800 // [200] GameSyncSave - /* 31 */ // = Blocks[31].Offset; // 0x6AA00 // [718] PokeDiarySave - /* 32 */ BattleTree = Blocks[32].Offset; // 0x6B200 // [1FC] BattleInstSave - /* 33 */ Daycare = Blocks[33].Offset; // 0x6B400 // [200] Sodateya - /* 34 */ // = Blocks[34].Offset; // 0x6B600 // [120] WeatherSave - /* 35 */ QRSaveData = Blocks[35].Offset; // 0x6B800 // [1C8] QRReaderSaveData - /* 36 */ // = Blocks[36].Offset; // 0x6BA00 // [200] TurtleSalmonSave - - // USUM only - /* 37 */ // = Blocks[37].Offset; BattleFesSave - /* 38 */ // = Blocks[38].Offset; FinderStudioSave - - EventFlag = EventConst + (EventConstMax * 2); // After Event Const (u16)*n - HoF = EventFlag + (EventFlagMax / 8); // After Event Flags (1b)*(1u8/8b)*n - - PokeDexLanguageFlags = 0x550; - WondercardData = WondercardFlags + 0x100; - - Played = new PlayTime6(this, PlayTime); - MysteryBlock = new MysteryBlock7(this, WondercardFlags); - PokeFinder = new PokeFinder7(this, PokeFinderSave); - Festa = new JoinFesta7(this, JoinFestaData); - DaycareBlock = new Daycare7(this, Daycare); - Situation = new Situation7(this, Trainer1); - MyStatus = new MyStatus7(this, TrainerCard); - OverworldBlock = new FieldMoveModelSave7(this, Overworld); - Config = new ConfigSave7(this, ConfigSave); - GameTime = new GameTime7(this, AdventureInfo); - MiscBlock = new Misc7(this, Misc); - BoxLayout = new BoxLayout7(this, PCLayout); - BattleTreeBlock = new BattleTree7(this, BattleTree); - ResortSave = new ResortSave7(this, Resort); - FieldMenu = new FieldMenu7(this, Trainer2); - FashionBlock = new FashionBlock7(this, Fashion); - - TeamSlots = BoxLayout.TeamSlots; - } - - // Private Only - protected int Bag { get; set; } - private int AdventureInfo { get; set; } - private int Trainer2 { get; set; } - public int Misc { get; private set; } - private int WondercardFlags { get; set; } - private int PlayTime { get; set; } - private int Overworld { get; set; } - public int JoinFestaData { get; private set; } - private int PokeFinderSave { get; set; } - private int BattleTree { get; set; } - private int ConfigSave { get; set; } - public int QRSaveData { get; set; } - private int PCLayout { get; set; } - public int HoF { get; private set; } - public int GTS { get; protected set; } - public int Fused { get; protected set; } - - protected MyItem Items { private get; set; } - protected MysteryBlock7 MysteryBlock { private get; set; } - public PokeFinder7 PokeFinder { get; private set; } - public JoinFesta7 Festa { get; private set; } - private Daycare7 DaycareBlock { get; set; } - protected Record6 Records { get; set; } - public PlayTime6 Played { get; set; } - public MyStatus7 MyStatus { get; private set; } - public FieldMoveModelSave7 OverworldBlock { get; private set; } - public Situation7 Situation { get; private set; } - public ConfigSave7 Config { get; private set; } - public GameTime7 GameTime { get; private set; } - public Misc7 MiscBlock { get; private set; } - public Zukan7 Zukan { get; protected set; } - private BoxLayout7 BoxLayout { get; set; } - public BattleTree7 BattleTreeBlock { get; private set; } - public ResortSave7 ResortSave { get; private set; } - public FieldMenu7 FieldMenu { get; private set; } - public FashionBlock7 FashionBlock { get; private set; } - - // Accessible as SAV7 - private int TrainerCard { get; set; } = 0x14000; - private int Resort { get; set; } - public int PokeDexLanguageFlags { get; private set; } - public int Fashion { get; set; } = int.MinValue; - protected int Record { get; set; } = int.MinValue; + public int HoF { get; protected set; } public override GameVersion Version { @@ -225,7 +124,6 @@ public override GameVersion Version } } - public override string MiscSaveInfo() => string.Join(Environment.NewLine, Blocks.Select(b => b.Summary)); public override string GetString(byte[] data, int offset, int length) => StringConverter.GetString7(data, offset, length); public override byte[] SetString(string value, int maxLength, int PadToSize = 0, ushort PadWith = 0) @@ -353,7 +251,7 @@ public int GetFusedSlotOffset(int slot) { if ((uint)slot >= FusedCount) return -1; - return Fused + (PKX.SIZE_6PARTY * slot); // 0x104*slot + return AllBlocks[08].Offset + (PKX.SIZE_6PARTY * slot); // 0x104*slot } public override int DaycareSeedSize => Daycare7.DaycareSeedSize; // 128 bits @@ -366,6 +264,6 @@ public int GetFusedSlotOffset(int slot) public override void SetDaycareHasEgg(int loc, bool hasEgg) => DaycareBlock.HasEgg = hasEgg; protected override bool[] MysteryGiftReceivedFlags { get => MysteryBlock.MysteryGiftReceivedFlags; set => MysteryBlock.MysteryGiftReceivedFlags = value; } - protected override MysteryGift[] MysteryGiftCards { get => MysteryBlock.MysteryGiftCards; set => MysteryBlock.MysteryGiftCards = value; } + protected override DataMysteryGift[] MysteryGiftCards { get => MysteryBlock.MysteryGiftCards; set => MysteryBlock.MysteryGiftCards = value; } } } diff --git a/PKHeX.Core/Saves/SAV7SM.cs b/PKHeX.Core/Saves/SAV7SM.cs index 91e630518..fd6e49820 100644 --- a/PKHeX.Core/Saves/SAV7SM.cs +++ b/PKHeX.Core/Saves/SAV7SM.cs @@ -1,79 +1,73 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { - public sealed class SAV7SM : SAV7 + public sealed class SAV7SM : SAV7, ISaveBlock7SM { - public SAV7SM(byte[] data) : base(data, BlocksSM, boSM) => Initialize(); - public SAV7SM() : base(SaveUtil.SIZE_G7SM, BlocksSM, boSM) => Initialize(); - public override SaveFile Clone() => new SAV7SM((byte[])Data.Clone()); + public SAV7SM(byte[] data) : base(data, SaveBlockAccessor7SM.boSM) + { + Blocks = new SaveBlockAccessor7SM(this); + Initialize(); + ClearMemeCrypto(); + } + + public SAV7SM() : base(SaveUtil.SIZE_G7SM, SaveBlockAccessor7SM.boSM) + { + Blocks = new SaveBlockAccessor7SM(this); + Initialize(); + ClearBoxes(); + } private void Initialize() { - Personal = PersonalTable.SM; - HeldItems = Legal.HeldItems_SM; - - Items = new MyItem7SM(this, Bag); - Zukan = new Zukan7(this, PokeDex, PokeDexLanguageFlags); - Records = new Record6(this, Record, Core.Records.MaxType_SM); + EventConst = Blocks.BlockInfo[05].Offset; + EventFlag = EventConst + (EventConstMax * 2); // After Event Const (u16)*n + HoF = EventFlag + (EventFlagMax / 8); // After Event Flags (1b)*(1u8/8b)*n + TeamSlots = Blocks.BoxLayout.TeamSlots; } + public override PersonalTable Personal => PersonalTable.SM; + public override IReadOnlyList HeldItems => Legal.HeldItems_SM; + public override SaveFile Clone() => new SAV7SM((byte[])Data.Clone()); + + #region Blocks + public SaveBlockAccessor7SM Blocks { get; } + public override IReadOnlyList AllBlocks => Blocks.BlockInfo; + public override MyItem Items => Blocks.Items; + public override MysteryBlock7 MysteryBlock => Blocks.MysteryBlock; + public override PokeFinder7 PokeFinder => Blocks.PokeFinder; + public override JoinFesta7 Festa => Blocks.Festa; + public override Daycare7 DaycareBlock => Blocks.DaycareBlock; + public override Record6 Records => Blocks.Records; + public override PlayTime6 Played => Blocks.Played; + public override MyStatus7 MyStatus => Blocks.MyStatus; + public override FieldMoveModelSave7 OverworldBlock => Blocks.OverworldBlock; + public override Situation7 Situation => Blocks.Situation; + public override ConfigSave7 Config => Blocks.Config; + public override GameTime7 GameTime => Blocks.GameTime; + public override Misc7 MiscBlock => Blocks.MiscBlock; + public override Zukan7 Zukan => Blocks.Zukan; + public override BoxLayout7 BoxLayout => Blocks.BoxLayout; + public override BattleTree7 BattleTreeBlock => Blocks.BattleTreeBlock; + public override ResortSave7 ResortSave => Blocks.ResortSave; + public override FieldMenu7 FieldMenu => Blocks.FieldMenu; + public override FashionBlock7 FashionBlock => Blocks.FashionBlock; + #endregion + protected override int EventFlagMax => 3968; public override int MaxMoveID => Legal.MaxMoveID_7; public override int MaxSpeciesID => Legal.MaxSpeciesID_7; public override int MaxItemID => Legal.MaxItemID_7; public override int MaxAbilityID => Legal.MaxAbilityID_7; - private const int boSM = SaveUtil.SIZE_G7SM - 0x200; - - public static readonly BlockInfo[] BlocksSM = - { - new BlockInfo7 (boSM, 00, 0x00000, 0x00DE0), - new BlockInfo7 (boSM, 01, 0x00E00, 0x0007C), - new BlockInfo7 (boSM, 02, 0x01000, 0x00014), - new BlockInfo7 (boSM, 03, 0x01200, 0x000C0), - new BlockInfo7 (boSM, 04, 0x01400, 0x0061C), - new BlockInfo7 (boSM, 05, 0x01C00, 0x00E00), - new BlockInfo7 (boSM, 06, 0x02A00, 0x00F78), - new BlockInfo7 (boSM, 07, 0x03A00, 0x00228), - new BlockInfo7 (boSM, 08, 0x03E00, 0x00104), - new BlockInfo7 (boSM, 09, 0x04000, 0x00200), - new BlockInfo7 (boSM, 10, 0x04200, 0x00020), - new BlockInfo7 (boSM, 11, 0x04400, 0x00004), - new BlockInfo7 (boSM, 12, 0x04600, 0x00058), - new BlockInfo7 (boSM, 13, 0x04800, 0x005E6), - new BlockInfo7 (boSM, 14, 0x04E00, 0x36600), - new BlockInfo7 (boSM, 15, 0x3B400, 0x0572C), - new BlockInfo7 (boSM, 16, 0x40C00, 0x00008), - new BlockInfo7 (boSM, 17, 0x40E00, 0x01080), - new BlockInfo7 (boSM, 18, 0x42000, 0x01A08), - new BlockInfo7 (boSM, 19, 0x43C00, 0x06408), - new BlockInfo7 (boSM, 20, 0x4A200, 0x06408), - new BlockInfo7 (boSM, 21, 0x50800, 0x03998), - new BlockInfo7 (boSM, 22, 0x54200, 0x00100), - new BlockInfo7 (boSM, 23, 0x54400, 0x00100), - new BlockInfo7 (boSM, 24, 0x54600, 0x10528), - new BlockInfo7 (boSM, 25, 0x64C00, 0x00204), - new BlockInfo7 (boSM, 26, 0x65000, 0x00B60), - new BlockInfo7 (boSM, 27, 0x65C00, 0x03F50), - new BlockInfo7 (boSM, 28, 0x69C00, 0x00358), - new BlockInfo7 (boSM, 29, 0x6A000, 0x00728), - new BlockInfo7 (boSM, 30, 0x6A800, 0x00200), - new BlockInfo7 (boSM, 31, 0x6AA00, 0x00718), - new BlockInfo7 (boSM, 32, 0x6B200, 0x001FC), - new BlockInfo7 (boSM, 33, 0x6B400, 0x00200), - new BlockInfo7 (boSM, 34, 0x6B600, 0x00120), - new BlockInfo7 (boSM, 35, 0x6B800, 0x001C8), - new BlockInfo7 (boSM, 36, 0x6BA00, 0x00200), - }; - private const ulong MagearnaConst = 0xCBE05F18356504AC; public void UpdateMagearnaConstant() { var flag = GetEventFlag(3100); ulong value = flag ? MagearnaConst : 0ul; - SetData(BitConverter.GetBytes(value), QRSaveData + 0x168); + SetData(BitConverter.GetBytes(value), Blocks.BlockInfo[35].Offset + 0x168); } } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/SAV7USUM.cs b/PKHeX.Core/Saves/SAV7USUM.cs index 28c48dbe9..455e12c63 100644 --- a/PKHeX.Core/Saves/SAV7USUM.cs +++ b/PKHeX.Core/Saves/SAV7USUM.cs @@ -1,29 +1,32 @@ -namespace PKHeX.Core +using System.Collections.Generic; + +namespace PKHeX.Core { - public sealed class SAV7USUM : SAV7 + public sealed class SAV7USUM : SAV7, ISaveBlock7USUM { - public SAV7USUM(byte[] data) : base(data, BlocksUSUM, boUU) + public SAV7USUM(byte[] data) : base(data, boUU) { + Blocks = new SaveBlockAccessor7USUM(this); Initialize(); } - public SAV7USUM() : base(SaveUtil.SIZE_G7USUM, BlocksUSUM, boUU) + public SAV7USUM() : base(SaveUtil.SIZE_G7USUM, boUU) { + Blocks = new SaveBlockAccessor7USUM(this); Initialize(); } - public override SaveFile Clone() => new SAV7USUM((byte[])Data.Clone()); - private void Initialize() { - Personal = PersonalTable.USUM; - HeldItems = Legal.HeldItems_USUM; - - Items = new MyItem7USUM(this, Bag); - Zukan = new Zukan7(this, PokeDex, PokeDexLanguageFlags); - Records = new Record6(this, Record, Core.Records.MaxType_USUM); + EventConst = Blocks.BlockInfo[05].Offset; + EventFlag = EventConst + (EventConstMax * 2); // After Event Const (u16)*n + HoF = EventFlag + (EventFlagMax / 8); // After Event Flags (1b)*(1u8/8b)*n + TeamSlots = Blocks.BoxLayout.TeamSlots; } + public override PersonalTable Personal => PersonalTable.USUM; + public override IReadOnlyList HeldItems => Legal.HeldItems_USUM; + public override SaveFile Clone() => new SAV7USUM((byte[])Data.Clone()); protected override int EventFlagMax => 4928; public override int MaxMoveID => Legal.MaxMoveID_7_USUM; public override int MaxSpeciesID => Legal.MaxSpeciesID_7_USUM; @@ -32,47 +35,28 @@ private void Initialize() private const int boUU = SaveUtil.SIZE_G7USUM - 0x200; - public static readonly BlockInfo[] BlocksUSUM = - { - new BlockInfo7(boUU, 00, 0x00000, 0x00E28), - new BlockInfo7(boUU, 01, 0x01000, 0x0007C), - new BlockInfo7(boUU, 02, 0x01200, 0x00014), - new BlockInfo7(boUU, 03, 0x01400, 0x000C0), - new BlockInfo7(boUU, 04, 0x01600, 0x0061C), - new BlockInfo7(boUU, 05, 0x01E00, 0x00E00), - new BlockInfo7(boUU, 06, 0x02C00, 0x00F78), - new BlockInfo7(boUU, 07, 0x03C00, 0x00228), - new BlockInfo7(boUU, 08, 0x04000, 0x0030C), - new BlockInfo7(boUU, 09, 0x04400, 0x001FC), - new BlockInfo7(boUU, 10, 0x04600, 0x0004C), - new BlockInfo7(boUU, 11, 0x04800, 0x00004), - new BlockInfo7(boUU, 12, 0x04A00, 0x00058), - new BlockInfo7(boUU, 13, 0x04C00, 0x005E6), - new BlockInfo7(boUU, 14, 0x05200, 0x36600), - new BlockInfo7(boUU, 15, 0x3B800, 0x0572C), - new BlockInfo7(boUU, 16, 0x41000, 0x00008), - new BlockInfo7(boUU, 17, 0x41200, 0x01218), - new BlockInfo7(boUU, 18, 0x42600, 0x01A08), - new BlockInfo7(boUU, 19, 0x44200, 0x06408), - new BlockInfo7(boUU, 20, 0x4A800, 0x06408), - new BlockInfo7(boUU, 21, 0x50E00, 0x03998), - new BlockInfo7(boUU, 22, 0x54800, 0x00100), - new BlockInfo7(boUU, 23, 0x54A00, 0x00100), - new BlockInfo7(boUU, 24, 0x54C00, 0x10528), - new BlockInfo7(boUU, 25, 0x65200, 0x00204), - new BlockInfo7(boUU, 26, 0x65600, 0x00B60), - new BlockInfo7(boUU, 27, 0x66200, 0x03F50), - new BlockInfo7(boUU, 28, 0x6A200, 0x00358), - new BlockInfo7(boUU, 29, 0x6A600, 0x00728), - new BlockInfo7(boUU, 30, 0x6AE00, 0x00200), - new BlockInfo7(boUU, 31, 0x6B000, 0x00718), - new BlockInfo7(boUU, 32, 0x6B800, 0x001FC), - new BlockInfo7(boUU, 33, 0x6BA00, 0x00200), - new BlockInfo7(boUU, 34, 0x6BC00, 0x00120), - new BlockInfo7(boUU, 35, 0x6BE00, 0x001C8), - new BlockInfo7(boUU, 36, 0x6C000, 0x00200), - new BlockInfo7(boUU, 37, 0x6C200, 0x0039C), - new BlockInfo7(boUU, 38, 0x6C600, 0x00400), - }; + #region Blocks + public SaveBlockAccessor7USUM Blocks { get; } + public override IReadOnlyList AllBlocks => Blocks.BlockInfo; + public override MyItem Items => Blocks.Items; + public override MysteryBlock7 MysteryBlock => Blocks.MysteryBlock; + public override PokeFinder7 PokeFinder => Blocks.PokeFinder; + public override JoinFesta7 Festa => Blocks.Festa; + public override Daycare7 DaycareBlock => Blocks.DaycareBlock; + public override Record6 Records => Blocks.Records; + public override PlayTime6 Played => Blocks.Played; + public override MyStatus7 MyStatus => Blocks.MyStatus; + public override FieldMoveModelSave7 OverworldBlock => Blocks.OverworldBlock; + public override Situation7 Situation => Blocks.Situation; + public override ConfigSave7 Config => Blocks.Config; + public override GameTime7 GameTime => Blocks.GameTime; + public override Misc7 MiscBlock => Blocks.MiscBlock; + public override Zukan7 Zukan => Blocks.Zukan; + public override BoxLayout7 BoxLayout => Blocks.BoxLayout; + public override BattleTree7 BattleTreeBlock => Blocks.BattleTreeBlock; + public override ResortSave7 ResortSave => Blocks.ResortSave; + public override FieldMenu7 FieldMenu => Blocks.FieldMenu; + public override FashionBlock7 FashionBlock => Blocks.FashionBlock; + #endregion } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/SAV7b.cs b/PKHeX.Core/Saves/SAV7b.cs index fc2bb1f64..7ce4b7d1b 100644 --- a/PKHeX.Core/Saves/SAV7b.cs +++ b/PKHeX.Core/Saves/SAV7b.cs @@ -9,7 +9,7 @@ namespace PKHeX.Core /// public sealed class SAV7b : SAV_BEEF { - protected override string BAKText => $"{OT} ({Version}) - {Played.LastSavedTime}"; + protected override string BAKText => $"{OT} ({Version}) - {Blocks.Played.LastSavedTime}"; public override string Filter => "savedata|*.bin"; public override string Extension => ".bin"; public override string[] PKMExtensions => PKM.Extensions.Where(f => f[1] == 'b' && f[f.Length - 1] == '7').ToArray(); @@ -19,54 +19,40 @@ public sealed class SAV7b : SAV_BEEF public override int SIZE_STORED => SIZE_PARTY; protected override int SIZE_PARTY => 260; + public override PersonalTable Personal => PersonalTable.GG; + public override IReadOnlyList HeldItems => Legal.HeldItems_GG; + public override SaveFile Clone() => new SAV7b((byte[])Data.Clone()); - public SAV7b() : base(SaveUtil.SIZE_G7GG, BlockInfoGG, 0xB8800) + public SaveBlockAccessor7b Blocks { get; } + public override IReadOnlyList AllBlocks => Blocks.BlockInfo; + + public SAV7b() : base(SaveUtil.SIZE_G7GG, 0xB8800) { + Blocks = new SaveBlockAccessor7b(this); Initialize(); ClearBoxes(); } - public SAV7b(byte[] data) : base(data, BlockInfoGG, 0xB8800) + public SAV7b(byte[] data) : base(data, 0xB8800) { + Blocks = new SaveBlockAccessor7b(this); Initialize(); } private void Initialize() { - Personal = PersonalTable.GG; + Box = Blocks.GetBlockOffset(BelugaBlockIndex.PokeListPokemon); + Party = Blocks.GetBlockOffset(BelugaBlockIndex.PokeListPokemon); + EventFlag = Blocks.GetBlockOffset(BelugaBlockIndex.EventWork); + PokeDex = Blocks.GetBlockOffset(BelugaBlockIndex.Zukan); - Box = GetBlockOffset(BelugaBlockIndex.PokeListPokemon); - Party = GetBlockOffset(BelugaBlockIndex.PokeListPokemon); - EventFlag = GetBlockOffset(BelugaBlockIndex.EventWork); - PokeDex = GetBlockOffset(BelugaBlockIndex.Zukan); - Zukan = new Zukan7b(this, PokeDex, 0x550); - Config = new ConfigSave7b(this); - Items = new MyItem7b(this); - Storage = new PokeListHeader(this); - Status = new MyStatus7b(this); - Played = new PlayTime7b(this); - Misc = new Misc7b(this); - EventWork = new EventWork7b(this); - GiftRecords = new WB7Records(this); - - WondercardData = GiftRecords.Offset; - - HeldItems = Legal.HeldItems_GG; + WondercardData = Blocks.GiftRecords.Offset; } // Save Block accessors - public MyItem Items { get; private set; } - public Misc7b Misc { get; private set; } - public Zukan7b Zukan { get; private set; } - public MyStatus7b Status { get; private set; } - public PlayTime7b Played { get; private set; } - public ConfigSave7b Config { get; private set; } - public EventWork7b EventWork { get; private set; } - public PokeListHeader Storage { get; private set; } - public WB7Records GiftRecords { get; private set; } - public override InventoryPouch[] Inventory { get => Items.Inventory; set => Items.Inventory = value; } + public override InventoryPouch[] Inventory { get => Blocks.Items.Inventory; set => Blocks.Items.Inventory = value; } // Feature Overrides public override int Generation => 7; @@ -93,37 +79,7 @@ private void Initialize() public override int BoxSlotCount => 25; public override int BoxCount => 40; // 1000/25 - public BlockInfo GetBlock(BelugaBlockIndex index) => Blocks[(int)index]; - public int GetBlockOffset(BelugaBlockIndex index) => GetBlock(index).Offset; - - private const int boGG = 0xB8800 - 0x200; // nowhere near 1MB (savedata.bin size) - - private static readonly BlockInfo[] BlockInfoGG = - { - new BlockInfo7b(boGG, 00, 0x00000, 0x00D90), - new BlockInfo7b(boGG, 01, 0x00E00, 0x00200), - new BlockInfo7b(boGG, 02, 0x01000, 0x00168), - new BlockInfo7b(boGG, 03, 0x01200, 0x01800), - new BlockInfo7b(boGG, 04, 0x02A00, 0x020E8), - new BlockInfo7b(boGG, 05, 0x04C00, 0x00930), - new BlockInfo7b(boGG, 06, 0x05600, 0x00004), - new BlockInfo7b(boGG, 07, 0x05800, 0x00130), - new BlockInfo7b(boGG, 08, 0x05A00, 0x00012), - new BlockInfo7b(boGG, 09, 0x05C00, 0x3F7A0), - new BlockInfo7b(boGG, 10, 0x45400, 0x00008), - new BlockInfo7b(boGG, 11, 0x45600, 0x00E90), - new BlockInfo7b(boGG, 12, 0x46600, 0x010A4), - new BlockInfo7b(boGG, 13, 0x47800, 0x000F0), - new BlockInfo7b(boGG, 14, 0x47A00, 0x06010), - new BlockInfo7b(boGG, 15, 0x4DC00, 0x00200), - new BlockInfo7b(boGG, 16, 0x4DE00, 0x00098), - new BlockInfo7b(boGG, 17, 0x4E000, 0x00068), - new BlockInfo7b(boGG, 18, 0x4E200, 0x69780), - new BlockInfo7b(boGG, 19, 0xB7A00, 0x000B0), - new BlockInfo7b(boGG, 20, 0xB7C00, 0x00940), - }; - - public bool FixPreWrite() => Storage.CompressStorage(); + public bool FixPreWrite() => Blocks.Storage.CompressStorage(); protected override void SetPKM(PKM pkm) { @@ -143,25 +99,25 @@ protected override void SetPKM(PKM pkm) pk.RefreshChecksum(); } - protected override void SetDex(PKM pkm) => Zukan.SetDex(pkm); - public override bool GetCaught(int species) => Zukan.GetCaught(species); - public override bool GetSeen(int species) => Zukan.GetSeen(species); + protected override void SetDex(PKM pkm) => Blocks.Zukan.SetDex(pkm); + public override bool GetCaught(int species) => Blocks.Zukan.GetCaught(species); + public override bool GetSeen(int species) => Blocks.Zukan.GetSeen(species); protected override PKM GetPKM(byte[] data) => new PB7(data); protected override byte[] DecryptPKM(byte[] data) => PKX.DecryptArray6(data); public override int GetBoxOffset(int box) => Box + (box * BoxSlotCount * SIZE_STORED); - protected override IList[] SlotPointers => new[] { Storage.PokeListInfo }; + protected override IList[] SlotPointers => new[] { Blocks.Storage.PokeListInfo }; - public override int GetPartyOffset(int slot) => Storage.GetPartyOffset(slot); - public override int PartyCount { get => Storage.PartyCount; protected set => Storage.PartyCount = value; } + public override int GetPartyOffset(int slot) => Blocks.Storage.GetPartyOffset(slot); + public override int PartyCount { get => Blocks.Storage.PartyCount; protected set => Blocks.Storage.PartyCount = value; } protected override void SetPartyValues(PKM pkm, bool isParty) => base.SetPartyValues(pkm, true); public override StorageSlotFlag GetSlotFlags(int index) { var val = StorageSlotFlag.None; - if (Storage.PokeListInfo[6] == index) + if (Blocks.Storage.PokeListInfo[6] == index) val |= StorageSlotFlag.Starter; - int position = Array.IndexOf(Storage.PokeListInfo, index); + int position = Array.IndexOf(Blocks.Storage.PokeListInfo, index); if ((uint) position < 6) val |= (StorageSlotFlag)((int)StorageSlotFlag.Party1 << position); return val; @@ -193,24 +149,24 @@ public override GameVersion Version } // Player Information - public override int TID { get => Status.TID; set => Status.TID = value; } - public override int SID { get => Status.SID; set => Status.SID = value; } - public override int Game { get => Status.Game; set => Status.Game = value; } - public override int Gender { get => Status.Gender; set => Status.Gender = value; } - public override int Language { get => Status.Language; set => Config.Language = Status.Language = value; } // stored in multiple places - public override string OT { get => Status.OT; set => Status.OT = value; } - public override uint Money { get => Misc.Money; set => Misc.Money = value; } + public override int TID { get => Blocks.Status.TID; set => Blocks.Status.TID = value; } + public override int SID { get => Blocks.Status.SID; set => Blocks.Status.SID = value; } + public override int Game { get => Blocks.Status.Game; set => Blocks.Status.Game = value; } + public override int Gender { get => Blocks.Status.Gender; set => Blocks.Status.Gender = value; } + public override int Language { get => Blocks.Status.Language; set => Blocks.Config.Language = Blocks.Status.Language = value; } // stored in multiple places + public override string OT { get => Blocks.Status.OT; set => Blocks.Status.OT = value; } + public override uint Money { get => Blocks.Misc.Money; set => Blocks.Misc.Money = value; } - public override int PlayedHours { get => Played.PlayedHours; set => Played.PlayedHours = value; } - public override int PlayedMinutes { get => Played.PlayedMinutes; set => Played.PlayedMinutes = value; } - public override int PlayedSeconds { get => Played.PlayedSeconds; set => Played.PlayedSeconds = value; } + public override int PlayedHours { get => Blocks.Played.PlayedHours; set => Blocks.Played.PlayedHours = value; } + public override int PlayedMinutes { get => Blocks.Played.PlayedMinutes; set => Blocks.Played.PlayedMinutes = value; } + public override int PlayedSeconds { get => Blocks.Played.PlayedSeconds; set => Blocks.Played.PlayedSeconds = value; } /// /// Gets the status of a desired Event Flag /// /// Event Flag to check /// Flag is Set (true) or not Set (false) - public override bool GetEventFlag(int flagNumber) => EventWork.GetFlag(flagNumber); + public override bool GetEventFlag(int flagNumber) => Blocks.EventWork.GetFlag(flagNumber); /// /// Sets the status of a desired Event Flag @@ -218,12 +174,12 @@ public override GameVersion Version /// Event Flag to check /// Event Flag status to set /// Flag is Set (true) or not Set (false) - public override void SetEventFlag(int flagNumber, bool value) => EventWork.SetFlag(flagNumber, value); + public override void SetEventFlag(int flagNumber, bool value) => Blocks.EventWork.SetFlag(flagNumber, value); - protected override bool[] MysteryGiftReceivedFlags { get => GiftRecords.Flags; set => GiftRecords.Flags = value; } - protected override MysteryGift[] MysteryGiftCards { get => GiftRecords.Records; set => GiftRecords.Records = (WR7[])value; } + protected override bool[] MysteryGiftReceivedFlags { get => Blocks.GiftRecords.Flags; set => Blocks.GiftRecords.Flags = value; } + protected override DataMysteryGift[] MysteryGiftCards { get => Blocks.GiftRecords.Records; set => Blocks.GiftRecords.Records = (WR7[])value; } public override int GameSyncIDSize => MyStatus7b.GameSyncIDSize; // 64 bits - public override string GameSyncID { get => Status.GameSyncID; set => Status.GameSyncID = value; } + public override string GameSyncID { get => Blocks.Status.GameSyncID; set => Blocks.Status.GameSyncID = value; } } } diff --git a/PKHeX.Core/Saves/SAV8.cs b/PKHeX.Core/Saves/SAV8.cs index d0798beaa..1528586ea 100644 --- a/PKHeX.Core/Saves/SAV8.cs +++ b/PKHeX.Core/Saves/SAV8.cs @@ -6,7 +6,7 @@ namespace PKHeX.Core /// /// Generation 8 object. /// - public abstract class SAV8 : SAV_BEEF, ITrainerStatRecord + public abstract class SAV8 : SAV_BEEF, ITrainerStatRecord, ISaveBlock8Main { // Save Data Attributes protected override string BAKText => $"{OT} ({Version}) - {Played.LastSavedTime}"; @@ -19,39 +19,15 @@ public abstract class SAV8 : SAV_BEEF, ITrainerStatRecord return gen == 8; // future: change to <= when HOME released }).ToArray(); - protected SAV8(byte[] data, BlockInfo[] blocks, int biOffset) : base(data, blocks, biOffset) + protected SAV8(byte[] data, int biOffset) : base(data, biOffset) { - Initialize(); } - protected SAV8(int size, BlockInfo[] blocks, int biOffset) : base(size, blocks, biOffset) + protected SAV8(int size, int biOffset) : base(size, biOffset) { - Initialize(); ClearBoxes(); } - private void Initialize() - { - BoxLayout = new BoxLayout8(this, GetBlockOffset(SAV8BlockIndex.BOX)); - - Box = GetBlockOffset(SAV8BlockIndex.BoxPokemon); - Party = GetBlockOffset(SAV8BlockIndex.PokePartySave); - EventFlag = GetBlockOffset(SAV8BlockIndex.EventWork); - PokeDex = GetBlockOffset(SAV8BlockIndex.ZukanData); - - const int langFlagStart = 0x550; // todo - Zukan = new Zukan8(this, PokeDex, langFlagStart); - Items = new MyItem8(this); - MyStatus = new MyStatus8(this, GetBlockOffset(SAV8BlockIndex.MyStatus)); - Played = new PlayTime8(this, GetBlockOffset(SAV8BlockIndex.PlayTime)); - MiscBlock = new Misc8(this, GetBlockOffset(SAV8BlockIndex.Misc)); - GameTime = new GameTime8(this, GetBlockOffset(SAV8BlockIndex.GameTime)); - OverworldBlock = new FieldMoveModelSave8(this, GetBlockOffset(SAV8BlockIndex.FieldMoveModelSave)); - Records = new Record8(this, GetBlockOffset(SAV8BlockIndex.Records), Core.Records.MaxType_SWSH); - Situation = new Situation8(this, GetBlockOffset(SAV8BlockIndex.Situation)); - EventWork = new EventWork8(this); - } - // Configuration public override int SIZE_STORED => PKX.SIZE_8STORED; protected override int SIZE_PARTY => PKX.SIZE_8PARTY; @@ -69,34 +45,28 @@ private void Initialize() protected override PKM GetPKM(byte[] data) => new PK8(data); protected override byte[] DecryptPKM(byte[] data) => PKX.DecryptArray8(data); - // Feature Overrides - protected override void SetChecksums() - { - Blocks.SetChecksums(Data); - } + #region Blocks + public abstract MyItem Items { get; } + public abstract Record8 Records { get; } + public abstract PlayTime8 Played { get; } + public abstract MyStatus8 MyStatus { get; } + public abstract ConfigSave8 Config { get; } + public abstract GameTime8 GameTime { get; } + public abstract Misc8 MiscBlock { get; } + public abstract Zukan8 Zukan { get; } + public abstract EventWork8 EventWork { get; } + public abstract BoxLayout8 BoxLayout { get; } + public abstract Situation8 Situation { get; } + public abstract FieldMoveModelSave8 OverworldBlock { get; } + #endregion + // Feature Overrides protected override byte[] GetFinalData() { SetChecksums(); return Data; } - protected MyItem Items { private get; set; } - protected Record8 Records { get; private set; } - public PlayTime8 Played { get; private set; } - public MyStatus8 MyStatus { get; protected set; } - public ConfigSave8 Config { get; protected set; } - public GameTime8 GameTime { get; private set; } - public Misc8 MiscBlock { get; private set; } - public Zukan8 Zukan { get; protected set; } - public EventWork8 EventWork { get; protected set; } - private BoxLayout8 BoxLayout { get; set; } - public Situation8 Situation { get; private set; } - public FieldMoveModelSave8 OverworldBlock { get; private set; } - - public BlockInfo GetBlock(SAV8BlockIndex index) => Blocks[(int)index]; - public int GetBlockOffset(SAV8BlockIndex index) => GetBlock(index).Offset; - public override GameVersion Version { get @@ -108,7 +78,6 @@ public override GameVersion Version } } - public override string MiscSaveInfo() => string.Join(Environment.NewLine, Blocks.Select(b => b.Summary)); public override string GetString(byte[] data, int offset, int length) => StringConverter.GetString7(data, offset, length); public override byte[] SetString(string value, int maxLength, int PadToSize = 0, ushort PadWith = 0) diff --git a/PKHeX.Core/Saves/SAV8BlockIndex.cs b/PKHeX.Core/Saves/SAV8BlockIndex.cs index 7f13aade3..3f458a466 100644 --- a/PKHeX.Core/Saves/SAV8BlockIndex.cs +++ b/PKHeX.Core/Saves/SAV8BlockIndex.cs @@ -21,5 +21,6 @@ public enum SAV8BlockIndex PlayTime, FieldMoveModelSave, Records, + Pokedex } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/SAV8SWSH.cs b/PKHeX.Core/Saves/SAV8SWSH.cs index e210a46d3..c942c231a 100644 --- a/PKHeX.Core/Saves/SAV8SWSH.cs +++ b/PKHeX.Core/Saves/SAV8SWSH.cs @@ -1,13 +1,44 @@ -namespace PKHeX.Core +using System.Collections.Generic; + +namespace PKHeX.Core { /// /// Generation 8 object for games. /// - public sealed class SAV8SWSH : SAV8 + public sealed class SAV8SWSH : SAV8, ISaveBlock8SWSH { - public SAV8SWSH(byte[] data) : base(data, BlocksSWSH, boSWSH) => Initialize(); - public SAV8SWSH() : base(SaveUtil.SIZE_G8SWSH, BlocksSWSH, boSWSH) => Initialize(); + public SAV8SWSH(byte[] data) : base(data, SaveBlockAccessorSWSH.boGG) + { + Blocks = new SaveBlockAccessorSWSH(this); + Initialize(); + } + public SAV8SWSH() : base(SaveUtil.SIZE_G8SWSH, SaveBlockAccessorSWSH.boGG) + { + Blocks = new SaveBlockAccessorSWSH(this); + Initialize(); + } + + public override PersonalTable Personal => PersonalTable.SWSH; + public override IReadOnlyList HeldItems => Legal.HeldItems_SWSH; + + #region Blocks + public SaveBlockAccessorSWSH Blocks { get; } + public override IReadOnlyList AllBlocks => Blocks.BlockInfo; + public override MyItem Items => Blocks.Items; + public override Record8 Records => Blocks.Records; + public override PlayTime8 Played => Blocks.Played; + public override MyStatus8 MyStatus => Blocks.MyStatus; + public override ConfigSave8 Config => Blocks.Config; + public override GameTime8 GameTime => Blocks.GameTime; + public override Misc8 MiscBlock => Blocks.MiscBlock; + public override Zukan8 Zukan => Blocks.Zukan; + public override EventWork8 EventWork => Blocks.EventWork; + public override BoxLayout8 BoxLayout => Blocks.BoxLayout; + public override Situation8 Situation => Blocks.Situation; + public override FieldMoveModelSave8 OverworldBlock => Blocks.OverworldBlock; + + #endregion public override SaveFile Clone() => new SAV8SWSH((byte[])Data.Clone()); public override int MaxMoveID => Legal.MaxMoveID_8; public override int MaxSpeciesID => Legal.MaxSpeciesID_8; @@ -16,38 +47,8 @@ public sealed class SAV8SWSH : SAV8 public override int MaxGameID => Legal.MaxGameID_8; public override int MaxAbilityID => Legal.MaxAbilityID_8; - private const int boSWSH = -1; - - private static readonly BlockInfo[] BlocksSWSH = - { - new BlockInfo7b(boSWSH, 00, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 01, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 02, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 03, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 04, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 04, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 05, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 06, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 07, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 08, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 09, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 10, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 11, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 12, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 13, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 14, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 14, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 15, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 16, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 17, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 18, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 19, 0x00000, 0x00000), - new BlockInfo7b(boSWSH, 20, 0x00000, 0x00000), - }; - private void Initialize() { - Personal = PersonalTable.SWSH; } } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/SAV_BEEF.cs b/PKHeX.Core/Saves/SAV_BEEF.cs index 18a1058f0..062013dc2 100644 --- a/PKHeX.Core/Saves/SAV_BEEF.cs +++ b/PKHeX.Core/Saves/SAV_BEEF.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; namespace PKHeX.Core @@ -9,25 +10,23 @@ namespace PKHeX.Core /// Shared logic is used by Gen6 and Gen7 save files. public abstract class SAV_BEEF : SaveFile, ISecureValueStorage { - protected SAV_BEEF(byte[] data, BlockInfo[] blocks, int biOffset) : base(data) + protected SAV_BEEF(byte[] data, int biOffset) : base(data) { - Blocks = blocks; BlockInfoOffset = biOffset; } - protected SAV_BEEF(int size, BlockInfo[] blocks, int biOffset) : base(size) + protected SAV_BEEF(int size, int biOffset) : base(size) { - Blocks = blocks; BlockInfoOffset = biOffset; } - protected override void SetChecksums() => Blocks.SetChecksums(Data); - public override bool ChecksumsValid => Blocks.GetChecksumsValid(Data); - public override string ChecksumInfo => Blocks.GetChecksumInfo(Data); - public override string MiscSaveInfo() => string.Join(Environment.NewLine, Blocks.Select(b => b.Summary)); + public abstract IReadOnlyList AllBlocks { get; } + protected override void SetChecksums() => AllBlocks.SetChecksums(Data); + public override bool ChecksumsValid => AllBlocks.GetChecksumsValid(Data); + public override string ChecksumInfo => AllBlocks.GetChecksumInfo(Data); + public override string MiscSaveInfo() => string.Join(Environment.NewLine, AllBlocks.Select(b => b.Summary)); protected readonly int BlockInfoOffset; - protected readonly BlockInfo[] Blocks; public ulong TimeStampCurrent { diff --git a/PKHeX.Core/Saves/SaveFile.cs b/PKHeX.Core/Saves/SaveFile.cs index 83414ccbb..51ca377da 100644 --- a/PKHeX.Core/Saves/SaveFile.cs +++ b/PKHeX.Core/Saves/SaveFile.cs @@ -14,22 +14,31 @@ public abstract class SaveFile : ITrainerInfo, IGameValueLimit public byte[] Data; public bool Edited; public readonly bool Exportable; - public byte[] BAK { get; protected set; } + public readonly byte[] BAK; - protected SaveFile(byte[] data) + protected SaveFile(byte[] data, byte[] bak) { Data = data; - BAK = (byte[])Data.Clone(); + BAK = bak; Exportable = true; } - protected SaveFile(int size) : this() + protected SaveFile(byte[] data) : this(data, (byte[])data.Clone()) { } + + protected SaveFile() + { + Data = BAK = Array.Empty(); + Exportable = false; + } + + protected SaveFile(int size) { Data = new byte[size]; BAK = Data; + Exportable = false; } - public string FileName, FilePath, FileFolder; + public string? FileName, FilePath, FileFolder; public string BAKName => $"{FileName} [{BAKText}].bak"; protected abstract string BAKText { get; } public abstract SaveFile Clone(); @@ -45,11 +54,6 @@ protected SaveFile(int size) : this() return 3 <= gen && gen <= Generation; }).ToArray(); - protected SaveFile() - { - Exportable = false; - } - // General SAV Properties public byte[] Write(ExportFlags flags = ExportFlags.None) { @@ -96,7 +100,7 @@ public void SetData(byte[] dest, byte[] input, int offset) protected int Trainer1 { get; set; } = int.MinValue; #region Stored PKM Limits - public PersonalTable Personal { get; protected set; } + public abstract PersonalTable Personal { get; } public abstract int OTLength { get; } public abstract int NickLength { get; } public abstract int MaxMoveID { get; } @@ -236,7 +240,7 @@ public virtual void SetEventFlag(int flagNumber, bool value) public virtual void SetFlag(int offset, int bitIndex, bool value) => FlagUtil.SetFlag(Data, offset, bitIndex, value); #endregion - public virtual InventoryPouch[] Inventory { get; set; } + public virtual InventoryPouch[] Inventory { get; set; } = Array.Empty(); #region Mystery Gift protected virtual int GiftCountMax { get; } = int.MinValue; @@ -244,15 +248,11 @@ public virtual void SetEventFlag(int flagNumber, bool value) protected int WondercardData { get; set; } = int.MinValue; public bool HasWondercards => WondercardData > -1; protected virtual bool[] MysteryGiftReceivedFlags { get => Array.Empty(); set { } } - protected virtual MysteryGift[] MysteryGiftCards { get => Array.Empty(); set { } } + protected virtual DataMysteryGift[] MysteryGiftCards { get => Array.Empty(); set { } } public virtual MysteryGiftAlbum GiftAlbum { - get => new MysteryGiftAlbum - { - Flags = MysteryGiftReceivedFlags, - Gifts = MysteryGiftCards - }; + get => new MysteryGiftAlbum(MysteryGiftCards, MysteryGiftReceivedFlags); set { MysteryGiftReceivedFlags = value.Flags; @@ -350,7 +350,7 @@ public IList PartyData // Varied Methods protected abstract void SetChecksums(); public virtual int GameSyncIDSize { get; } = 8; - public virtual string GameSyncID { get => null; set { } } + public virtual string GameSyncID { get => string.Empty; set { } } #region Daycare public bool HasDaycare => Daycare > -1; @@ -360,7 +360,7 @@ public IList PartyData public virtual bool HasTwoDaycares => false; public virtual int GetDaycareSlotOffset(int loc, int slot) => -1; public virtual uint? GetDaycareEXP(int loc, int slot) => null; - public virtual string GetDaycareRNGSeed(int loc) => null; + public virtual string GetDaycareRNGSeed(int loc) => string.Empty; public virtual bool? IsDaycareHasEgg(int loc) => null; public virtual bool? IsDaycareOccupied(int loc, int slot) => null; @@ -449,7 +449,7 @@ public void DeletePartySlot(int slot) protected abstract int SIZE_PARTY { get; } public abstract int MaxEV { get; } public virtual int MaxIV => 31; - public ushort[] HeldItems { get; protected set; } + public abstract IReadOnlyList HeldItems { get; } public virtual bool IsPKMPresent(byte[] data, int offset) => PKX.IsPKMPresent(data, offset); public virtual PKM GetDecryptedPKM(byte[] data) => GetPKM(DecryptPKM(data)); public virtual PKM GetPartySlot(int offset) => GetDecryptedPKM(GetData(offset, SIZE_PARTY)); @@ -753,7 +753,7 @@ private bool IsBoxAbleToMove(int box) /// Sorting logic required to order a with respect to its peers; if not provided, will use a default sorting method. /// Reverse the sorting order /// Count of repositioned slots. - public int SortBoxes(int BoxStart = 0, int BoxEnd = -1, Func, IEnumerable> sortMethod = null, bool reverse = false) + public int SortBoxes(int BoxStart = 0, int BoxEnd = -1, Func, IEnumerable>? sortMethod = null, bool reverse = false) { var BD = BoxData; int start = BoxSlotCount * BoxStart; @@ -797,7 +797,7 @@ public int SortBoxes(int BoxStart = 0, int BoxEnd = -1, Func, I /// Ending box; if not provided, will iterate to the end. /// Criteria required to be satisfied for a to be deleted; if not provided, will clear if possible. /// Count of deleted slots. - public int ClearBoxes(int BoxStart = 0, int BoxEnd = -1, Func deleteCriteria = null) + public int ClearBoxes(int BoxStart = 0, int BoxEnd = -1, Func? deleteCriteria = null) { var storage = StorageData; @@ -838,12 +838,10 @@ public int ClearBoxes(int BoxStart = 0, int BoxEnd = -1, Func deleteC /// Count of modified slots. public int ModifyBoxes(Action action, int BoxStart = 0, int BoxEnd = -1) { - var storage = StorageData; - - if (action == null) - throw new ArgumentException(nameof(action)); if (BoxEnd < 0) BoxEnd = BoxCount - 1; + + var storage = StorageData; int modified = 0; for (int b = BoxStart; b <= BoxEnd; b++) { diff --git a/PKHeX.Core/Saves/Storage/Bank3.cs b/PKHeX.Core/Saves/Storage/Bank3.cs index b821c7ce2..78c68d51e 100644 --- a/PKHeX.Core/Saves/Storage/Bank3.cs +++ b/PKHeX.Core/Saves/Storage/Bank3.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace PKHeX.Core { /// @@ -5,13 +7,11 @@ namespace PKHeX.Core /// public sealed class Bank3 : BulkStorage { - public Bank3(byte[] data) : base(data, typeof(PK3), 0) - { - Personal = PersonalTable.RS; - Version = GameVersion.RS; - HeldItems = Legal.HeldItems_RS; - } + public Bank3(byte[] data) : base(data, typeof(PK3), 0) => Version = GameVersion.RS; + public override PersonalTable Personal => PersonalTable.RS; + public override IReadOnlyList HeldItems => Legal.HeldItems_RS; + public override SaveFile Clone() => new Bank3((byte[])Data.Clone()); public override string PlayTimeString => Checksums.CRC16(Data, 0, Data.Length).ToString("X4"); protected override string BAKText => PlayTimeString; public override string Extension => ".gst"; diff --git a/PKHeX.Core/Saves/Storage/Bank4.cs b/PKHeX.Core/Saves/Storage/Bank4.cs index 650237bf9..c17f8fc81 100644 --- a/PKHeX.Core/Saves/Storage/Bank4.cs +++ b/PKHeX.Core/Saves/Storage/Bank4.cs @@ -1,3 +1,5 @@ +using System.Collections.Generic; + namespace PKHeX.Core { /// @@ -5,13 +7,11 @@ namespace PKHeX.Core /// public sealed class Bank4 : BulkStorage { - public Bank4(byte[] data) : base(data, typeof(PK4), 0) - { - Personal = PersonalTable.HGSS; - Version = GameVersion.HGSS; - HeldItems = Legal.HeldItems_HGSS; - } + public Bank4(byte[] data) : base(data, typeof(PK4), 0) => Version = GameVersion.HGSS; + public override PersonalTable Personal => PersonalTable.HGSS; + public override IReadOnlyList HeldItems => Legal.HeldItems_HGSS; + public override SaveFile Clone() => new Bank4((byte[])Data.Clone()); public override string PlayTimeString => Checksums.CRC16(Data, 0, Data.Length).ToString("X4"); protected override string BAKText => PlayTimeString; public override string Extension => ".stk"; diff --git a/PKHeX.Core/Saves/Storage/Bank7.cs b/PKHeX.Core/Saves/Storage/Bank7.cs index f1ba45cb9..623315003 100644 --- a/PKHeX.Core/Saves/Storage/Bank7.cs +++ b/PKHeX.Core/Saves/Storage/Bank7.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { @@ -7,13 +8,11 @@ namespace PKHeX.Core /// public sealed class Bank7 : BulkStorage { - public Bank7(byte[] data, Type t, int start, int slotsPerBox = 30) : base(data, t, start, slotsPerBox) - { - Personal = PersonalTable.USUM; - Version = GameVersion.USUM; - HeldItems = Legal.HeldItems_USUM; - } + public Bank7(byte[] data, Type t, int start, int slotsPerBox = 30) : base(data, t, start, slotsPerBox) => Version = GameVersion.USUM; + public override PersonalTable Personal => PersonalTable.USUM; + public override IReadOnlyList HeldItems => Legal.HeldItems_SM; + public override SaveFile Clone() => new Bank7((byte[])Data.Clone(), PKMType, BoxStart, SlotsPerBox); public override string PlayTimeString => $"{Year:00}{Month:00}{Day:00}_{Hours:00}ː{Minutes:00}"; protected override string BAKText => PlayTimeString; private const int GroupNameSize = 0x20; diff --git a/PKHeX.Core/Saves/Storage/BulkStorage.cs b/PKHeX.Core/Saves/Storage/BulkStorage.cs index cc49a887a..a1b6e4dac 100644 --- a/PKHeX.Core/Saves/Storage/BulkStorage.cs +++ b/PKHeX.Core/Saves/Storage/BulkStorage.cs @@ -1,11 +1,12 @@ using System; +using System.Collections.Generic; namespace PKHeX.Core { /// /// Simple Storage Binary wrapper for a concatenated list of data. /// - public class BulkStorage : SaveFile + public abstract class BulkStorage : SaveFile { protected BulkStorage(byte[] data, Type t, int start, int slotsPerBox = 30) : base(data) { @@ -22,7 +23,6 @@ protected BulkStorage(byte[] data, Type t, int start, int slotsPerBox = 30) : ba protected readonly int SlotsPerBox; protected override string BAKText => $"{Checksums.CRC16(Data, Box, Data.Length - Box):X4}"; - public override SaveFile Clone() => new BulkStorage((byte[])Data.Clone(), PKMType, Box, SlotsPerBox); public override string Filter { get; } = "All Files|*.*"; public override string Extension { get; } = ".bin"; public override bool ChecksumsValid { get; } = true; @@ -32,7 +32,7 @@ protected BulkStorage(byte[] data, Type t, int start, int slotsPerBox = 30) : ba public override Type PKMType => blank.GetType(); public override PKM BlankPKM => blank.Clone(); - protected override PKM GetPKM(byte[] data) => PKMConverter.GetPKMfromBytes(data, prefer: Generation); + protected override PKM GetPKM(byte[] data) => PKMConverter.GetPKMfromBytes(data, prefer: Generation) ?? blank; protected override byte[] DecryptPKM(byte[] data) => GetPKM(data).Data; public override int SIZE_STORED => blank.SIZE_STORED; diff --git a/PKHeX.Core/Saves/Storage/SAV4Ranch.cs b/PKHeX.Core/Saves/Storage/SAV4Ranch.cs index 02b3c241f..e24a6a06d 100644 --- a/PKHeX.Core/Saves/Storage/SAV4Ranch.cs +++ b/PKHeX.Core/Saves/Storage/SAV4Ranch.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Security.Cryptography; using System.Text; @@ -15,6 +16,9 @@ public sealed class SAV4Ranch : BulkStorage public override int BoxCount { get; } public override int SlotCount { get; } + public override PersonalTable Personal => PersonalTable.Pt; + public override IReadOnlyList HeldItems => Legal.HeldItems_Pt; + public override SaveFile Clone() => new SAV4Ranch((byte[])Data.Clone()); public override string PlayTimeString => Checksums.CRC16(Data, 0, Data.Length).ToString("X4"); protected override string BAKText => $"{OT} {PlayTimeString}"; public override string Extension => ".bin"; @@ -27,9 +31,7 @@ public sealed class SAV4Ranch : BulkStorage public SAV4Ranch(byte[] data) : base(data, typeof(PK4), 0) { - Personal = PersonalTable.Pt; Version = Data.Length == SaveUtil.SIZE_G4RANCH_PLAT ? GameVersion.Pt : GameVersion.DP; - HeldItems = Legal.HeldItems_Pt; OT = GetString(0x770, 0x12); diff --git a/PKHeX.Core/Saves/Substructures/Battle Videos/BVRequestUtil.cs b/PKHeX.Core/Saves/Substructures/Battle Videos/BVRequestUtil.cs index 19d90f162..11aa80dd2 100644 --- a/PKHeX.Core/Saves/Substructures/Battle Videos/BVRequestUtil.cs +++ b/PKHeX.Core/Saves/Substructures/Battle Videos/BVRequestUtil.cs @@ -11,7 +11,7 @@ public static string GetSMBattleVideoURL(string code) Debug.Assert(code.Length == 16); var video_id = StrToU64(code, out bool valid); if (!valid) - return null; + return string.Empty; return $"https://ctr-bnda-live.s3.amazonaws.com/10.CTR_BNDA_datastore/ds/1/data/{video_id:D11}-00001"; // Sun datastore } diff --git a/PKHeX.Core/Saves/Substructures/Battle Videos/BattleVideo.cs b/PKHeX.Core/Saves/Substructures/Battle Videos/BattleVideo.cs index 7fe7bedf2..1d3b71754 100644 --- a/PKHeX.Core/Saves/Substructures/Battle Videos/BattleVideo.cs +++ b/PKHeX.Core/Saves/Substructures/Battle Videos/BattleVideo.cs @@ -5,7 +5,7 @@ public abstract class BattleVideo public abstract PKM[] BattlePKMs { get; } public abstract int Generation { get; } - public static BattleVideo GetVariantBattleVideo(byte[] data) + public static BattleVideo? GetVariantBattleVideo(byte[] data) { if (BV6.IsValid(data)) return new BV6(data); diff --git a/PKHeX.Core/Saves/Substructures/Gen12/G1OverworldSpawner.cs b/PKHeX.Core/Saves/Substructures/Gen12/G1OverworldSpawner.cs index 4ed5fce7c..71e3232fe 100644 --- a/PKHeX.Core/Saves/Substructures/Gen12/G1OverworldSpawner.cs +++ b/PKHeX.Core/Saves/Substructures/Gen12/G1OverworldSpawner.cs @@ -17,24 +17,24 @@ public G1OverworldSpawner(SAV1 sav) bool yellow = SAV.Yellow; // FlagPairs set for Red/Blue when appropriate. - FlagEevee = new FlagPair {SpawnFlag = 0x45}; - FlagAerodactyl = new FlagPair {EventFlag = 0x069, SpawnFlag = 0x34}; - FlagHitmonlee = new FlagPair {EventFlag = 0x356, SpawnFlag = 0x4A}; - FlagHitmonchan = new FlagPair {EventFlag = 0x357, SpawnFlag = 0x4B}; - FlagVoltorb_1 = new FlagPair {EventFlag = 0x461, SpawnFlag = 0x4D}; - FlagVoltorb_2 = new FlagPair {EventFlag = 0x462, SpawnFlag = 0x4E}; - FlagVoltorb_3 = new FlagPair { EventFlag = 0x463, SpawnFlag = 0x4F}; - FlagElectrode_1 = new FlagPair {EventFlag = 0x464, SpawnFlag = 0x50}; - FlagVoltorb_4 = new FlagPair {EventFlag = 0x465, SpawnFlag = 0x51}; - FlagVoltorb_5 = new FlagPair {EventFlag = 0x466, SpawnFlag = 0x52}; - FlagElectrode_2 = new FlagPair {EventFlag = 0x467, SpawnFlag = 0x53}; - FlagVoltorb_6 = new FlagPair {EventFlag = 0x468, SpawnFlag = 0x54}; - FlagZapdos = new FlagPair {EventFlag = 0x469, SpawnFlag = 0x55}; - FlagMoltres = new FlagPair {EventFlag = 0x53E, SpawnFlag = 0x5B}; - FlagKabuto = new FlagPair {EventFlag = 0x57E, SpawnFlag = 0x6D}; - FlagOmanyte = new FlagPair {EventFlag = 0x57F, SpawnFlag = 0x6E}; - FlagMewtwo = new FlagPair {EventFlag = 0x8C1, SpawnFlag = 0xD1}; - FlagArticuno = new FlagPair {EventFlag = 0x9DA, SpawnFlag = 0xE3}; + FlagEevee = new FlagPairG1 {SpawnFlag = 0x45}; + FlagAerodactyl = new FlagPairG1 {EventFlag = 0x069, SpawnFlag = 0x34}; + FlagHitmonlee = new FlagPairG1 {EventFlag = 0x356, SpawnFlag = 0x4A}; + FlagHitmonchan = new FlagPairG1 {EventFlag = 0x357, SpawnFlag = 0x4B}; + FlagVoltorb_1 = new FlagPairG1 {EventFlag = 0x461, SpawnFlag = 0x4D}; + FlagVoltorb_2 = new FlagPairG1 {EventFlag = 0x462, SpawnFlag = 0x4E}; + FlagVoltorb_3 = new FlagPairG1 { EventFlag = 0x463, SpawnFlag = 0x4F}; + FlagElectrode_1 = new FlagPairG1 {EventFlag = 0x464, SpawnFlag = 0x50}; + FlagVoltorb_4 = new FlagPairG1 {EventFlag = 0x465, SpawnFlag = 0x51}; + FlagVoltorb_5 = new FlagPairG1 {EventFlag = 0x466, SpawnFlag = 0x52}; + FlagElectrode_2 = new FlagPairG1 {EventFlag = 0x467, SpawnFlag = 0x53}; + FlagVoltorb_6 = new FlagPairG1 {EventFlag = 0x468, SpawnFlag = 0x54}; + FlagZapdos = new FlagPairG1 {EventFlag = 0x469, SpawnFlag = 0x55}; + FlagMoltres = new FlagPairG1 {EventFlag = 0x53E, SpawnFlag = 0x5B}; + FlagKabuto = new FlagPairG1 {EventFlag = 0x57E, SpawnFlag = 0x6D}; + FlagOmanyte = new FlagPairG1 {EventFlag = 0x57F, SpawnFlag = 0x6E}; + FlagMewtwo = new FlagPairG1 {EventFlag = 0x8C1, SpawnFlag = 0xD1}; + FlagArticuno = new FlagPairG1 {EventFlag = 0x9DA, SpawnFlag = 0xE3}; if (yellow) // slightly different { @@ -45,69 +45,33 @@ public G1OverworldSpawner(SAV1 sav) FlagKabuto.SpawnFlag += 2; FlagOmanyte.SpawnFlag += 2; - FlagBulbasaur = new FlagPair { EventFlag = 0x0A8, SpawnFlag = 0x34 }; - FlagSquirtle = new FlagPair { EventFlag = 0x147 }; // Given by Officer Jenny after badged - FlagCharmander = new FlagPair { EventFlag = 0x54F }; // Given by Damian, doesn't despawn + FlagBulbasaur = new FlagPairG1 { EventFlag = 0x0A8, SpawnFlag = 0x34 }; + FlagSquirtle = new FlagPairG1 { EventFlag = 0x147 }; // Given by Officer Jenny after badged + FlagCharmander = new FlagPairG1 { EventFlag = 0x54F }; // Given by Damian, doesn't despawn } } - private FlagPair FlagMewtwo { get; } - private FlagPair FlagArticuno { get; } - private FlagPair FlagZapdos { get; } - private FlagPair FlagMoltres { get; } - private FlagPair FlagVoltorb_1 { get; } - private FlagPair FlagVoltorb_2 { get; } - private FlagPair FlagVoltorb_3 { get; } - private FlagPair FlagVoltorb_4 { get; } - private FlagPair FlagVoltorb_5 { get; } - private FlagPair FlagVoltorb_6 { get; } - private FlagPair FlagElectrode_1 { get; } - private FlagPair FlagElectrode_2 { get; } - private FlagPair FlagHitmonchan { get; } - private FlagPair FlagHitmonlee { get; } - private FlagPair FlagEevee { get; } - private FlagPair FlagKabuto { get; } - private FlagPair FlagOmanyte { get; } - private FlagPair FlagAerodactyl { get; } - private FlagPair FlagBulbasaur { get; } - private FlagPair FlagSquirtle { get; } - private FlagPair FlagCharmander { get; } - - public sealed class FlagPair - { - public string Name { get; internal set; } - - internal int SpawnFlag { get; set; } - internal int EventFlag { get; set; } - internal bool[] Event { get; set; } - internal bool[] Spawn { get; set; } - - public void Invert() => SetState(!IsDespawned); - public void Reset() => SetState(false); - - public void SetState(bool despawned) - { - if (EventFlag != 0) - Event[EventFlag] = despawned; - if (SpawnFlag != 0) - Spawn[SpawnFlag] = despawned; - } - - public bool IsDespawned - { - get - { - bool result = false; - if (EventFlag != 0) - result |= Event[EventFlag]; - if (SpawnFlag != 0) - result |= Spawn[SpawnFlag]; - return result; - } - } - - internal FlagPair() { } - } + private FlagPairG1 FlagMewtwo { get; } + private FlagPairG1 FlagArticuno { get; } + private FlagPairG1 FlagZapdos { get; } + private FlagPairG1 FlagMoltres { get; } + private FlagPairG1 FlagVoltorb_1 { get; } + private FlagPairG1 FlagVoltorb_2 { get; } + private FlagPairG1 FlagVoltorb_3 { get; } + private FlagPairG1 FlagVoltorb_4 { get; } + private FlagPairG1 FlagVoltorb_5 { get; } + private FlagPairG1 FlagVoltorb_6 { get; } + private FlagPairG1 FlagElectrode_1 { get; } + private FlagPairG1 FlagElectrode_2 { get; } + private FlagPairG1 FlagHitmonchan { get; } + private FlagPairG1 FlagHitmonlee { get; } + private FlagPairG1 FlagEevee { get; } + private FlagPairG1 FlagKabuto { get; } + private FlagPairG1 FlagOmanyte { get; } + private FlagPairG1 FlagAerodactyl { get; } + private FlagPairG1? FlagBulbasaur { get; } + private FlagPairG1? FlagSquirtle { get; } + private FlagPairG1? FlagCharmander { get; } public void Save() { @@ -115,18 +79,65 @@ public void Save() SAV.EventSpawnFlags = SpawnFlags; } - public IEnumerable GetFlagPairs() + + public IEnumerable GetFlagPairs() { var pz = ReflectUtil.GetPropertiesStartWithPrefix(GetType(), "Flag"); foreach (var pair in pz) { - if (!(ReflectUtil.GetValue(this, pair) is FlagPair p)) + if (!(ReflectUtil.GetValue(this, pair) is FlagPairG1 p)) continue; - p.Name = pair; - p.Event = EventFlags; - p.Spawn = SpawnFlags; - yield return p; + yield return new FlagPairG1Detail(p, pair, EventFlags, SpawnFlags); + } + } + } + + public sealed class FlagPairG1 + { + internal int SpawnFlag { get; set; } + internal int EventFlag { get; set; } + + internal FlagPairG1() { } + } + + public sealed class FlagPairG1Detail + { + private readonly FlagPairG1 Backing; + + public readonly string Name; + internal readonly bool[] Event; + internal readonly bool[] Spawn; + + public FlagPairG1Detail(FlagPairG1 back, string name, bool[] ev, bool[] spawn) + { + Backing = back; + Name = name; + Event = ev; + Spawn = spawn; + } + + public void Invert() => SetState(!IsDespawned); + public void Reset() => SetState(false); + + public void SetState(bool despawned) + { + if (Backing.EventFlag != 0) + Event[Backing.EventFlag] = despawned; + if (Backing.SpawnFlag != 0) + Spawn[Backing.SpawnFlag] = despawned; + } + + public bool IsDespawned + { + get + { + bool result = false; + if (Backing.EventFlag != 0) + result |= Event[Backing.EventFlag]; + if (Backing.SpawnFlag != 0) + result |= Spawn[Backing.SpawnFlag]; + return result; } } } diff --git a/PKHeX.Core/Saves/Substructures/Gen3/ShadowInfo.cs b/PKHeX.Core/Saves/Substructures/Gen3/ShadowInfo.cs index a586cfa22..3e50878aa 100644 --- a/PKHeX.Core/Saves/Substructures/Gen3/ShadowInfo.cs +++ b/PKHeX.Core/Saves/Substructures/Gen3/ShadowInfo.cs @@ -23,6 +23,8 @@ public ShadowInfoTableXD(byte[] data) } } + public ShadowInfoTableXD() : this(new byte[SIZE_ENTRY * 200]) { } + private static ShadowInfoEntryXD GetEntry(byte[] data, int i) { var d = new byte[SIZE_ENTRY]; diff --git a/PKHeX.Core/Saves/Substructures/Gen3/StrategyMemo.cs b/PKHeX.Core/Saves/Substructures/Gen3/StrategyMemo.cs index e5889ae82..8df837c65 100644 --- a/PKHeX.Core/Saves/Substructures/Gen3/StrategyMemo.cs +++ b/PKHeX.Core/Saves/Substructures/Gen3/StrategyMemo.cs @@ -9,15 +9,19 @@ public sealed class StrategyMemo private readonly bool XD; private const int SIZE_ENTRY = 12; private readonly List Entries = new List(); + public const int MAX_COUNT = 500; + public const int MAX_SIZE = MAX_COUNT * SIZE_ENTRY; private StrategyMemoEntry this[int Species] => Entries.Find(e => e.Species == Species); private readonly byte[] _unk; + public StrategyMemo(bool xd = true) : this(new byte[MAX_SIZE], 0, xd) { } + public StrategyMemo(byte[] input, int offset, bool xd) { XD = xd; int count = BigEndian.ToInt16(input, offset); - if (count > 500) - count = 500; + if (count > MAX_COUNT) + count = MAX_COUNT; _unk = input.Slice(offset + 2, 2); for (int i = 0; i < count; i++) { @@ -56,9 +60,11 @@ public sealed class StrategyMemoEntry public readonly byte[] Data; private readonly bool XD; - public StrategyMemoEntry(bool xd, byte[] data = null) + public StrategyMemoEntry(bool xd) : this(xd, new byte[SIZE_ENTRY]) { } + + public StrategyMemoEntry(bool xd, byte[] data) { - Data = data ?? new byte[SIZE_ENTRY]; + Data = data; XD = xd; } diff --git a/PKHeX.Core/Saves/Substructures/Gen5/BattleSubway5.cs b/PKHeX.Core/Saves/Substructures/Gen5/BattleSubway5.cs index 8985d51e8..236a6839d 100644 --- a/PKHeX.Core/Saves/Substructures/Gen5/BattleSubway5.cs +++ b/PKHeX.Core/Saves/Substructures/Gen5/BattleSubway5.cs @@ -4,7 +4,8 @@ namespace PKHeX.Core { public sealed class BattleSubway5 : SaveBlock { - public BattleSubway5(SAV5 sav, int offset) : base(sav) => Offset = offset; + public BattleSubway5(SAV5BW sav, int offset) : base(sav) => Offset = offset; + public BattleSubway5(SAV5B2W2 sav, int offset) : base(sav) => Offset = offset; public int BP { diff --git a/PKHeX.Core/Saves/Substructures/Gen5/BoxLayout5.cs b/PKHeX.Core/Saves/Substructures/Gen5/BoxLayout5.cs index a0e004db4..6b9282b7c 100644 --- a/PKHeX.Core/Saves/Substructures/Gen5/BoxLayout5.cs +++ b/PKHeX.Core/Saves/Substructures/Gen5/BoxLayout5.cs @@ -2,7 +2,8 @@ { public sealed class BoxLayout5 : SaveBlock { - public BoxLayout5(SAV5 sav, int offset) : base(sav) => Offset = offset; + public BoxLayout5(SAV5BW sav, int offset) : base(sav) => Offset = offset; + public BoxLayout5(SAV5B2W2 sav, int offset) : base(sav) => Offset = offset; public int CurrentBox { get => Data[Offset]; set => Data[Offset] = (byte)value; } public int GetBoxNameOffset(int box) => Offset + (0x28 * box) + 4; diff --git a/PKHeX.Core/Saves/Substructures/Gen5/CGearBackground.cs b/PKHeX.Core/Saves/Substructures/Gen5/CGearBackground.cs index 3748a0c9e..f70805137 100644 --- a/PKHeX.Core/Saves/Substructures/Gen5/CGearBackground.cs +++ b/PKHeX.Core/Saves/Substructures/Gen5/CGearBackground.cs @@ -42,7 +42,7 @@ public sealed class CGearBackground public CGearBackground(byte[] data) { if (data.Length != SIZE_CGB) - return; + throw new ArgumentException(nameof(data)); // decode for easy handling if (!IsCGB(data)) @@ -76,8 +76,8 @@ public CGearBackground(byte[] data) Map = new TileMap(Region2); } - private readonly byte[] _cgb; - private readonly byte[] _psk; + private readonly byte[]? _cgb; + private readonly byte[]? _psk; private byte[] GetCGB() => _cgb ?? Write(); private byte[] GetPSK() => _psk ?? CGBtoPSK(Write()); public byte[] GetSkin(bool B2W2) => B2W2 ? GetCGB() : GetPSK(); @@ -163,23 +163,24 @@ public sealed class Tile private const int TileHeight = 8; internal readonly int[] ColorChoices; private byte[] PixelData; - private byte[] PixelDataX; - private byte[] PixelDataY; + private byte[]? PixelDataX; + private byte[]? PixelDataY; - internal Tile(byte[] data = null) + internal Tile() : this(new byte[SIZE_TILE]) { } + + internal Tile(byte[] data) { - if (data == null) - data = new byte[SIZE_TILE]; if (data.Length != SIZE_TILE) - return; + throw new ArgumentException(nameof(data)); - ColorChoices = new int[TileWidth*TileHeight]; + ColorChoices = new int[TileWidth * TileHeight]; for (int i = 0; i < data.Length; i++) { var ofs = i * 2; ColorChoices[ofs + 0] = data[i] & 0xF; ColorChoices[ofs + 1] = data[i] >> 4; } + PixelData = Array.Empty(); } internal void SetTile(int[] Palette) => PixelData = GetTileData(Palette); diff --git a/PKHeX.Core/Saves/Substructures/Gen5/Daycare5.cs b/PKHeX.Core/Saves/Substructures/Gen5/Daycare5.cs index db0e7e019..0d92eddae 100644 --- a/PKHeX.Core/Saves/Substructures/Gen5/Daycare5.cs +++ b/PKHeX.Core/Saves/Substructures/Gen5/Daycare5.cs @@ -27,7 +27,7 @@ public sealed class Daycare5 : SaveBlock public void SetSeed(string value) { - if (value == null || !(SAV is SAV5B2W2)) + if (!(SAV is SAV5B2W2)) return; var data = Util.GetBytesFromHexString(value); SAV.SetData(data, Offset + 0x1CC); diff --git a/PKHeX.Core/Saves/Substructures/Gen5/Misc5.cs b/PKHeX.Core/Saves/Substructures/Gen5/Misc5.cs index 02a3254cb..e87cf1d8a 100644 --- a/PKHeX.Core/Saves/Substructures/Gen5/Misc5.cs +++ b/PKHeX.Core/Saves/Substructures/Gen5/Misc5.cs @@ -4,7 +4,8 @@ namespace PKHeX.Core { public sealed class Misc5 : SaveBlock { - public Misc5(SAV5 sav, int offset) : base(sav) => Offset = offset; + public Misc5(SAV5BW sav, int offset) : base(sav) => Offset = offset; + public Misc5(SAV5B2W2 sav, int offset) : base(sav) => Offset = offset; public uint Money { diff --git a/PKHeX.Core/Saves/Substructures/Gen5/MysteryBlock5.cs b/PKHeX.Core/Saves/Substructures/Gen5/MysteryBlock5.cs index cbfe81b3c..d3ebf49a3 100644 --- a/PKHeX.Core/Saves/Substructures/Gen5/MysteryBlock5.cs +++ b/PKHeX.Core/Saves/Substructures/Gen5/MysteryBlock5.cs @@ -14,9 +14,10 @@ public sealed class MysteryBlock5 : SaveBlock private int SeedOffset => Offset + DataSize; // Everything is stored encrypted, and only decrypted on demand. Only crypt on object fetch... - public MysteryBlock5(SAV5 sav, int offset) : base(sav) => Offset = offset; + public MysteryBlock5(SAV5BW sav, int offset) : base(sav) => Offset = offset; + public MysteryBlock5(SAV5B2W2 sav, int offset) : base(sav) => Offset = offset; - public MysteryGiftAlbum GiftAlbum + public EncryptedMysteryGiftAlbum GiftAlbum { get { @@ -33,13 +34,14 @@ public MysteryGiftAlbum GiftAlbum } } - private static MysteryGiftAlbum GetAlbum(uint seed, byte[] wcData) + private static EncryptedMysteryGiftAlbum GetAlbum(uint seed, byte[] wcData) { - MysteryGiftAlbum Info = new MysteryGiftAlbum { Seed = seed }; PKX.CryptArray(wcData, seed); - Info.Flags = new bool[MaxReceivedFlag]; - Info.Gifts = new MysteryGift[MaxCardsPresent]; + var flags = new bool[MaxReceivedFlag]; + var gifts = new DataMysteryGift[MaxCardsPresent]; + var Info = new EncryptedMysteryGiftAlbum(gifts, flags, seed); + // 0x100 Bytes for Used Flags for (int i = 0; i < Info.Flags.Length; i++) Info.Flags[i] = (wcData[i / 8] >> i % 8 & 0x1) == 1; @@ -54,7 +56,7 @@ private static MysteryGiftAlbum GetAlbum(uint seed, byte[] wcData) return Info; } - private static byte[] SetAlbum(MysteryGiftAlbum value) + private static byte[] SetAlbum(EncryptedMysteryGiftAlbum value) { byte[] wcData = new byte[0xA90]; diff --git a/PKHeX.Core/Saves/Substructures/Gen5/PlayerData5.cs b/PKHeX.Core/Saves/Substructures/Gen5/PlayerData5.cs index ea1868319..abaff0dd7 100644 --- a/PKHeX.Core/Saves/Substructures/Gen5/PlayerData5.cs +++ b/PKHeX.Core/Saves/Substructures/Gen5/PlayerData5.cs @@ -4,7 +4,8 @@ namespace PKHeX.Core { public sealed class PlayerData5 : SaveBlock { - public PlayerData5(SAV5 sav, int offset) : base(sav) => Offset = offset; + public PlayerData5(SAV5BW sav, int offset) : base(sav) => Offset = offset; + public PlayerData5(SAV5B2W2 sav, int offset) : base(sav) => Offset = offset; public string OT { diff --git a/PKHeX.Core/Saves/Substructures/Gen6/BoxLayout6.cs b/PKHeX.Core/Saves/Substructures/Gen6/BoxLayout6.cs index 0ac4f4c41..9921030e9 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/BoxLayout6.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/BoxLayout6.cs @@ -9,14 +9,16 @@ public sealed class BoxLayout6 : SaveBlock // byte UnlockedCount; // byte CurrentBox; - private const int strlen = SAV6.LongStringLength / 2; + private const int strbytecount = SAV6XY.LongStringLength; // same for both games + private const int strlen = strbytecount / 2; private const int BoxCount = 31; - private const int PCBackgrounds = BoxCount * (strlen * 2); // 0x41E; + private const int PCBackgrounds = BoxCount * strbytecount; // 0x41E; private const int PCFlags = PCBackgrounds + BoxCount; // 0x43D; private const int Unlocked = PCFlags + 1; // 0x43E; private const int LastViewedBoxOffset = Unlocked + 1; // 0x43F; - public BoxLayout6(SAV6 sav, int offset) : base(sav) => Offset = offset; + public BoxLayout6(SAV6XY sav, int offset) : base(sav) => Offset = offset; + public BoxLayout6(SAV6AO sav, int offset) : base(sav) => Offset = offset; public int GetBoxWallpaperOffset(int box) => Offset + PCBackgrounds + box; @@ -34,14 +36,14 @@ public void SetBoxWallpaper(int box, int value) Data[GetBoxWallpaperOffset(box)] = (byte)value; } - private int GetBoxNameOffset(int box) => Offset + (SAV6.LongStringLength * box); + private int GetBoxNameOffset(int box) => Offset + (strbytecount * box); - public string GetBoxName(int box) => SAV.GetString(Data, GetBoxNameOffset(box), SAV6.LongStringLength); + public string GetBoxName(int box) => SAV.GetString(Data, GetBoxNameOffset(box), strbytecount); public void SetBoxName(int box, string value) { var data = SAV.SetString(value, strlen, strlen, 0); - var offset = GetBoxNameOffset(box) + (SAV6.LongStringLength * box); + var offset = GetBoxNameOffset(box) + (strbytecount * box); SAV.SetData(data, offset); } diff --git a/PKHeX.Core/Saves/Substructures/Gen6/Fashion6XY.cs b/PKHeX.Core/Saves/Substructures/Gen6/Fashion6XY.cs new file mode 100644 index 000000000..99209eaa8 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen6/Fashion6XY.cs @@ -0,0 +1,23 @@ +namespace PKHeX.Core +{ + public class Fashion6XY : SaveBlock + { + public Fashion6XY(SAV6XY sav, int offset) : base(sav) => Offset = offset; + + public void UnlockAllAccessories() + { + SAV.SetData(AllAccessories, Offset); + } + + private static readonly byte[] AllAccessories = + { + 0xFE,0xFF,0xFF,0x7E,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xEF,0xFF,0xFF,0xFF,0xF9,0xFF,0xFB,0xFF,0xF7,0xFF,0xFF,0x0F,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xFF, + 0xFF,0x7E,0xFF,0xFD,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xEF, + 0xFF,0xFF,0xFF,0xF9,0xFF,0xFB,0xFF,0xF7,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 + }; + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Substructures/Gen6/IPokePuff.cs b/PKHeX.Core/Saves/Substructures/Gen6/IPokePuff.cs index 29f95da8a..2b747c72b 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/IPokePuff.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/IPokePuff.cs @@ -1,3 +1,5 @@ +using System; + namespace PKHeX.Core { public interface IPokePuff @@ -12,6 +14,37 @@ public interface IOPower public interface ILink { - byte[] LinkBlock { get; set; } + Link6 LinkBlock { get; } + } + + public sealed class Link6 : SaveBlock + { + public Link6(SAV6XY sav, int offset) : base(sav) => Offset = offset; + public Link6(SAV6AO sav, int offset) : base(sav) => Offset = offset; + + public byte[] GetLinkInfoData() => Data.Slice(Offset + 0x1FF, PL6.Size); + public PL6 GetLinkInfo() => new PL6(GetLinkInfoData()); + + public void SetLinkInfoData(byte[] data) + { + data.CopyTo(Data, Offset); + Checksum = GetCalculatedChecksum(); // [app,chk) + } + + public void SetLinkInfo(PL6 pl6) + { + pl6.Data.CopyTo(Data, Offset + 0x1FF); + Checksum = GetCalculatedChecksum(); // [app,chk) + } + + private ushort GetCalculatedChecksum() => Checksums.CRC16_CCITT(Data, Offset + 0x200, 0xC48 - 4 - 0x200); // [app,chk) + + private int GetChecksumOffset() => Offset + 0xC48 - 4; + + public ushort Checksum + { + get => BitConverter.ToUInt16(Data, GetChecksumOffset()); + set => BitConverter.GetBytes(value).CopyTo(Data, GetChecksumOffset()); + } } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/Substructures/Gen6/ItemInfo6.cs b/PKHeX.Core/Saves/Substructures/Gen6/ItemInfo6.cs index f97250ad2..1d6657684 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/ItemInfo6.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/ItemInfo6.cs @@ -6,20 +6,23 @@ public sealed class ItemInfo6 : SaveBlock { public ItemInfo6(SaveFile sav, int offset) : base(sav) => Offset = offset; + private const int BoundItemCount = 4; + private const int RecentItemCount = 12; + public int[] SelectItems { // UP,RIGHT,DOWN,LEFT get { - int[] list = new int[4]; + int[] list = new int[BoundItemCount]; for (int i = 0; i < list.Length; i++) list[i] = BitConverter.ToUInt16(Data, Offset + 10 + (2 * i)); return list; } set { - if (value == null || value.Length > 4) - return; + if (value.Length != BoundItemCount) + throw new ArgumentException(nameof(value)); for (int i = 0; i < value.Length; i++) BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, Offset + 10 + (2 * i)); } @@ -30,15 +33,15 @@ public int[] RecentItems // Items recently interacted with (Give, Use) get { - int[] list = new int[12]; + int[] list = new int[RecentItemCount]; for (int i = 0; i < list.Length; i++) list[i] = BitConverter.ToUInt16(Data, Offset + 20 + (2 * i)); return list; } set { - if (value == null || value.Length > 12) - return; + if (value.Length != RecentItemCount) + throw new ArgumentException(nameof(value)); for (int i = 0; i < value.Length; i++) BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, Offset + 20 + (2 * i)); } diff --git a/PKHeX.Core/Saves/Substructures/Gen6/Misc6AO.cs b/PKHeX.Core/Saves/Substructures/Gen6/Misc6AO.cs new file mode 100644 index 000000000..abc632601 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen6/Misc6AO.cs @@ -0,0 +1,39 @@ +using System; + +namespace PKHeX.Core +{ + public interface IMisc6 + { + uint Money { get; set; } + } + + public sealed class Misc6AO : SaveBlock, IMisc6 + { + public Misc6AO(SAV6AO sav, int offset) : base(sav) => Offset = offset; + public Misc6AO(SAV6AODemo sav, int offset) : base(sav) => Offset = offset; + + public uint Money + { + get => BitConverter.ToUInt32(Data, Offset + 0x8); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x8); + } + + public int Badges + { + get => Data[Offset + 0xC]; + set => Data[Offset + 0xC] = (byte)value; + } + + public int BP + { + get => BitConverter.ToUInt16(Data, Offset + 0x30); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x30); + } + + public int Vivillon + { + get => Data[Offset + 0x44]; + set => Data[Offset + 0x44] = (byte)value; + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Substructures/Gen6/Misc6XY.cs b/PKHeX.Core/Saves/Substructures/Gen6/Misc6XY.cs new file mode 100644 index 000000000..6f4334e89 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen6/Misc6XY.cs @@ -0,0 +1,33 @@ +using System; + +namespace PKHeX.Core +{ + public sealed class Misc6XY : SaveBlock, IMisc6 + { + public Misc6XY(SAV6XY sav, int offset) : base(sav) => Offset = offset; + + public uint Money + { + get => BitConverter.ToUInt32(Data, Offset + 0x8); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x8); + } + + public int Badges + { + get => Data[Offset + 0xC]; + set => Data[Offset + 0xC] = (byte)value; + } + + public int BP + { + get => BitConverter.ToUInt16(Data, Offset + 0x3C); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x3C); + } + + public int Vivillon + { + get => Data[Offset + 0x50]; + set => Data[Offset + 0x50] = (byte)value; + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Substructures/Gen6/MyItem6AO.cs b/PKHeX.Core/Saves/Substructures/Gen6/MyItem6AO.cs index 2499a7b94..0f6db811a 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/MyItem6AO.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/MyItem6AO.cs @@ -8,7 +8,7 @@ public sealed class MyItem6AO : MyItem private const int Medicine = 0x970; // 3, +2 items shift because 2 HMs added private const int Berry = 0xA70; // 4 - public MyItem6AO(SaveFile SAV, int offset) : base(SAV) => Offset = offset; + public MyItem6AO(SAV6 SAV, int offset) : base(SAV) => Offset = offset; public override InventoryPouch[] Inventory { diff --git a/PKHeX.Core/Saves/Substructures/Gen6/MyStatus6.cs b/PKHeX.Core/Saves/Substructures/Gen6/MyStatus6.cs index 97a275d24..383817df3 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/MyStatus6.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/MyStatus6.cs @@ -49,10 +49,8 @@ public string GameSyncID get => Util.GetHexStringFromBytes(Data, Offset + 0x08, GameSyncIDSize / 2); set { - if (value == null) - return; if (value.Length != GameSyncIDSize) - return; + throw new ArgumentException(nameof(value)); var data = Util.GetBytesFromHexString(value); SAV.SetData(data, Offset + 0x08); @@ -101,9 +99,9 @@ public string OT set => SAV.SetData(SAV.SetString(value, SAV.OTLength), Offset + 0x48); } - private int GetSayingOffset(int say) => Offset + 0x7C + (SAV6.LongStringLength * say); - private string GetSaying(int say) => SAV.GetString(GetSayingOffset(say), SAV6.LongStringLength); - private void SetSaying(int say, string value) => SAV.SetData(SAV.SetString(value, SAV6.LongStringLength / 2), GetSayingOffset(say)); + private int GetSayingOffset(int say) => Offset + 0x7C + (SAV6XY.LongStringLength * say); + private string GetSaying(int say) => SAV.GetString(GetSayingOffset(say), SAV6XY.LongStringLength); + private void SetSaying(int say, string value) => SAV.SetData(SAV.SetString(value, SAV6XY.LongStringLength / 2), GetSayingOffset(say)); public string Saying1 { get => GetSaying(0); set => SetSaying(0, value); } public string Saying2 { get => GetSaying(1); set => SetSaying(1, value); } diff --git a/PKHeX.Core/Saves/Substructures/Gen6/MyStatus6XY.cs b/PKHeX.Core/Saves/Substructures/Gen6/MyStatus6XY.cs index 78a3c084b..ff61ea7b5 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/MyStatus6XY.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/MyStatus6XY.cs @@ -18,8 +18,8 @@ public TrainerFashion6 Fashion public string OT_Nick { - get => SAV.GetString(Offset + 0x62, SAV6.ShortStringLength / 2); - set => SAV.SetData(SAV.SetString(value, SAV6.ShortStringLength / 2), Offset + 0x62); + get => SAV.GetString(Offset + 0x62, SAV6XY.ShortStringLength / 2); + set => SAV.SetData(SAV.SetString(value, SAV6XY.ShortStringLength / 2), Offset + 0x62); } public short EyeColor diff --git a/PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs b/PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs index f7aeacd86..5bb04a39a 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/MysteryBlock6.cs @@ -10,7 +10,8 @@ public sealed class MysteryBlock6 : SaveBlock // private const int FlagRegionSize = (MaxReceivedFlag / 8); // 0x100 private const int CardStart = FlagStart + (MaxReceivedFlag / 8); - public MysteryBlock6(SAV6 sav, int offset) : base(sav) => Offset = offset; + public MysteryBlock6(SAV6XY sav, int offset) : base(sav) => Offset = offset; + public MysteryBlock6(SAV6AO sav, int offset) : base(sav) => Offset = offset; public bool[] MysteryGiftReceivedFlags { @@ -24,11 +25,11 @@ public bool[] MysteryGiftReceivedFlags } } - public MysteryGift[] MysteryGiftCards + public DataMysteryGift[] MysteryGiftCards { get { - var cards = new MysteryGift[MaxCardsPresent]; + var cards = new DataMysteryGift[MaxCardsPresent]; for (int i = 0; i < cards.Length; i++) cards[i] = GetGift(i); return cards; @@ -43,7 +44,7 @@ public MysteryGift[] MysteryGiftCards } } - public MysteryGift GetGift(int index) + public DataMysteryGift GetGift(int index) { if ((uint)index > MaxCardsPresent) throw new ArgumentOutOfRangeException(nameof(index)); @@ -55,7 +56,7 @@ public MysteryGift GetGift(int index) private int GetGiftOffset(int index) => Offset + CardStart + (index * WC6.Size); - public void SetGift(MysteryGift wc6, int index) + public void SetGift(DataMysteryGift wc6, int index) { if ((uint)index > MaxCardsPresent) throw new ArgumentOutOfRangeException(nameof(index)); @@ -67,7 +68,7 @@ public void SetGift(MysteryGift wc6, int index) if (!(SAV is SAV6AO ao)) return; // Set the special received data - var info = ao.Sango; + var info = ao.Blocks.Sango; info.ReceiveEon(); info.EnableSendEon(); } diff --git a/PKHeX.Core/Saves/Substructures/Gen6/Record6.cs b/PKHeX.Core/Saves/Substructures/Gen6/Record6.cs index b8fd51baa..0d6619924 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/Record6.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/Record6.cs @@ -9,16 +9,34 @@ public sealed class Record6 : RecordBlock public const int RecordCount = 200; protected override IReadOnlyList RecordMax { get; } - public Record6(SAV6 sav, int offset, IReadOnlyList maxes) : base(sav) + public Record6(SAV6XY sav, int offset) : base(sav) { Offset = offset; - RecordMax = maxes; + RecordMax = Records.MaxType_XY; } - public Record6(SAV7 sav, int offset, IReadOnlyList maxes) : base(sav) + public Record6(SAV6AO sav, int offset) : base(sav) { Offset = offset; - RecordMax = maxes; + RecordMax = Records.MaxType_AO; + } + + public Record6(SAV6AODemo sav, int offset) : base(sav) + { + Offset = offset; + RecordMax = Records.MaxType_AO; + } + + public Record6(SAV7SM sav, int offset) : base(sav) + { + Offset = offset; + RecordMax = Records.MaxType_SM; + } + + public Record6(SAV7USUM sav, int offset) : base(sav) + { + Offset = offset; + RecordMax = Records.MaxType_USUM; } public override int GetRecord(int recordID) diff --git a/PKHeX.Core/Saves/Substructures/Gen7/BattleTree7.cs b/PKHeX.Core/Saves/Substructures/Gen7/BattleTree7.cs index 26755ee12..66c81e532 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/BattleTree7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/BattleTree7.cs @@ -4,7 +4,8 @@ namespace PKHeX.Core { public sealed class BattleTree7 : SaveBlock { - public BattleTree7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public BattleTree7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public BattleTree7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public int GetTreeStreak(int battletype, bool super, bool max) { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/BoxLayout7.cs b/PKHeX.Core/Saves/Substructures/Gen7/BoxLayout7.cs index cfe6e5f55..f9e79d06f 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/BoxLayout7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/BoxLayout7.cs @@ -12,13 +12,14 @@ public sealed class BoxLayout7 : SaveBlock private const int Unlocked = 0x5E1; private const int LastViewedBoxOffset = 0x5E3; - private const int strlen = SAV6.LongStringLength / 2; + private const int strlen = SAV6XY.LongStringLength / 2; private const int TeamCount = 6; private const int NONE_SELECTED = -1; public readonly int[] TeamSlots = new int[TeamCount * 6]; - public BoxLayout7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public BoxLayout7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public BoxLayout7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public int GetBoxWallpaperOffset(int box) => Offset + PCBackgrounds + box; @@ -36,17 +37,17 @@ public void SetBoxWallpaper(int box, int value) Data[GetBoxWallpaperOffset(box)] = (byte)value; } - private int GetBoxNameOffset(int box) => Offset + (SAV6.LongStringLength * box); + private int GetBoxNameOffset(int box) => Offset + (SAV6XY.LongStringLength * box); public string GetBoxName(int box) { - return SAV.GetString(Data, GetBoxNameOffset(box), SAV6.LongStringLength); + return SAV.GetString(Data, GetBoxNameOffset(box), SAV6XY.LongStringLength); } public void SetBoxName(int box, string value) { var data = SAV.SetString(value, strlen, strlen, 0); - var offset = GetBoxNameOffset(box) + (SAV6.LongStringLength * box); + var offset = GetBoxNameOffset(box) + (SAV6XY.LongStringLength * box); SAV.SetData(data, offset); } diff --git a/PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7.cs b/PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7.cs index 79a7aab2d..e76e3e45e 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7.cs @@ -14,7 +14,8 @@ public sealed class ConfigSave7 : SaveBlock * everything else: unknown */ - public ConfigSave7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public ConfigSave7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public ConfigSave7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public int ConfigValue { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7b.cs b/PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7b.cs index 2f132b064..26f3953dc 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7b.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/ConfigSave7b.cs @@ -13,11 +13,7 @@ public sealed class ConfigSave7b : SaveBlock * everything else: unknown */ - - public ConfigSave7b(SAV7b sav) : base(sav) - { - Offset = sav.GetBlockOffset(BelugaBlockIndex.ConfigSave); - } + public ConfigSave7b(SAV7b sav, int offset) : base(sav) => Offset = offset; public int ConfigValue { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/Daycare7.cs b/PKHeX.Core/Saves/Substructures/Gen7/Daycare7.cs index a8b43c02c..5e6eff8aa 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/Daycare7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/Daycare7.cs @@ -4,7 +4,8 @@ public sealed class Daycare7 : SaveBlock { public const int DaycareSeedSize = 32; // 128 bits - public Daycare7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public Daycare7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public Daycare7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public bool GetIsOccupied(int slot) { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/EventWork7b.cs b/PKHeX.Core/Saves/Substructures/Gen7/EventWork7b.cs index 180ad4319..70fa7c0ef 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/EventWork7b.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/EventWork7b.cs @@ -4,9 +4,9 @@ namespace PKHeX.Core { public sealed class EventWork7b : SaveBlock, IEventWork { - public EventWork7b(SAV7b sav) : base(sav) + public EventWork7b(SAV7b sav, int offset) : base(sav) { - Offset = sav.GetBlockOffset(BelugaBlockIndex.EventWork); + Offset = offset; // Zone @ 0x21A0 - 0x21AF (128 flags) // System @ 0x21B0 - 0x21EF (512 flags) -- is this really 256 instead, with another 256 region after for the small vanish? // Vanish @ 0x21F0 - 0x22AF (1536 flags) @@ -14,7 +14,6 @@ public EventWork7b(SAV7b sav) : base(sav) // time flags (39 used flags of 42) = 6 bytes 0x22F0-0x22F5 // trainer flags (???) = 0x22F6 - end? - } // Overall Layout diff --git a/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs b/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs index b1e72faa0..c78a8cc12 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs @@ -5,7 +5,8 @@ namespace PKHeX.Core { public sealed class FashionBlock7 : SaveBlock { - public FashionBlock7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public FashionBlock7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public FashionBlock7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; private const int FashionLength = 0x1A08; diff --git a/PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs b/PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs index dac1936b0..6d464af10 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/FieldMenu7.cs @@ -2,7 +2,8 @@ { public sealed class FieldMenu7 : SaveBlock { - public FieldMenu7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public FieldMenu7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public FieldMenu7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; // USUM ONLY public string RotomOT diff --git a/PKHeX.Core/Saves/Substructures/Gen7/FieldMoveModelSave7.cs b/PKHeX.Core/Saves/Substructures/Gen7/FieldMoveModelSave7.cs index 6a4b14251..bcca09002 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/FieldMoveModelSave7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/FieldMoveModelSave7.cs @@ -4,7 +4,8 @@ namespace PKHeX.Core { public sealed class FieldMoveModelSave7 : SaveBlock { - public FieldMoveModelSave7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public FieldMoveModelSave7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public FieldMoveModelSave7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public int M { get => BitConverter.ToUInt16(Data, Offset + 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x00); } public float X { get => BitConverter.ToSingle(Data, Offset + 0x08); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x08); } diff --git a/PKHeX.Core/Saves/Substructures/Gen7/GoParkStorage.cs b/PKHeX.Core/Saves/Substructures/Gen7/GoParkStorage.cs index 618a9bd59..0f1934e68 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/GoParkStorage.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/GoParkStorage.cs @@ -9,7 +9,7 @@ public sealed class GoParkStorage : SaveBlock, IEnumerable { public GoParkStorage(SaveFile sav) : base(sav) { - Offset = ((SAV7b)sav).GetBlockOffset(BelugaBlockIndex.GoParkEntities); + Offset = ((SAV7b)sav).Blocks.GetBlockOffset(BelugaBlockIndex.GoParkEntities); } public const int SlotsPerArea = 50; @@ -41,7 +41,7 @@ public GP1[] AllEntities } set { - Debug.Assert(value?.Length == Count); + Debug.Assert(value.Length == Count); for (int i = 0; i < value.Length; i++) this[i] = value[i]; } diff --git a/PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs b/PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs index 88ef69c38..7ead1efca 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/JoinFesta7.cs @@ -5,7 +5,8 @@ namespace PKHeX.Core { public sealed class JoinFesta7 : SaveBlock { - public JoinFesta7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public JoinFesta7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public JoinFesta7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public int FestaCoins { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/Misc7.cs b/PKHeX.Core/Saves/Substructures/Gen7/Misc7.cs index 1545a3058..e621cabfd 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/Misc7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/Misc7.cs @@ -4,15 +4,16 @@ namespace PKHeX.Core { public sealed class Misc7 : SaveBlock { - public Misc7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public Misc7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public Misc7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public uint Money { get => BitConverter.ToUInt32(Data, Offset + 0x4); set { - if (value > 9999999) - value = 9999999; + if (value > 9_999_999) + value = 9_999_999; SAV.SetData(BitConverter.GetBytes(value), Offset + 0x4); } } diff --git a/PKHeX.Core/Saves/Substructures/Gen7/Misc7b.cs b/PKHeX.Core/Saves/Substructures/Gen7/Misc7b.cs index 76b37400e..d163708b7 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/Misc7b.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/Misc7b.cs @@ -4,10 +4,7 @@ namespace PKHeX.Core { public sealed class Misc7b : SaveBlock { - public Misc7b(SaveFile sav) : base(sav) - { - Offset = ((SAV7b)sav).GetBlockOffset(BelugaBlockIndex.Misc); - } + public Misc7b(SAV7b sav, int offset) : base(sav) => Offset = offset; public uint Money { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/MyItem7SM.cs b/PKHeX.Core/Saves/Substructures/Gen7/MyItem7SM.cs index dae63c3aa..eb7e69cb1 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/MyItem7SM.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/MyItem7SM.cs @@ -9,7 +9,7 @@ public sealed class MyItem7SM : MyItem private const int Berry = Medicine + (4 * 64); // 72 (Case 3) private const int ZCrystals = Berry + (4 * 72); // 30 (Case 5) - public MyItem7SM(SaveFile SAV, int offset) : base(SAV) => Offset = offset; + public MyItem7SM(SAV7SM SAV, int offset) : base(SAV) => Offset = offset; public override InventoryPouch[] Inventory { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/MyItem7b.cs b/PKHeX.Core/Saves/Substructures/Gen7/MyItem7b.cs index 19e226f9c..8848ed3df 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/MyItem7b.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/MyItem7b.cs @@ -10,7 +10,7 @@ public sealed class MyItem7b : MyItem private const int Battle = 0x08E0; // 5 private const int Key = 0x0B38; // 6 - public MyItem7b(SaveFile SAV) : base(SAV) { } + public MyItem7b(SAV7b sav, int offset) : base(sav) => Offset = offset; public override InventoryPouch[] Inventory { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/MyStatus7.cs b/PKHeX.Core/Saves/Substructures/Gen7/MyStatus7.cs index d1673a1a5..2dd18ef5d 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/MyStatus7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/MyStatus7.cs @@ -8,7 +8,8 @@ public sealed class MyStatus7 : SaveBlock public const int GameSyncIDSize = 16; // 64 bits public const int NexUniqueIDSize = 32; // 128 bits - public MyStatus7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public MyStatus7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public MyStatus7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public int TID { @@ -39,10 +40,8 @@ public string GameSyncID get => Util.GetHexStringFromBytes(Data, Offset + 0x10, GameSyncIDSize / 2); set { - if (value == null) - return; if (value.Length != GameSyncIDSize) - return; + throw new ArgumentException(nameof(value)); var data = Util.GetBytesFromHexString(value); SAV.SetData(data, Offset + 0x10); @@ -54,10 +53,8 @@ public string NexUniqueID get => Util.GetHexStringFromBytes(Data, Offset + 0x18, NexUniqueIDSize / 2); set { - if (value == null) - return; if (value.Length != NexUniqueIDSize) - return; + throw new ArgumentException(nameof(value)); var data = Util.GetBytesFromHexString(value); SAV.SetData(data, Offset + 0x18); diff --git a/PKHeX.Core/Saves/Substructures/Gen7/MyStatus7b.cs b/PKHeX.Core/Saves/Substructures/Gen7/MyStatus7b.cs index 326c8eaea..d296b0507 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/MyStatus7b.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/MyStatus7b.cs @@ -5,10 +5,7 @@ namespace PKHeX.Core { public sealed class MyStatus7b : SaveBlock { - public MyStatus7b(SaveFile sav) : base(sav) - { - Offset = ((SAV7b)sav).GetBlockOffset(BelugaBlockIndex.MyStatus); - } + public MyStatus7b(SAV7b sav, int offset) : base(sav) => Offset = offset; // Player Information @@ -49,10 +46,8 @@ public string GameSyncID } set { - if (value == null) - return; if (value.Length > 16) - return; + throw new ArgumentException(nameof(value)); Enumerable.Range(0, value.Length) .Where(x => x % 2 == 0) diff --git a/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs b/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs index 95b149d02..092800557 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/MysteryBlock7.cs @@ -10,7 +10,8 @@ public sealed class MysteryBlock7 : SaveBlock // private const int FlagRegionSize = (MaxReceivedFlag / 8); // 0x100 private const int CardStart = FlagStart + (MaxReceivedFlag / 8); - public MysteryBlock7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public MysteryBlock7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public MysteryBlock7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; // Mystery Gift public bool[] MysteryGiftReceivedFlags @@ -25,11 +26,11 @@ public bool[] MysteryGiftReceivedFlags } } - public MysteryGift[] MysteryGiftCards + public DataMysteryGift[] MysteryGiftCards { get { - var cards = new MysteryGift[MaxCardsPresent]; + var cards = new DataMysteryGift[MaxCardsPresent]; for (int i = 0; i < cards.Length; i++) cards[i] = GetGift(i); return cards; @@ -38,25 +39,25 @@ public MysteryGift[] MysteryGiftCards { int count = Math.Min(MaxCardsPresent, value.Length); for (int i = 0; i < count; i++) - SetGift(value[i], i); + SetGift((WC7)value[i], i); for (int i = value.Length; i < MaxCardsPresent; i++) SetGift(new WC7(), i); } } - private MysteryGift GetGift(int index) + private WC7 GetGift(int index) { if ((uint)index > MaxCardsPresent) throw new ArgumentOutOfRangeException(nameof(index)); var offset = GetGiftOffset(index); - var data = SAV.GetData(offset, WC6.Size); + var data = SAV.GetData(offset, WC7.Size); return new WC7(data); } private int GetGiftOffset(int index) => Offset + CardStart + (index * WC7.Size); - private void SetGift(MysteryGift wc7, int index) + private void SetGift(WC7 wc7, int index) { if ((uint)index > MaxCardsPresent) throw new ArgumentOutOfRangeException(nameof(index)); diff --git a/PKHeX.Core/Saves/Substructures/Gen7/PlayTime7b.cs b/PKHeX.Core/Saves/Substructures/Gen7/PlayTime7b.cs index fe26e7764..6d1055397 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/PlayTime7b.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/PlayTime7b.cs @@ -4,10 +4,7 @@ namespace PKHeX.Core { public sealed class PlayTime7b : SaveBlock { - public PlayTime7b(SaveFile sav) : base(sav) - { - Offset = ((SAV7b)sav).GetBlockOffset(BelugaBlockIndex.PlayTime); - } + public PlayTime7b(SAV7b sav, int offset) : base(sav) => Offset = offset; public int PlayedHours { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/PokeFinder7.cs b/PKHeX.Core/Saves/Substructures/Gen7/PokeFinder7.cs index 68cdab9e8..44f4db93f 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/PokeFinder7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/PokeFinder7.cs @@ -4,7 +4,8 @@ namespace PKHeX.Core { public sealed class PokeFinder7 : SaveBlock { - public PokeFinder7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public PokeFinder7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public PokeFinder7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public ushort CameraVersion { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/PokeListHeader.cs b/PKHeX.Core/Saves/Substructures/Gen7/PokeListHeader.cs index 15d2a5ed3..8aa316564 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/PokeListHeader.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/PokeListHeader.cs @@ -26,9 +26,9 @@ public sealed class PokeListHeader : SaveBlock private const int MAX_SLOTS = 1000; private const int SLOT_EMPTY = 1001; - public PokeListHeader(SaveFile sav) : base(sav) + public PokeListHeader(SAV7b sav, int offset) : base(sav) { - Offset = ((SAV7b)sav).GetBlockOffset(BelugaBlockIndex.PokeListHeader); + Offset = offset; PokeListInfo = LoadPointerData(); if (!sav.Exportable) { diff --git a/PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs b/PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs index 774f80a20..0f4a4a0ce 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/ResortSave7.cs @@ -4,7 +4,8 @@ namespace PKHeX.Core { public sealed class ResortSave7 : SaveBlock { - public ResortSave7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public ResortSave7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public ResortSave7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; public const int ResortCount = 93; public int GetResortSlotOffset(int slot) => Offset + 0x16 + (slot * PKX.SIZE_6STORED); diff --git a/PKHeX.Core/Saves/Substructures/Gen7/Situation7.cs b/PKHeX.Core/Saves/Substructures/Gen7/Situation7.cs index 4054dd3be..2738e67ad 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/Situation7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/Situation7.cs @@ -4,7 +4,8 @@ namespace PKHeX.Core { public sealed class Situation7 : SaveBlock { - public Situation7(SAV7 sav, int offset) : base(sav) => Offset = offset; + public Situation7(SAV7SM sav, int offset) : base(sav) => Offset = offset; + public Situation7(SAV7USUM sav, int offset) : base(sav) => Offset = offset; // "StartLocation" public int M { get => BitConverter.ToUInt16(Data, Offset + 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x00); } @@ -15,65 +16,7 @@ public sealed class Situation7 : SaveBlock public void UpdateOverworldCoordinates() { - var o = ((SAV7) SAV).OverworldBlock; - o.M = M; - o.X = X; - o.Z = Z; - o.Y = Y; - o.R = R; - } - - public int SpecialLocation - { - get => Data[Offset + 0x24]; - set => Data[Offset + 0x24] = (byte)value; - } - - public int WarpContinueRequest - { - get => Data[Offset + 0x6E]; - set => Data[Offset + 0x6E] = (byte)value; - } - - public int StepCountEgg - { - get => BitConverter.ToInt32(Data, Offset + 0x70); - set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x70); - } - - public int LastZoneID - { - get => BitConverter.ToUInt16(Data, Offset + 0x74); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x74); - } - - public int StepCountFriendship - { - get => BitConverter.ToUInt16(Data, Offset + 0x76); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x76); - } - - public int StepCountAffection // Kawaigari - { - get => BitConverter.ToUInt16(Data, Offset + 0x78); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x78); - } - } - - public sealed class Situation8 : SaveBlock - { - public Situation8(SAV8 sav, int offset) : base(sav) => Offset = offset; - - // "StartLocation" - public int M { get => BitConverter.ToUInt16(Data, Offset + 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x00); } - public float X { get => BitConverter.ToSingle(Data, Offset + 0x08); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x08); } - public float Z { get => BitConverter.ToSingle(Data, Offset + 0x10); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x10); } - public float Y { get => (int)BitConverter.ToSingle(Data, Offset + 0x18); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x18); } - public float R { get => (int)BitConverter.ToSingle(Data, Offset + 0x20); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x20); } - - public void UpdateOverworldCoordinates() - { - var o = ((SAV8)SAV).OverworldBlock; + var o = ((SAV7)SAV).OverworldBlock; o.M = M; o.X = X; o.Z = Z; diff --git a/PKHeX.Core/Saves/Substructures/Gen7/Situation8.cs b/PKHeX.Core/Saves/Substructures/Gen7/Situation8.cs new file mode 100644 index 000000000..a4eb0f60a --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen7/Situation8.cs @@ -0,0 +1,62 @@ +using System; + +namespace PKHeX.Core +{ + public sealed class Situation8 : SaveBlock + { + public Situation8(SAV8SWSH sav, int offset) : base(sav) => Offset = offset; + + // "StartLocation" + public int M { get => BitConverter.ToUInt16(Data, Offset + 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x00); } + public float X { get => BitConverter.ToSingle(Data, Offset + 0x08); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x08); } + public float Z { get => BitConverter.ToSingle(Data, Offset + 0x10); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x10); } + public float Y { get => (int)BitConverter.ToSingle(Data, Offset + 0x18); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x18); } + public float R { get => (int)BitConverter.ToSingle(Data, Offset + 0x20); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x20); } + + public void UpdateOverworldCoordinates() + { + var o = ((SAV8)SAV).OverworldBlock; + o.M = M; + o.X = X; + o.Z = Z; + o.Y = Y; + o.R = R; + } + + public int SpecialLocation + { + get => Data[Offset + 0x24]; + set => Data[Offset + 0x24] = (byte)value; + } + + public int WarpContinueRequest + { + get => Data[Offset + 0x6E]; + set => Data[Offset + 0x6E] = (byte)value; + } + + public int StepCountEgg + { + get => BitConverter.ToInt32(Data, Offset + 0x70); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x70); + } + + public int LastZoneID + { + get => BitConverter.ToUInt16(Data, Offset + 0x74); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x74); + } + + public int StepCountFriendship + { + get => BitConverter.ToUInt16(Data, Offset + 0x76); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x76); + } + + public int StepCountAffection // Kawaigari + { + get => BitConverter.ToUInt16(Data, Offset + 0x78); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x78); + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Substructures/Gen7/WB7Records.cs b/PKHeX.Core/Saves/Substructures/Gen7/WB7Records.cs index 61c70bd74..a5ea5e6a5 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/WB7Records.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/WB7Records.cs @@ -4,10 +4,7 @@ namespace PKHeX.Core { public sealed class WB7Records : SaveBlock { - public WB7Records(SaveFile sav) : base(sav) - { - Offset = ((SAV7b) sav).GetBlockOffset(BelugaBlockIndex.WB7Record); - } + public WB7Records(SAV7b sav, int offset) : base(sav) => Offset = offset; private const int RecordMax = 10; // 0xE90 > (0x140 * 0xA = 0xC80), not sure what final 0x210 bytes are used for private const int FlagCountMax = 0x1C00; // (7168) end of the block? diff --git a/PKHeX.Core/Saves/Substructures/Gen7/WormholeInfoReader.cs b/PKHeX.Core/Saves/Substructures/Gen7/WormholeInfoReader.cs index ea650024f..96fecbdd1 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/WormholeInfoReader.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/WormholeInfoReader.cs @@ -9,8 +9,8 @@ public sealed class WormholeInfoReader // https://projectpokemon.org/home/forums/topic/39433-gen-7-save-research-thread/?page=3&tab=comments#comment-239090 public bool WormholeShininess // 0x4535 = Misc (0x4400 in USUM) + 0x0135 { - get => SAV.Data[SAV.Misc + 0x0135] == 1; - set => SAV.Data[SAV.Misc + 0x0135] = (byte)(value ? 1 : 0); + get => SAV.Data[SAV.MiscBlock.Offset + 0x0135] == 1; + set => SAV.Data[SAV.MiscBlock.Offset + 0x0135] = (byte)(value ? 1 : 0); } public const int WormholeSlotMax = 15; diff --git a/PKHeX.Core/Saves/Substructures/Gen8/BoxLayout8.cs b/PKHeX.Core/Saves/Substructures/Gen8/BoxLayout8.cs index 93aadf92e..20b6b2bb5 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/BoxLayout8.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/BoxLayout8.cs @@ -10,9 +10,9 @@ public sealed class BoxLayout8 : SaveBlock private const int Unlocked = 0x5E1; private const int LastViewedBoxOffset = 0x5E3; - private const int strlen = SAV6.LongStringLength / 2; + private const int strlen = SAV6XY.LongStringLength / 2; - public BoxLayout8(SAV8 sav, int offset) : base(sav) => Offset = offset; + public BoxLayout8(SAV8SWSH sav, int offset) : base(sav) => Offset = offset; public int GetBoxWallpaperOffset(int box) => -1; // Offset + PCBackgrounds + box; @@ -30,17 +30,17 @@ public void SetBoxWallpaper(int box, int value) Data[GetBoxWallpaperOffset(box)] = (byte)value; } - private int GetBoxNameOffset(int box) => Offset + (SAV6.LongStringLength * box); + private int GetBoxNameOffset(int box) => Offset + (SAV6XY.LongStringLength * box); public string GetBoxName(int box) { - return SAV.GetString(Data, GetBoxNameOffset(box), SAV6.LongStringLength); + return SAV.GetString(Data, GetBoxNameOffset(box), SAV6XY.LongStringLength); } public void SetBoxName(int box, string value) { var data = SAV.SetString(value, strlen, strlen, 0); - var offset = GetBoxNameOffset(box) + (SAV6.LongStringLength * box); + var offset = GetBoxNameOffset(box) + (SAV6XY.LongStringLength * box); SAV.SetData(data, offset); } diff --git a/PKHeX.Core/Saves/Substructures/Gen8/ConfigSave8.cs b/PKHeX.Core/Saves/Substructures/Gen8/ConfigSave8.cs index 2347e1dc2..7c5f803a7 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/ConfigSave8.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/ConfigSave8.cs @@ -14,7 +14,7 @@ public sealed class ConfigSave8 : SaveBlock * everything else: unknown */ - public ConfigSave8(SAV8 sav, int offset) : base(sav) => Offset = offset; + public ConfigSave8(SAV8SWSH sav, int offset) : base(sav) => Offset = offset; public int ConfigValue { diff --git a/PKHeX.Core/Saves/Substructures/Gen8/EventWork8.cs b/PKHeX.Core/Saves/Substructures/Gen8/EventWork8.cs index 309d6c181..545ab1411 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/EventWork8.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/EventWork8.cs @@ -4,9 +4,9 @@ namespace PKHeX.Core { public sealed class EventWork8 : SaveBlock, IEventWork { - public EventWork8(SAV8 sav) : base(sav) + public EventWork8(SAV8SWSH sav) : base(sav) { - Offset = sav.GetBlockOffset(SAV8BlockIndex.EventWork); + Offset = sav.Blocks.GetBlockOffset(SAV8BlockIndex.EventWork); } // Overall Layout diff --git a/PKHeX.Core/Saves/Substructures/Gen8/FieldMoveModelSave8.cs b/PKHeX.Core/Saves/Substructures/Gen8/FieldMoveModelSave8.cs index 412d3cdc9..4b82da5fd 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/FieldMoveModelSave8.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/FieldMoveModelSave8.cs @@ -4,7 +4,7 @@ namespace PKHeX.Core { public sealed class FieldMoveModelSave8 : SaveBlock { - public FieldMoveModelSave8(SAV8 sav, int offset) : base(sav) => Offset = offset; + public FieldMoveModelSave8(SAV8SWSH sav, int offset) : base(sav) => Offset = offset; public int M { get => BitConverter.ToUInt16(Data, Offset + 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, Offset + 0x00); } public float X { get => BitConverter.ToSingle(Data, Offset + 0x08); set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x08); } diff --git a/PKHeX.Core/Saves/Substructures/Gen8/Misc8.cs b/PKHeX.Core/Saves/Substructures/Gen8/Misc8.cs index 6951633e2..73b36ed89 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/Misc8.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/Misc8.cs @@ -4,7 +4,7 @@ namespace PKHeX.Core { public sealed class Misc8 : SaveBlock { - public Misc8(SAV8 sav, int offset) : base(sav) => Offset = offset; + public Misc8(SAV8SWSH sav, int offset) : base(sav) => Offset = offset; public uint Money { diff --git a/PKHeX.Core/Saves/Substructures/Gen8/MyStatus8.cs b/PKHeX.Core/Saves/Substructures/Gen8/MyStatus8.cs index 2471d55cc..9443bd8cf 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/MyStatus8.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/MyStatus8.cs @@ -4,7 +4,7 @@ namespace PKHeX.Core { public sealed class MyStatus8 : SaveBlock { - public MyStatus8(SAV8 sav, int offset) : base(sav) => Offset = offset; + public MyStatus8(SAV8SWSH sav, int offset) : base(sav) => Offset = offset; public int TID { diff --git a/PKHeX.Core/Saves/Substructures/Gen8/Record6.cs b/PKHeX.Core/Saves/Substructures/Gen8/Record6.cs index 5a54805f4..aba1774f6 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/Record6.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/Record6.cs @@ -9,7 +9,7 @@ public sealed class Record8 : RecordBlock public const int RecordCount = 200; protected override IReadOnlyList RecordMax { get; } - public Record8(SAV8 sav, int offset, IReadOnlyList maxes) : base(sav) + public Record8(SAV8SWSH sav, int offset, IReadOnlyList maxes) : base(sav) { Offset = offset; RecordMax = maxes; diff --git a/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch.cs b/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch.cs index 207c4adea..6fd066011 100644 --- a/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch.cs +++ b/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch.cs @@ -19,6 +19,7 @@ public abstract class InventoryPouch protected InventoryPouch(InventoryType type, ushort[] legal, int maxcount, int offset, int size = -1) { + Items = Array.Empty(); Type = type; LegalItems = legal; MaxCount = maxcount; @@ -88,16 +89,12 @@ public void RemoveAll() public void RemoveAll(Func deleteCriteria) { - if (deleteCriteria == null) - throw new ArgumentNullException(nameof(deleteCriteria)); foreach (var item in Items.Where(deleteCriteria)) item.Clear(); } public void RemoveAll(Func deleteCriteria) { - if (deleteCriteria == null) - throw new ArgumentNullException(nameof(deleteCriteria)); foreach (var item in Items.Where(deleteCriteria)) item.Clear(); } @@ -110,16 +107,12 @@ public void ModifyAllCount(int value) public void ModifyAllCount(int value, Func modifyCriteria) { - if (modifyCriteria == null) - throw new ArgumentNullException(nameof(modifyCriteria)); foreach (var item in Items.Where(z => z.Count != 0).Where(modifyCriteria)) item.Count = value; } public void ModifyAllCount(int value, Func modifyCriteria) { - if (modifyCriteria == null) - throw new ArgumentNullException(nameof(modifyCriteria)); foreach (var item in Items.Where(z => z.Count != 0).Where(modifyCriteria)) item.Count = value; } @@ -134,17 +127,12 @@ public void ModifyAllCount(SaveFile sav, int count = -1) public void ModifyAllCount(Func modification) { - if (modification == null) - throw new ArgumentNullException(nameof(modification)); foreach (var item in Items.Where(z => z.Count != 0)) item.Count = modification(item); } public void GiveAllItems(IReadOnlyList newItems, Func getSuggestedItemCount, int count = -1) { - if (getSuggestedItemCount == null) - throw new ArgumentNullException(nameof(getSuggestedItemCount)); - GiveAllItems(newItems, count); ModifyAllCount(getSuggestedItemCount); } diff --git a/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch7.cs b/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch7.cs index ae2534be3..86e361bf0 100644 --- a/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch7.cs +++ b/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch7.cs @@ -8,6 +8,7 @@ public sealed class InventoryPouch7 : InventoryPouch public InventoryPouch7(InventoryType type, ushort[] legal, int maxcount, int offset) : base(type, legal, maxcount, offset) { + OriginalItems = Array.Empty(); } public bool SetNew { get; set; } = false; diff --git a/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch7b.cs b/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch7b.cs index 66ad42901..7030c40de 100644 --- a/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch7b.cs +++ b/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch7b.cs @@ -14,7 +14,7 @@ public InventoryPouch7b(InventoryType type, ushort[] legal, int maxcount, int of } public bool SetNew { get; set; } - private InventoryItem[] OriginalItems; + private InventoryItem[] OriginalItems = Array.Empty(); public override void GetPouch(byte[] Data) { diff --git a/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch8.cs b/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch8.cs index d713e567c..551845d4f 100644 --- a/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch8.cs +++ b/PKHeX.Core/Saves/Substructures/Inventory/InventoryPouch8.cs @@ -14,7 +14,7 @@ public InventoryPouch8(InventoryType type, ushort[] legal, int maxcount, int off } public bool SetNew { get; set; } - private InventoryItem[] OriginalItems; + private InventoryItem[] OriginalItems = Array.Empty(); public override void GetPouch(byte[] Data) { diff --git a/PKHeX.Core/Saves/Substructures/Mail/Mail.cs b/PKHeX.Core/Saves/Substructures/Mail/Mail.cs index 869ab689e..44191ec3b 100644 --- a/PKHeX.Core/Saves/Substructures/Mail/Mail.cs +++ b/PKHeX.Core/Saves/Substructures/Mail/Mail.cs @@ -2,16 +2,23 @@ namespace PKHeX.Core { public abstract class Mail { - protected byte[] Data; - protected int DataOffset; + protected readonly byte[] Data; + protected readonly int DataOffset; + + protected Mail(byte[] data, int offset = 0) + { + Data = data; + DataOffset = offset; + } + public virtual void CopyTo(SaveFile sav) => sav.SetData(Data, DataOffset); public virtual void CopyTo(PK4 pk4) { } public virtual void CopyTo(PK5 pk5) { } - public virtual string GetMessage(bool isLastLine) => null; + public virtual string GetMessage(bool isLastLine) => string.Empty; public virtual ushort GetMessage(int index1, int index2) => 0; public virtual void SetMessage(string line1, string line2) { } public virtual void SetMessage(int index1, int index2, ushort value) { } - public virtual string AuthorName { get; set; } + public virtual string AuthorName { get; set; } = string.Empty; public virtual ushort AuthorTID { get; set; } public virtual ushort AuthorSID { get; set; } public virtual byte AuthorVersion { get; set; } diff --git a/PKHeX.Core/Saves/Substructures/Mail/Mail2.cs b/PKHeX.Core/Saves/Substructures/Mail/Mail2.cs index 044891d94..db0c1c615 100644 --- a/PKHeX.Core/Saves/Substructures/Mail/Mail2.cs +++ b/PKHeX.Core/Saves/Substructures/Mail/Mail2.cs @@ -6,11 +6,14 @@ public sealed class Mail2 : Mail { private readonly bool US; - public Mail2(SAV2 sav, int index) + public Mail2(SAV2 sav, int index) : base(sav.GetData(GetMailOffset(index), 0x2F), GetMailOffset(index)) { US = !sav.Japanese && !sav.Korean; - DataOffset = index < 6 ? (index * 0x2F) + 0x600 : ((index - 6) * 0x2F) + 0x835; - Data = sav.GetData(DataOffset, 0x2F); + } + + private static int GetMailOffset(int index) + { + return index < 6 ? (index * 0x2F) + 0x600 : ((index - 6) * 0x2F) + 0x835; } public override string GetMessage(bool isLastLine) => US ? StringConverter12.GetString1(Data, isLastLine ? 0x11 : 0, 0x10, false) : string.Empty; diff --git a/PKHeX.Core/Saves/Substructures/Mail/Mail3.cs b/PKHeX.Core/Saves/Substructures/Mail/Mail3.cs index 25ec5ba9b..cd7017ab1 100644 --- a/PKHeX.Core/Saves/Substructures/Mail/Mail3.cs +++ b/PKHeX.Core/Saves/Substructures/Mail/Mail3.cs @@ -5,49 +5,11 @@ namespace PKHeX.Core { public sealed class Mail3 : Mail { - private const int SIZE = 0x24; + public const int SIZE = 0x24; private readonly bool JP; - - public Mail3(SAV3 sav, int index) - { - JP = sav.Japanese; - GetMailBlockOffset(sav.Version, ref index, out int block, out int offset); - DataOffset = (index * SIZE) + sav.GetBlockOffset(block) + offset; - Data = sav.GetData(DataOffset, SIZE); - } - - private static void GetMailBlockOffset(GameVersion game, ref int index, out int block, out int offset) - { - block = 3; - if (game == GameVersion.E) - { - offset = 0xCE0; - } - else if (GameVersion.RS.Contains(game)) - { - offset = 0xC4C; - } - else // FRLG - { - if (index >= 12) - { - block = 4; - offset = 0; - index -= 12; - } - else - { - offset = 0xDD0; - } - } - } - - public Mail3() - { - Data = new byte[SIZE]; - DataOffset = -1; - ResetData(); - } + + public Mail3() : base(new byte[SIZE], -1) => ResetData(); + public Mail3(byte[] data, int ofs, bool japanese) : base(data, ofs) => JP = japanese; private void ResetData() { diff --git a/PKHeX.Core/Saves/Substructures/Mail/Mail4.cs b/PKHeX.Core/Saves/Substructures/Mail/Mail4.cs index f6479c225..2da2a53fb 100644 --- a/PKHeX.Core/Saves/Substructures/Mail/Mail4.cs +++ b/PKHeX.Core/Saves/Substructures/Mail/Mail4.cs @@ -4,29 +4,14 @@ namespace PKHeX.Core { public sealed class Mail4 : Mail { - private const int SIZE = 0x38; + public const int SIZE = 0x38; - public Mail4(SAV4 sav, int index) - { - switch (sav.Version) - { - case GameVersion.DP: DataOffset = (index * SIZE) + 0x4BEC; break; - case GameVersion.Pt: DataOffset = (index * SIZE) + 0x4E80; break; - case GameVersion.HGSS: DataOffset = (index * SIZE) + 0x3FA8; break; - } - Data = sav.General.Slice(DataOffset, SIZE); - } + public Mail4(byte[] data, int ofs) : base(data, ofs) { } - public Mail4(byte[] data) + public Mail4(byte[] data) : base(data, -1) { } + + public Mail4(byte? lang, byte? ver) : base(new byte[SIZE]) { - Data = data; - DataOffset = -1; - } - - public Mail4(byte? lang = null, byte? ver = null) - { - Data = new byte[SIZE]; - DataOffset = -1; if (lang != null) AuthorLanguage = (byte)lang; if (ver != null) AuthorVersion = (byte)ver; ResetData(); @@ -73,7 +58,12 @@ private void ResetData() } } - public override void SetBlank() => SetBlank(null, null); - public void SetBlank(byte? lang, byte? ver) => new Mail4(lang: lang, ver: ver).Data.CopyTo(Data, 0); + public override void SetBlank() => SetBlank(0, 0); + public void SetBlank(byte lang, byte ver) + { + Array.Clear(Data, 0, Data.Length); + AuthorLanguage = lang; + AuthorVersion = ver; + } } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/Substructures/Mail/Mail5.cs b/PKHeX.Core/Saves/Substructures/Mail/Mail5.cs index 337773ccc..27ffbab73 100644 --- a/PKHeX.Core/Saves/Substructures/Mail/Mail5.cs +++ b/PKHeX.Core/Saves/Substructures/Mail/Mail5.cs @@ -4,24 +4,12 @@ namespace PKHeX.Core { public sealed class Mail5 : Mail { - private const int SIZE = 0x38; + public const int SIZE = 0x38; - public Mail5(SAV5 sav, int index) - { - DataOffset = (index * SIZE) + 0x1DD00; - Data = sav.GetData(DataOffset, SIZE); - } + public Mail5(byte[] data, int ofs = -1) : base(data, ofs) { } - public Mail5(byte[] data) + public Mail5(byte? lang, byte? ver) : base(new byte[SIZE]) { - Data = data; - DataOffset = -1; - } - - public Mail5(byte? lang = null, byte? ver = null) - { - Data = new byte[SIZE]; - DataOffset = -1; if (lang != null) AuthorLanguage = (byte)lang; if (ver != null) AuthorVersion = (byte)ver; ResetData(); diff --git a/PKHeX.Core/Saves/Substructures/Misc/FestaFacility.cs b/PKHeX.Core/Saves/Substructures/Misc/FestaFacility.cs index b68fad709..730d6b24e 100644 --- a/PKHeX.Core/Saves/Substructures/Misc/FestaFacility.cs +++ b/PKHeX.Core/Saves/Substructures/Misc/FestaFacility.cs @@ -11,7 +11,7 @@ public sealed class FestaFacility public FestaFacility(SAV7 sav, int index) { - ofs = (index * SIZE) + sav.JoinFestaData + 0x310; + ofs = (index * SIZE) + sav.Festa.Offset + 0x310; Data = sav.GetData(ofs, SIZE); Language = sav.Language; } diff --git a/PKHeX.Core/Saves/Substructures/MysteryGiftAlbum.cs b/PKHeX.Core/Saves/Substructures/MysteryGiftAlbum.cs index 64711f035..a09923821 100644 --- a/PKHeX.Core/Saves/Substructures/MysteryGiftAlbum.cs +++ b/PKHeX.Core/Saves/Substructures/MysteryGiftAlbum.cs @@ -3,12 +3,12 @@ /// /// Structure containing the Mystery Gift Data /// - public sealed class MysteryGiftAlbum + public class MysteryGiftAlbum { /// /// Mystery Gift data received /// - public MysteryGift[] Gifts; + public readonly DataMysteryGift[] Gifts; /// /// Received Flag list @@ -16,11 +16,22 @@ public sealed class MysteryGiftAlbum /// /// this[index] == true iff index= has been received already. /// - public bool[] Flags; + public readonly bool[] Flags; + public MysteryGiftAlbum(DataMysteryGift[] gifts, bool[] flags) + { + Flags = flags; + Gifts = gifts; + } + } + + public class EncryptedMysteryGiftAlbum : MysteryGiftAlbum + { /// - /// Encryption Seed (only used in Generation 4 to encrypt the stored data) + /// Encryption Seed (only used in Generation 5 to encrypt the stored data) /// - public uint Seed; + public readonly uint Seed; + + public EncryptedMysteryGiftAlbum(DataMysteryGift[] gifts, bool[] flags, uint seed) : base(gifts, flags) => Seed = seed; } } diff --git a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan.cs b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan.cs index b00b8f8b5..ee4d14b59 100644 --- a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan.cs +++ b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan.cs @@ -6,7 +6,7 @@ namespace PKHeX.Core public abstract class Zukan { protected SaveFile SAV { get; set; } - protected int PokeDex { get; set; } + public int PokeDex { get; private set; } protected int PokeDexLanguageFlags { get; set; } protected Zukan(SaveFile sav, int dex, int langflag) @@ -25,8 +25,6 @@ protected Zukan(SaveFile sav, int dex, int langflag) protected abstract int DexLangIDCount { get; } protected abstract int GetDexLangFlag(int lang); - public Func DexFormIndexFetcher { get; protected set; } - protected abstract bool GetSaneFormsToIterate(int species, out int formStart, out int formEnd, int formIn); protected virtual void SetSpindaDexData(PKM pkm, bool alreadySeen) { } protected abstract void SetAllDexFlagsLanguage(int bit, int lang, bool value = true); diff --git a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan5.cs b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan5.cs index 9baa96935..6e088c13b 100644 --- a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan5.cs +++ b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan5.cs @@ -10,12 +10,18 @@ public sealed class Zukan5 : Zukan protected override int DexLangFlagByteCount => 7; protected override int DexLangIDCount => 7; - public Zukan5(SaveFile sav, int dex, int langflag) : base(sav, dex, langflag) + public Zukan5(SAV5B2W2 sav, int dex, int langflag) : base(sav, dex, langflag) { - var wrap = SAV is SAV5BW ? DexFormUtil.GetDexFormIndexBW : (Func)DexFormUtil.GetDexFormIndexB2W2; - DexFormIndexFetcher = (spec, form, _) => wrap(spec, form); + DexFormIndexFetcher = DexFormUtil.GetDexFormIndexB2W2; } + public Zukan5(SAV5BW sav, int dex, int langflag) : base(sav, dex, langflag) + { + DexFormIndexFetcher = DexFormUtil.GetDexFormIndexBW; + } + + public readonly Func DexFormIndexFetcher; + protected override int GetDexLangFlag(int lang) { lang--; @@ -106,7 +112,7 @@ private void SetFormFlags(PKM pkm) private void SetFormFlags(int species, int form, int shiny, bool value = true) { int fc = SAV.Personal[species].FormeCount; - int f = DexFormIndexFetcher(species, fc, SAV.MaxSpeciesID - 1); + int f = DexFormIndexFetcher(species, fc); if (f < 0) return; diff --git a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan6.cs b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan6.cs index c1e67f915..c8a912f10 100644 --- a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan6.cs +++ b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan6.cs @@ -12,7 +12,17 @@ public abstract class Zukan6 : Zukan protected override int DexLangIDCount => 7; protected int SpindaOffset { get; set; } - protected Zukan6(SaveFile sav, int dex, int langflag) : base(sav, dex, langflag) { } + protected Zukan6(SAV6XY sav, int dex, int langflag) : base(sav, dex, langflag) + { + DexFormIndexFetcher = DexFormUtil.GetDexFormIndexXY; + } + + private Func DexFormIndexFetcher { get; } + + protected Zukan6(SAV6AO sav, int dex, int langflag) : base(sav, dex, langflag) + { + DexFormIndexFetcher = DexFormUtil.GetDexFormIndexORAS; + } protected override int GetDexLangFlag(int lang) { @@ -91,7 +101,7 @@ private void SetFormFlags(PKM pkm) private void SetFormFlags(int species, int form, int shiny, bool value = true) { int fc = SAV.Personal[species].FormeCount; - int f = DexFormIndexFetcher(species, fc, SAV.MaxSpeciesID - 1); + int f = DexFormIndexFetcher(species, fc); if (f < 0) return; @@ -170,9 +180,8 @@ private bool[] GetBlankLanguageBits(bool value) public sealed class Zukan6AO : Zukan6 { - public Zukan6AO(SaveFile sav, int dex, int langflag) : base(sav, dex, langflag) + public Zukan6AO(SAV6AO sav, int dex, int langflag) : base(sav, dex, langflag) { - DexFormIndexFetcher = (spec, form, _) => DexFormUtil.GetDexFormIndexORAS(spec, form); SpindaOffset = 0x680; } @@ -199,9 +208,8 @@ public void SetEncounterCount(int index, ushort value) public sealed class Zukan6XY : Zukan6 { - public Zukan6XY(SaveFile sav, int dex, int langflag) : base(sav, dex, langflag) + public Zukan6XY(SAV6XY sav, int dex, int langflag) : base(sav, dex, langflag) { - DexFormIndexFetcher = (spec, form, _) => DexFormUtil.GetDexFormIndexXY(spec, form); SpindaOffset = 0x648; } diff --git a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7.cs b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7.cs index c76d1633e..88eba304a 100644 --- a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7.cs +++ b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7.cs @@ -19,16 +19,20 @@ public class Zukan7 : Zukan protected override int DexLangFlagByteCount => 920; // 0x398 = 817*9, top off the savedata block. protected override int DexLangIDCount => 9; // CHT, skipping langID 6 (unused) - private IList FormBaseSpecies; + private readonly IList FormBaseSpecies; - public Zukan7(SaveFile sav, int dex, int langflag) : base(sav, dex, langflag) + public Zukan7(SAV7SM sav, int dex, int langflag) : this(sav, dex, langflag, DexFormUtil.GetDexFormIndexSM) { } + public Zukan7(SAV7USUM sav, int dex, int langflag) : this(sav, dex, langflag, DexFormUtil.GetDexFormIndexUSUM) { } + protected Zukan7(SAV7b sav, int dex, int langflag) : this(sav, dex, langflag, DexFormUtil.GetDexFormIndexGG) { } + + private Zukan7(SaveFile sav, int dex, int langflag, Func form) : base(sav, dex, langflag) { - DexFormIndexFetcher = SAV is SAV7USUM ? (Func)DexFormUtil.GetDexFormIndexUSUM : DexFormUtil.GetDexFormIndexSM; - LoadDexList(); + DexFormIndexFetcher = form; + FormBaseSpecies = GetFormIndexBaseSpeciesList(); Debug.Assert(!SAV.Exportable || BitConverter.ToUInt32(SAV.Data, PokeDex) == MAGIC); } - protected void LoadDexList() => FormBaseSpecies = GetFormIndexBaseSpeciesList(); + public Func DexFormIndexFetcher { get; } protected override void SetAllDexSeenFlags(int baseBit, int altform, int gender, bool isShiny, bool value = true) { diff --git a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7b.cs b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7b.cs index 753aa35bb..a01629b1e 100644 --- a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7b.cs +++ b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan7b.cs @@ -19,10 +19,8 @@ public class Zukan7b : Zukan7 protected override int DexLangFlagByteCount => 920; // 0x398 = 817*9, top off the savedata block. protected override int DexLangIDCount => 9; // CHT, skipping langID 6 (unused) - public Zukan7b(SaveFile sav, int dex, int langflag) : base(sav, dex, langflag) + public Zukan7b(SAV7b sav, int dex, int langflag) : base(sav, dex, langflag) { - DexFormIndexFetcher = DexFormUtil.GetDexFormIndexGG; - LoadDexList(); } public override void SetDex(PKM pkm) diff --git a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan8.cs b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan8.cs index 4d993ec87..d3f7fdb61 100644 --- a/PKHeX.Core/Saves/Substructures/PokeDex/Zukan8.cs +++ b/PKHeX.Core/Saves/Substructures/PokeDex/Zukan8.cs @@ -19,16 +19,18 @@ public class Zukan8 : Zukan protected override int DexLangFlagByteCount => 920; // 0x398 = 817*9, top off the savedata block. protected override int DexLangIDCount => 9; // CHT, skipping langID 6 (unused) - private IList FormBaseSpecies; + private readonly IList FormBaseSpecies; - public Zukan8(SaveFile sav, int dex, int langflag) : base(sav, dex, langflag) + public Zukan8(SAV8SWSH sav, int dex, int langflag) : this(sav, dex, langflag, DexFormUtil.GetDexFormIndexSWSH) { } + + private Zukan8(SaveFile sav, int dex, int langflag, Func form) : base(sav, dex, langflag) { - DexFormIndexFetcher = DexFormUtil.GetDexFormIndexSWSH; - LoadDexList(); + DexFormIndexFetcher = form; + FormBaseSpecies = GetFormIndexBaseSpeciesList(); Debug.Assert(!SAV.Exportable || BitConverter.ToUInt32(SAV.Data, PokeDex) == MAGIC); } - protected void LoadDexList() => FormBaseSpecies = GetFormIndexBaseSpeciesList(); + public Func DexFormIndexFetcher { get; } protected override void SetAllDexSeenFlags(int baseBit, int altform, int gender, bool isShiny, bool value = true) { diff --git a/PKHeX.Core/Saves/Util/BoxUtil.cs b/PKHeX.Core/Saves/Util/BoxUtil.cs index f51ec8c5f..7858ca0cf 100644 --- a/PKHeX.Core/Saves/Util/BoxUtil.cs +++ b/PKHeX.Core/Saves/Util/BoxUtil.cs @@ -167,11 +167,16 @@ public static int LoadBoxes(this SaveFile SAV, IEnumerable pks, out string public static IEnumerable GetPKMsFromPaths(IEnumerable filepaths, int generation) { - return filepaths + var result = filepaths .Where(file => PKX.IsPKM(new FileInfo(file).Length)) .Select(File.ReadAllBytes) - .Select(data => PKMConverter.GetPKMfromBytes(data, prefer: generation)) - .Where(temp => temp != null); + .Select(data => PKMConverter.GetPKMfromBytes(data, prefer: generation)); + + foreach (var pkm in result) + { + if (pkm != null) + yield return pkm; + } } private static IEnumerable GetPossiblePKMsFromPaths(SaveFile sav, IEnumerable filepaths) diff --git a/PKHeX.Core/Saves/Util/SaveDetection.cs b/PKHeX.Core/Saves/Util/SaveDetection.cs index 66ee96d20..6c0d1f15c 100644 --- a/PKHeX.Core/Saves/Util/SaveDetection.cs +++ b/PKHeX.Core/Saves/Util/SaveDetection.cs @@ -77,7 +77,7 @@ public static IEnumerable GetSwitchBackupPaths(string root) /// If this function does not return a save file, this parameter will be set to the error message. /// Paths to check in addition to the default paths /// Reference to a valid save file, if any. - public static SaveFile DetectSaveFile(IReadOnlyList drives, ref string error, params string[] extra) + public static SaveFile? DetectSaveFile(IReadOnlyList drives, ref string error, params string[] extra) { var foldersToCheck = GetFoldersToCheck(drives, extra); var result = GetSaveFilePathsFromFolders(foldersToCheck, out var possiblePaths); @@ -114,10 +114,15 @@ public static IEnumerable GetSaveFiles(IReadOnlyList drives, b var paths = detect ? GetFoldersToCheck(drives, extra) : extra; var result = GetSaveFilePathsFromFolders(paths, out var possiblePaths); if (!result) - return Enumerable.Empty(); + yield break; var byMostRecent = possiblePaths.OrderByDescending(File.GetLastWriteTimeUtc); - return byMostRecent.Select(SaveUtil.GetVariantSAV); + foreach (var s in byMostRecent) + { + var sav = SaveUtil.GetVariantSAV(s); + if (sav != null) + yield return sav; + } } public static IEnumerable GetFoldersToCheck(IReadOnlyList drives, IEnumerable extra) @@ -142,9 +147,11 @@ private static bool GetSaveFilePathsFromFolders(IEnumerable foldersToChe { if (!SaveUtil.GetSavesFromFolder(folder, true, out IEnumerable files)) { - if (files == null) + if (!(files is string[] msg)) // should always return string[] continue; - possible = files; + if (msg.Length == 0) // folder doesn't exist + continue; + possible = msg; return false; } if (files != null) diff --git a/PKHeX.Core/Saves/Util/SaveExtensions.cs b/PKHeX.Core/Saves/Util/SaveExtensions.cs index 386fe013a..b9e17bd7b 100644 --- a/PKHeX.Core/Saves/Util/SaveExtensions.cs +++ b/PKHeX.Core/Saves/Util/SaveExtensions.cs @@ -183,7 +183,7 @@ public static IEnumerable GetCompatible(this SaveFile sav, IEnumerable /// SaveFile to receive the compatible /// Current Pokémon being edited /// Current Pokémon, assuming conversion is possible. If conversion is not possible, a blank will be obtained from the . - public static PKM GetCompatiblePKM(this SaveFile sav, PKM pk = null) + public static PKM GetCompatiblePKM(this SaveFile sav, PKM? pk = null) { if (pk == null) return sav.BlankPKM; @@ -198,26 +198,35 @@ public static PKM GetCompatiblePKM(this SaveFile sav, PKM pk = null) return PKMConverter.ConvertToType(pk, sav.PKMType, out _) ?? sav.BlankPKM; } + /// + /// Gets a blank file for the save file. If the template path exists, a template load will be attempted. + /// + /// Save File to fetch a template for + /// Template if it exists, or a blank from the + public static PKM LoadTemplate(this SaveFile sav) => sav.BlankPKM; + /// /// Gets a blank file for the save file. If the template path exists, a template load will be attempted. /// /// Save File to fetch a template for /// Path to look for a template in /// Template if it exists, or a blank from the - public static PKM LoadTemplate(this SaveFile sav, string templatePath = null) + public static PKM LoadTemplate(this SaveFile sav, string templatePath) { - var blank = sav.BlankPKM; if (!Directory.Exists(templatePath)) - return blank; + return LoadTemplate(sav); var di = new DirectoryInfo(templatePath); - string path = Path.Combine(templatePath, $"{di.Name}.{blank.Extension}"); + string path = Path.Combine(templatePath, $"{di.Name}.{sav.PKMType.Name.ToLower()}"); if (!File.Exists(path) || !PKX.IsPKM(new FileInfo(path).Length)) - return blank; + return LoadTemplate(sav); - var pk = PKMConverter.GetPKMfromBytes(File.ReadAllBytes(path), prefer: blank.Format); - return PKMConverter.ConvertToType(pk, sav.BlankPKM.GetType(), out _) ?? blank; + var pk = PKMConverter.GetPKMfromBytes(File.ReadAllBytes(path), prefer: sav.Generation); + if (pk == null) + return LoadTemplate(sav); + + return PKMConverter.ConvertToType(pk, sav.BlankPKM.GetType(), out _) ?? LoadTemplate(sav); } } } diff --git a/PKHeX.Core/Saves/Util/SaveUtil.cs b/PKHeX.Core/Saves/Util/SaveUtil.cs index 9f6937185..fe008730d 100644 --- a/PKHeX.Core/Saves/Util/SaveUtil.cs +++ b/PKHeX.Core/Saves/Util/SaveUtil.cs @@ -5,6 +5,7 @@ using System.Text; using static PKHeX.Core.MessageStrings; +using static PKHeX.Core.GameVersion; namespace PKHeX.Core { @@ -82,44 +83,44 @@ public static class SaveUtil private static GameVersion GetSAVType(byte[] data) { GameVersion ver; - if ((ver = GetIsG1SAV(data)) != GameVersion.Invalid) + if ((ver = GetIsG1SAV(data)) != Invalid) return ver; - if ((ver = GetIsG2SAV(data)) != GameVersion.Invalid) + if ((ver = GetIsG2SAV(data)) != Invalid) return ver; - if ((ver = GetIsG3SAV(data)) != GameVersion.Invalid) + if ((ver = GetIsG3SAV(data)) != Invalid) return ver; - if ((ver = GetIsG4SAV(data)) != GameVersion.Invalid) + if ((ver = GetIsG4SAV(data)) != Invalid) return ver; - if ((ver = GetIsG5SAV(data)) != GameVersion.Invalid) + if ((ver = GetIsG5SAV(data)) != Invalid) return ver; - if ((ver = GetIsG6SAV(data)) != GameVersion.Invalid) + if ((ver = GetIsG6SAV(data)) != Invalid) return ver; - if ((ver = GetIsG7SAV(data)) != GameVersion.Invalid) + if ((ver = GetIsG7SAV(data)) != Invalid) return ver; - if ((ver = GetIsG8SAV(data)) != GameVersion.Invalid) + if ((ver = GetIsG8SAV(data)) != Invalid) return ver; - if (GetIsBelugaSAV(data) != GameVersion.Invalid) - return GameVersion.GG; - if (GetIsG3COLOSAV(data) != GameVersion.Invalid) - return GameVersion.COLO; - if (GetIsG3XDSAV(data) != GameVersion.Invalid) - return GameVersion.XD; - if (GetIsG3BOXSAV(data) != GameVersion.Invalid) - return GameVersion.RSBOX; - if (GetIsG4BRSAV(data) != GameVersion.Invalid) - return GameVersion.BATREV; + if (GetIsBelugaSAV(data) != Invalid) + return GG; + if (GetIsG3COLOSAV(data) != Invalid) + return COLO; + if (GetIsG3XDSAV(data) != Invalid) + return XD; + if (GetIsG3BOXSAV(data) != Invalid) + return RSBOX; + if (GetIsG4BRSAV(data) != Invalid) + return BATREV; if (GetIsBank7(data)) // pokebank - return GameVersion.Gen7; + return Gen7; if (GetIsBank4(data)) // pokestock - return GameVersion.Gen4; + return Gen4; if (GetIsBank3(data)) // pokestock - return GameVersion.Gen3; + return Gen3; if (GetIsRanch4(data)) // ranch - return GameVersion.DPPt; + return DPPt; - return GameVersion.Invalid; + return Invalid; } /// @@ -141,14 +142,14 @@ private static bool IsG12ListValid(byte[] data, int offset, int listCount) internal static GameVersion GetIsG1SAV(byte[] data) { if (data.Length != SIZE_G1RAW && data.Length != SIZE_G1BAT) - return GameVersion.Invalid; + return Invalid; // Check if it's not an american save or a japanese save if (!(GetIsG1SAVU(data) || GetIsG1SAVJ(data))) - return GameVersion.Invalid; + return Invalid; // I can't actually detect which game version, because it's not stored anywhere. // If you can think of anything to do here, please implement :) - return GameVersion.RBY; + return RBY; } /// Checks to see if the data belongs to an International Gen1 save @@ -173,17 +174,17 @@ internal static bool GetIsG1SAVJ(byte[] data) internal static GameVersion GetIsG2SAV(byte[] data) { if (!SIZES_2.Contains(data.Length)) - return GameVersion.Invalid; + return Invalid; // Check if it's not an International, Japanese, or Korean save file GameVersion result; - if ((result = GetIsG2SAVU(data)) != GameVersion.Invalid) + if ((result = GetIsG2SAVU(data)) != Invalid) return result; - if ((result = GetIsG2SAVJ(data)) != GameVersion.Invalid) + if ((result = GetIsG2SAVJ(data)) != Invalid) return result; - if ((result = GetIsG2SAVK(data)) != GameVersion.Invalid) + if ((result = GetIsG2SAVK(data)) != Invalid) return result; - return GameVersion.Invalid; + return Invalid; } /// Checks to see if the data belongs to an International (not Japanese or Korean) Gen2 save @@ -192,10 +193,10 @@ internal static GameVersion GetIsG2SAV(byte[] data) private static GameVersion GetIsG2SAVU(byte[] data) { if (IsG12ListValid(data, 0x288A, 20) && IsG12ListValid(data, 0x2D6C, 20)) - return GameVersion.GS; + return GS; if (IsG12ListValid(data, 0x2865, 20) && IsG12ListValid(data, 0x2D10, 20)) - return GameVersion.C; - return GameVersion.Invalid; + return C; + return Invalid; } /// Checks to see if the data belongs to a Japanese Gen2 save @@ -204,12 +205,12 @@ private static GameVersion GetIsG2SAVU(byte[] data) internal static GameVersion GetIsG2SAVJ(byte[] data) { if (!IsG12ListValid(data, 0x2D10, 30)) - return GameVersion.Invalid; + return Invalid; if (IsG12ListValid(data, 0x283E, 30)) - return GameVersion.GS; + return GS; if (IsG12ListValid(data, 0x281A, 30)) - return GameVersion.C; - return GameVersion.Invalid; + return C; + return Invalid; } /// Checks to see if the data belongs to a Korean Gen2 save @@ -218,8 +219,8 @@ internal static GameVersion GetIsG2SAVJ(byte[] data) internal static GameVersion GetIsG2SAVK(byte[] data) { if (IsG12ListValid(data, 0x2DAE, 20) && IsG12ListValid(data, 0x28CC, 20)) - return GameVersion.GS; - return GameVersion.Invalid; + return GS; + return Invalid; } /// Checks to see if the data belongs to a Gen3 save @@ -228,7 +229,7 @@ internal static GameVersion GetIsG2SAVK(byte[] data) internal static GameVersion GetIsG3SAV(byte[] data) { if (data.Length != SIZE_G3RAW && data.Length != SIZE_G3RAWHALF) - return GameVersion.Invalid; + return Invalid; // check the save file(s) int count = data.Length/SIZE_G3RAWHALF; @@ -255,7 +256,7 @@ internal static GameVersion GetIsG3SAV(byte[] data) // Detect RS/E/FRLG return SAV3.GetVersion(data, (blocksize * Block0) + ofs); } - return GameVersion.Invalid; + return Invalid; } /// Checks to see if the data belongs to a Gen3 Box RS save @@ -264,7 +265,7 @@ internal static GameVersion GetIsG3SAV(byte[] data) internal static GameVersion GetIsG3BOXSAV(byte[] data) { if (data.Length != SIZE_G3BOX && data.Length != SIZE_G3BOXGCI) - return GameVersion.Invalid; + return Invalid; byte[] sav = data; @@ -280,7 +281,7 @@ internal static GameVersion GetIsG3BOXSAV(byte[] data) ushort CHK_A = BigEndian.ToUInt16(sav, ofs + 0); ushort CHK_B = BigEndian.ToUInt16(sav, ofs + 2); - return CHK_A == chkA && CHK_B == chkB ? GameVersion.RSBOX : GameVersion.Invalid; + return CHK_A == chkA && CHK_B == chkB ? RSBOX : Invalid; } /// Checks to see if the data belongs to a Colosseum save @@ -289,7 +290,7 @@ internal static GameVersion GetIsG3BOXSAV(byte[] data) internal static GameVersion GetIsG3COLOSAV(byte[] data) { if (data.Length != SIZE_G3COLO && data.Length != SIZE_G3COLOGCI) - return GameVersion.Invalid; + return Invalid; // Check the intro bytes for each save slot int offset = data.Length - SIZE_G3COLO; @@ -297,9 +298,9 @@ internal static GameVersion GetIsG3COLOSAV(byte[] data) { var ofs = 0x6000 + offset + (0x1E000 * i); if (BitConverter.ToUInt32(data, ofs) != 0x00000101) - return GameVersion.Invalid; + return Invalid; } - return GameVersion.COLO; + return COLO; } /// Checks to see if the data belongs to a Gen3 XD save @@ -308,7 +309,7 @@ internal static GameVersion GetIsG3COLOSAV(byte[] data) internal static GameVersion GetIsG3XDSAV(byte[] data) { if (data.Length != SIZE_G3XD && data.Length != SIZE_G3XDGCI) - return GameVersion.Invalid; + return Invalid; // Check the intro bytes for each save slot int offset = data.Length - SIZE_G3XD; @@ -316,9 +317,9 @@ internal static GameVersion GetIsG3XDSAV(byte[] data) { var ofs = 0x6000 + offset + (0x28000 * i); if ((BitConverter.ToUInt32(data, ofs) & 0xFFFE_FFFF) != 0x00000101) - return GameVersion.Invalid; + return Invalid; } - return GameVersion.XD; + return XD; } /// Checks to see if the data belongs to a Gen4 save @@ -327,7 +328,7 @@ internal static GameVersion GetIsG3XDSAV(byte[] data) internal static GameVersion GetIsG4SAV(byte[] data) { if (data.Length != SIZE_G4RAW) - return GameVersion.Invalid; + return Invalid; // The block footers contain a u32 'size' followed by a u32 binary-coded-decimal timestamp(?) // Korean savegames have a different timestamp from other localizations. @@ -346,13 +347,13 @@ bool validSequence(int offset) // Check the other save -- first save is done to the latter half of the binary. // The second save should be all that is needed to check. if (validSequence(0x4C100)) - return GameVersion.DP; + return DP; if (validSequence(0x4CF2C)) - return GameVersion.Pt; + return Pt; if (validSequence(0x4F628)) - return GameVersion.HGSS; + return HGSS; - return GameVersion.Invalid; + return Invalid; } /// Checks to see if the data belongs to a Gen4 Battle Revolution save @@ -361,10 +362,10 @@ bool validSequence(int offset) internal static GameVersion GetIsG4BRSAV(byte[] data) { if (data.Length != SIZE_G4BR) - return GameVersion.Invalid; + return Invalid; byte[] sav = SAV4BR.DecryptPBRSaveData(data); - return SAV4BR.IsChecksumsValid(sav) ? GameVersion.BATREV : GameVersion.Invalid; + return SAV4BR.IsChecksumsValid(sav) ? BATREV : Invalid; } /// Checks to see if the data belongs to a Gen5 save @@ -373,18 +374,18 @@ internal static GameVersion GetIsG4BRSAV(byte[] data) internal static GameVersion GetIsG5SAV(byte[] data) { if (data.Length != SIZE_G5RAW) - return GameVersion.Invalid; + return Invalid; // check the checksum block validity; nobody would normally modify this region ushort chk1 = BitConverter.ToUInt16(data, SIZE_G5BW - 0x100 + 0x8C + 0xE); ushort actual1 = Checksums.CRC16_CCITT(data, SIZE_G5BW - 0x100, 0x8C); if (chk1 == actual1) - return GameVersion.BW; + return BW; ushort chk2 = BitConverter.ToUInt16(data, SIZE_G5B2W2 - 0x100 + 0x94 + 0xE); ushort actual2 = Checksums.CRC16_CCITT(data, SIZE_G5B2W2 - 0x100, 0x94); if (chk2 == actual2) - return GameVersion.B2W2; - return GameVersion.Invalid; + return B2W2; + return Invalid; } /// Checks to see if the data belongs to a Gen6 save @@ -393,16 +394,16 @@ internal static GameVersion GetIsG5SAV(byte[] data) private static GameVersion GetIsG6SAV(byte[] data) { if (data.Length != SIZE_G6XY && data.Length != SIZE_G6ORAS && data.Length != SIZE_G6ORASDEMO) - return GameVersion.Invalid; + return Invalid; if (BitConverter.ToUInt32(data, data.Length - 0x1F0) != BEEF) - return GameVersion.Invalid; + return Invalid; if (data.Length == SIZE_G6XY) - return GameVersion.XY; + return XY; if (data.Length == SIZE_G6ORAS) - return GameVersion.ORAS; - return GameVersion.ORASDEMO; // least likely + return ORAS; + return ORASDEMO; // least likely } /// Checks to see if the data belongs to a Gen7 save @@ -411,12 +412,12 @@ private static GameVersion GetIsG6SAV(byte[] data) private static GameVersion GetIsG7SAV(byte[] data) { if (data.Length != SIZE_G7SM && data.Length != SIZE_G7USUM) - return GameVersion.Invalid; + return Invalid; if (BitConverter.ToUInt32(data, data.Length - 0x1F0) != BEEF) - return GameVersion.Invalid; + return Invalid; - return data.Length == SIZE_G7SM ? GameVersion.SM : GameVersion.USUM; + return data.Length == SIZE_G7SM ? SM : USUM; } /// Determines if the input data belongs to a save @@ -425,15 +426,15 @@ private static GameVersion GetIsG7SAV(byte[] data) private static GameVersion GetIsBelugaSAV(byte[] data) { if (data.Length != SIZE_G7GG) - return GameVersion.Invalid; + return Invalid; const int actualLength = 0xB8800; if (BitConverter.ToUInt32(data, actualLength - 0x1F0) != BEEF) // beef table start - return GameVersion.Invalid; + return Invalid; if (BitConverter.ToUInt16(data, actualLength - 0x200 + 0xB0) != 0x13) // check a block number to double check - return GameVersion.Invalid; + return Invalid; - return GameVersion.GG; + return GG; } /// Checks to see if the data belongs to a Gen7 save @@ -442,12 +443,12 @@ private static GameVersion GetIsBelugaSAV(byte[] data) private static GameVersion GetIsG8SAV(byte[] data) { if (data.Length != SIZE_G8SWSH) - return GameVersion.Invalid; + return Invalid; if (BitConverter.ToUInt32(data, data.Length - 0x1F0) != BEEF) - return GameVersion.Invalid; + return Invalid; - return GameVersion.SWSH; + return SWSH; } private static bool GetIsBank7(byte[] data) => data.Length == SIZE_G7BANK && data[0] != 0; @@ -458,7 +459,7 @@ private static GameVersion GetIsG8SAV(byte[] data) /// Creates an instance of a SaveFile using the given save data. /// File location from which to create a SaveFile. /// An appropriate type of save file for the given data, or null if the save data is invalid. - public static SaveFile GetVariantSAV(string path) + public static SaveFile? GetVariantSAV(string path) { var data = File.ReadAllBytes(path); var sav = GetVariantSAV(data); @@ -469,7 +470,7 @@ public static SaveFile GetVariantSAV(string path) /// Creates an instance of a SaveFile using the given save data. /// Save data from which to create a SaveFile. /// An appropriate type of save file for the given data, or null if the save data is invalid. - public static SaveFile GetVariantSAV(byte[] data) + public static SaveFile? GetVariantSAV(byte[] data) { // Pre-check for header/footer signatures CheckHeaderFooter(ref data, out var header, out var footer); @@ -481,58 +482,50 @@ public static SaveFile GetVariantSAV(byte[] data) return sav; } - private static SaveFile GetVariantSAVInternal(byte[] data) + private static SaveFile? GetVariantSAVInternal(byte[] data) { switch (GetSAVType(data)) { // Main Games - case GameVersion.RBY: return new SAV1(data); + case RBY: return new SAV1(data); + case GS: case C: return new SAV2(data); + case RS: case E: case FRLG: return new SAV3(data); - case GameVersion.GS: - case GameVersion.C: return new SAV2(data); + case DP: return new SAV4DP(data); + case Pt: return new SAV4Pt(data); + case HGSS: return new SAV4HGSS(data); - case GameVersion.RS: - case GameVersion.E: - case GameVersion.FRLG: return new SAV3(data); + case BW: return new SAV5BW(data); + case B2W2: return new SAV5B2W2(data); - case GameVersion.DP: return new SAV4DP(data); - case GameVersion.Pt: return new SAV4Pt(data); - case GameVersion.HGSS: return new SAV4HGSS(data); + case XY: return new SAV6XY(data); + case ORAS: return new SAV6AO(data); + case ORASDEMO: return new SAV6AODemo(data); - case GameVersion.BW: return new SAV5BW(data); - case GameVersion.B2W2: return new SAV5B2W2(data); + case SM: return new SAV7SM(data); + case USUM: return new SAV7USUM(data); + case GG: return new SAV7b(data); - case GameVersion.XY: return new SAV6XY(data); - case GameVersion.ORAS: return new SAV6AO(data); - case GameVersion.ORASDEMO: return new SAV6AODemo(data); - - case GameVersion.SM: - return new SAV7SM(data); - case GameVersion.USUM: - return new SAV7USUM(data); - - case GameVersion.SWSH: - return new SAV8SWSH(data); + case SWSH: return new SAV8SWSH(data); // Side Games - case GameVersion.COLO: return new SAV3Colosseum(data); - case GameVersion.XD: return new SAV3XD(data); - case GameVersion.RSBOX: return new SAV3RSBox(data); - case GameVersion.BATREV: return new SAV4BR(data); - case GameVersion.GG: return new SAV7b(data); + case COLO: return new SAV3Colosseum(data); + case XD: return new SAV3XD(data); + case RSBOX: return new SAV3RSBox(data); + case BATREV: return new SAV4BR(data); // Bulk Storage - case GameVersion.Gen3: return new Bank3(data); - case GameVersion.DPPt: return new SAV4Ranch(data); - case GameVersion.Gen4: return new Bank4(data); - case GameVersion.Gen7: return Bank7.GetBank7(data); + case Gen3: return new Bank3(data); + case DPPt: return new SAV4Ranch(data); + case Gen4: return new Bank4(data); + case Gen7: return Bank7.GetBank7(data); // No pattern matched default: return null; } } - public static SaveFile GetVariantSAV(SAV3GCMemoryCard MC) + public static SaveFile? GetVariantSAV(SAV3GCMemoryCard MC) { // Pre-check for header/footer signatures SaveFile sav; @@ -542,9 +535,9 @@ public static SaveFile GetVariantSAV(SAV3GCMemoryCard MC) switch (MC.SelectedGameVersion) { // Side Games - case GameVersion.COLO: sav = new SAV3Colosseum(data, MC); break; - case GameVersion.XD: sav = new SAV3XD(data, MC); break; - case GameVersion.RSBOX: sav = new SAV3RSBox(data, MC); break; + case COLO: sav = new SAV3Colosseum(data, MC); break; + case XD: sav = new SAV3XD(data, MC); break; + case RSBOX: sav = new SAV3RSBox(data, MC); break; // No pattern matched default: return null; @@ -563,9 +556,6 @@ public static SaveFile GetVariantSAV(SAV3GCMemoryCard MC) public static SaveFile GetBlankSAV(GameVersion Game, string OT) { var SAV = GetBlankSAV(Game); - if (SAV == null) - return null; - SAV.Game = (int)Game; SAV.OT = OT; @@ -589,65 +579,65 @@ private static SaveFile GetBlankSAV(GameVersion Game) { switch (Game) { - case GameVersion.RD: case GameVersion.BU: case GameVersion.GN: case GameVersion.YW: - case GameVersion.RBY: + case RD: case BU: case GN: case YW: + case RBY: return new SAV1(version: Game); - case GameVersion.GS: case GameVersion.GD: case GameVersion.SV: - return new SAV2(version: GameVersion.GS); - case GameVersion.GSC: case GameVersion.C: - return new SAV2(version: GameVersion.C); + case GS: case GD: case SV: + return new SAV2(version: GS); + case GSC: case C: + return new SAV2(version: C); - case GameVersion.R: case GameVersion.S: case GameVersion.E: case GameVersion.FR: case GameVersion.LG: + case R: case S: case E: case FR: case LG: return new SAV3(version: Game); - case GameVersion.FRLG: - return new SAV3(version: GameVersion.FR); - case GameVersion.RS: - return new SAV3(version: GameVersion.R); - case GameVersion.RSE: - return new SAV3(version: GameVersion.E); + case FRLG: + return new SAV3(version: FR); + case RS: + return new SAV3(version: R); + case RSE: + return new SAV3(version: E); - case GameVersion.CXD: - case GameVersion.COLO: + case CXD: + case COLO: return new SAV3Colosseum(); - case GameVersion.XD: + case XD: return new SAV3XD(); - case GameVersion.RSBOX: + case RSBOX: return new SAV3RSBox(); - case GameVersion.D: case GameVersion.P: case GameVersion.DP: - case GameVersion.DPPt: + case D: case P: case DP: + case DPPt: return new SAV4DP(); - case GameVersion.Pt: + case Pt: return new SAV4Pt(); - case GameVersion.HG: case GameVersion.SS: case GameVersion.HGSS: + case HG: case SS: case HGSS: return new SAV4HGSS(); - case GameVersion.B: case GameVersion.W: case GameVersion.BW: + case B: case W: case BW: return new SAV5BW(); - case GameVersion.B2: case GameVersion.W2: case GameVersion.B2W2: + case B2: case W2: case B2W2: return new SAV5B2W2(); - case GameVersion.X: case GameVersion.Y: case GameVersion.XY: + case X: case Y: case XY: return new SAV6XY(); - case GameVersion.ORASDEMO: + case ORASDEMO: return new SAV6AODemo(); - case GameVersion.OR: case GameVersion.AS: case GameVersion.ORAS: + case OR: case AS: case ORAS: return new SAV6AO(); - case GameVersion.SN: case GameVersion.MN: case GameVersion.SM: + case SN: case MN: case SM: return new SAV7SM(); - case GameVersion.US: case GameVersion.UM: case GameVersion.USUM: + case US: case UM: case USUM: return new SAV7USUM(); - case GameVersion.GO: - case GameVersion.GP: case GameVersion.GE: case GameVersion.GG: + case GO: + case GP: case GE: case GG: return new SAV7b(); - case GameVersion.SW: case GameVersion.SH: case GameVersion.SWSH: + case SW: case SH: case SWSH: return new SAV8SWSH(); default: - return null; + throw new ArgumentException(nameof(Game)); } } @@ -674,7 +664,7 @@ public static bool GetSavesFromFolder(string folderPath, bool deep, out IEnumera { if (!Directory.Exists(folderPath)) { - result = null; + result = Enumerable.Empty(); return false; } try @@ -766,21 +756,17 @@ private static void CheckHeaderFooter(ref byte[] input, out byte[] header, out b /// New object. public static SAV3 GetG3SaveOverride(SaveFile sav, GameVersion ver) { - switch (ver) // Reset save file info + return ver switch // Reset save file info { - case GameVersion.R: - case GameVersion.S: - case GameVersion.RS: - return new SAV3(sav.BAK, GameVersion.RS); - case GameVersion.E: - return new SAV3(sav.BAK, GameVersion.E); - case GameVersion.FRLG: - case GameVersion.FR: - case GameVersion.LG: - return new SAV3(sav.BAK, GameVersion.FRLG); - default: - return null; - } + R => new SAV3(sav.BAK, RS), + S => new SAV3(sav.BAK, RS), + RS => new SAV3(sav.BAK, RS), + E => new SAV3(sav.BAK, E), + FRLG => new SAV3(sav.BAK, FRLG), + FR => new SAV3(sav.BAK, FRLG), + LG => new SAV3(sav.BAK, FRLG), + _ => throw new ArgumentException(nameof(ver)) + }; } /// @@ -790,22 +776,17 @@ public static SAV3 GetG3SaveOverride(SaveFile sav, GameVersion ver) /// Reference to the . public static PersonalTable GetG3Personal(GameVersion ver) { - switch (ver) + return ver switch { - case GameVersion.FRLG: - case GameVersion.FR: - return PersonalTable.FR; - case GameVersion.LG: - return PersonalTable.LG; - case GameVersion.E: - return PersonalTable.E; - case GameVersion.R: - case GameVersion.S: - case GameVersion.RS: - return PersonalTable.RS; - default: - return null; - } + RS => PersonalTable.RS, + E => PersonalTable.E, + FRLG => PersonalTable.FR, + FR => PersonalTable.FR, + LG => PersonalTable.LG, + R => PersonalTable.RS, + S => PersonalTable.RS, + _ => throw new ArgumentException(nameof(ver)) + }; } } } diff --git a/PKHeX.Core/Util/DataUtil.cs b/PKHeX.Core/Util/DataUtil.cs index f18f9c77f..3eb0c975d 100644 --- a/PKHeX.Core/Util/DataUtil.cs +++ b/PKHeX.Core/Util/DataUtil.cs @@ -160,7 +160,7 @@ public static byte[] GetBinaryResource(string name) return buffer; } - public static string GetStringResource(string name) + public static string? GetStringResource(string name) { if (!resourceNameMap.TryGetValue(name, out var resname)) { @@ -172,6 +172,8 @@ public static string GetStringResource(string name) } using var resource = thisAssembly.GetManifestResourceStream(resname); + if (resource == null) + return null; using var reader = new StreamReader(resource); return reader.ReadToEnd(); } @@ -192,16 +194,20 @@ private static IEnumerable DumpStrings(Type t) return props.Select(p => $"{p}{TranslationSplitter}{ReflectUtil.GetValue(t, p)}"); } + /// + /// Gets the current localization in a static class containing language-specific strings + /// + /// + public static string[] GetLocalization(Type t) => DumpStrings(t).ToArray(); + /// /// Gets the current localization in a static class containing language-specific strings /// /// /// Existing localization lines (if provided) - public static string[] GetLocalization(Type t, string[] existingLines = null) + public static string[] GetLocalization(Type t, string[] existingLines) { - var currentLines = DumpStrings(t).ToArray(); - if (existingLines == null) - return currentLines; + var currentLines = GetLocalization(t); var existing = GetProperties(existingLines); var current = GetProperties(currentLines); diff --git a/PKHeX.Core/Util/FileUtil.cs b/PKHeX.Core/Util/FileUtil.cs index 6f2f193ab..69aaf934c 100644 --- a/PKHeX.Core/Util/FileUtil.cs +++ b/PKHeX.Core/Util/FileUtil.cs @@ -17,7 +17,7 @@ public static class FileUtil /// /// Reference savefile used for PC Binary compatibility checks. /// Supported file object reference, null if none found. - public static object GetSupportedFile(string path, SaveFile reference = null) + public static object? GetSupportedFile(string path, SaveFile? reference = null) { try { @@ -44,7 +44,7 @@ public static object GetSupportedFile(string path, SaveFile reference = null) /// File extension used as a hint. /// Reference savefile used for PC Binary compatibility checks. /// Supported file object reference, null if none found. - public static object GetSupportedFile(byte[] data, string ext, SaveFile reference = null) + public static object? GetSupportedFile(byte[] data, string ext, SaveFile? reference = null) { if (TryGetSAV(data, out var sav)) return sav; @@ -54,16 +54,16 @@ public static object GetSupportedFile(byte[] data, string ext, SaveFile referenc return pk; if (TryGetPCBoxBin(data, out IEnumerable pks, reference)) return pks; - if (TryGetBattleVideo(data, out BattleVideo bv)) + if (TryGetBattleVideo(data, out var bv)) return bv; - if (TryGetMysteryGift(data, out MysteryGift g, ext)) + if (TryGetMysteryGift(data, out var g, ext)) return g; - if (TryGetGP1(data, out GP1 gp)) + if (TryGetGP1(data, out var gp)) return gp; return null; } - private static bool TryGetGP1(byte[] data, out GP1 gp1) + private static bool TryGetGP1(byte[] data, out GP1? gp1) { gp1 = null; if (data.Length != GP1.SIZE || BitConverter.ToUInt32(data, 0x28) == 0) @@ -99,7 +99,7 @@ public static bool IsFileTooBig(long length) /// Binary data /// Output result /// True if file object reference is valid, false if none found. - public static bool TryGetSAV(byte[] data, out SaveFile sav) + public static bool TryGetSAV(byte[] data, out SaveFile? sav) { sav = SaveUtil.GetVariantSAV(data); return sav != null; @@ -111,7 +111,7 @@ public static bool TryGetSAV(byte[] data, out SaveFile sav) /// Binary data /// Output result /// True if file object reference is valid, false if none found. - public static bool TryGetMemoryCard(byte[] data, out SAV3GCMemoryCard memcard) + public static bool TryGetMemoryCard(byte[] data, out SAV3GCMemoryCard? memcard) { if (!SAV3GCMemoryCard.IsMemoryCardSize(data)) { @@ -130,11 +130,11 @@ public static bool TryGetMemoryCard(byte[] data, out SAV3GCMemoryCard memcard) /// Format hint /// Reference savefile used for PC Binary compatibility checks. /// True if file object reference is valid, false if none found. - public static bool TryGetPKM(byte[] data, out PKM pk, string ext, ITrainerInfo sav = null) + public static bool TryGetPKM(byte[] data, out PKM? pk, string ext, ITrainerInfo? sav = null) { if (ext == ".pgt") // size collision with pk6 { - pk = default; + pk = null; return false; } var format = PKX.GetPKMFormatFromExtension(ext, sav?.Generation ?? 6); @@ -147,17 +147,17 @@ public static bool TryGetPKM(byte[] data, out PKM pk, string ext, ITrainerInfo s /// /// Binary data /// Output result - /// Reference savefile used for PC Binary compatibility checks. + /// Reference savefile used for PC Binary compatibility checks. /// True if file object reference is valid, false if none found. - public static bool TryGetPCBoxBin(byte[] data, out IEnumerable pkms, SaveFile SAV) + public static bool TryGetPCBoxBin(byte[] data, out IEnumerable pkms, SaveFile? sav) { - if (SAV == null) + if (sav == null) { pkms = Enumerable.Empty(); return false; } var length = data.Length; - if (PKX.IsPKM(length / SAV.SlotCount) || PKX.IsPKM(length / SAV.BoxSlotCount)) + if (PKX.IsPKM(length / sav.SlotCount) || PKX.IsPKM(length / sav.BoxSlotCount)) { pkms = ArrayUtil.EnumerateSplit(data, length); return true; @@ -172,7 +172,7 @@ public static bool TryGetPCBoxBin(byte[] data, out IEnumerable pkms, Sav /// Binary data /// Output result /// True if file object reference is valid, false if none found. - public static bool TryGetBattleVideo(byte[] data, out BattleVideo bv) + public static bool TryGetBattleVideo(byte[] data, out BattleVideo? bv) { bv = BattleVideo.GetVariantBattleVideo(data); return bv != null; @@ -185,7 +185,7 @@ public static bool TryGetBattleVideo(byte[] data, out BattleVideo bv) /// Output result /// Format hint /// True if file object reference is valid, false if none found. - public static bool TryGetMysteryGift(byte[] data, out MysteryGift mg, string ext) + public static bool TryGetMysteryGift(byte[] data, out MysteryGift? mg, string ext) { mg = MysteryGift.GetMysteryGift(data, ext); return mg != null; @@ -211,13 +211,13 @@ public static string GetPKMTempFileName(PKM pk, bool encrypt) /// or file path. /// Generation Info /// New reference from the file. - public static PKM GetSingleFromPath(string file, ITrainerInfo SAV) + public static PKM? GetSingleFromPath(string file, ITrainerInfo SAV) { var fi = new FileInfo(file); if (!fi.Exists) return null; if (fi.Length == GP1.SIZE && TryGetGP1(File.ReadAllBytes(file), out var gp1)) - return gp1.ConvertToPB7(SAV); + return gp1?.ConvertToPB7(SAV); if (!PKX.IsPKM(fi.Length) && !MysteryGift.IsMysteryGift(fi.Length)) return null; var data = File.ReadAllBytes(file); diff --git a/PKHeX.Core/Util/NetUtil.cs b/PKHeX.Core/Util/NetUtil.cs index 1d17fe0fa..faad5e66d 100644 --- a/PKHeX.Core/Util/NetUtil.cs +++ b/PKHeX.Core/Util/NetUtil.cs @@ -8,7 +8,7 @@ namespace PKHeX.Core { public static class NetUtil { - public static string GetStringFromURL(string webURL) + public static string? GetStringFromURL(string webURL) { try { @@ -40,7 +40,7 @@ private static Stream GetStreamFromURL(string webURL) /// Gets the latest version of PKHeX according to the Github API /// /// A version representing the latest available version of PKHeX, or null if the latest version could not be determined - public static Version GetLatestPKHeXVersion() + public static Version? GetLatestPKHeXVersion() { const string apiEndpoint = "https://api.github.com/repos/kwsch/pkhex/releases/latest"; var responseJson = GetStringFromURL(apiEndpoint); diff --git a/PKHeX.Core/Util/ReflectUtil.cs b/PKHeX.Core/Util/ReflectUtil.cs index 369124de9..c89849ccc 100644 --- a/PKHeX.Core/Util/ReflectUtil.cs +++ b/PKHeX.Core/Util/ReflectUtil.cs @@ -21,8 +21,8 @@ public static void SetValue(PropertyInfo pi, object obj, object value) pi.SetValue(obj, c, null); } - public static object GetValue(object obj, string name) => GetPropertyInfo(obj?.GetType().GetTypeInfo(), name)?.GetValue(obj); - public static void SetValue(object obj, string name, object value) => GetPropertyInfo(obj?.GetType().GetTypeInfo(), name)?.SetValue(obj, value, null); + public static object? GetValue(object obj, string name) => GetPropertyInfo(obj.GetType().GetTypeInfo(), name)?.GetValue(obj); + public static void SetValue(object obj, string name, object value) => GetPropertyInfo(obj.GetType().GetTypeInfo(), name)?.SetValue(obj, value, null); public static object GetValue(Type t, string propertyName) => t.GetTypeInfo().GetDeclaredProperty(propertyName).GetValue(null); public static void SetValue(Type t, string propertyName, object value) => t.GetTypeInfo().GetDeclaredProperty(propertyName).SetValue(null, value); @@ -70,7 +70,7 @@ public static IEnumerable GetPropertiesCanWritePublicDeclared(Type type) ; } - private static object ConvertValue(object value, Type type) + private static object? ConvertValue(object value, Type type) { if (type == typeof(DateTime?)) // Used for PKM.MetDate and other similar properties { @@ -104,7 +104,7 @@ public static IEnumerable GetAllNestedTypes(this TypeInfo typeInfo) public static IEnumerable GetAllProperties(this TypeInfo typeInfo) => GetAll(typeInfo, ti => ti.DeclaredProperties); - public static IEnumerable GetAllTypeInfo(this TypeInfo typeInfo) + public static IEnumerable GetAllTypeInfo(this TypeInfo? typeInfo) { while (typeInfo != null) { @@ -113,9 +113,9 @@ public static IEnumerable GetAllTypeInfo(this TypeInfo typeInfo) } } - public static bool HasProperty(object obj, string name, out PropertyInfo pi) => (pi = GetPropertyInfo(obj?.GetType().GetTypeInfo(), name)) != null; + public static bool HasProperty(object obj, string name, out PropertyInfo? pi) => (pi = GetPropertyInfo(obj.GetType().GetTypeInfo(), name)) != null; - public static PropertyInfo GetPropertyInfo(this TypeInfo typeInfo, string name) + public static PropertyInfo? GetPropertyInfo(this TypeInfo typeInfo, string name) { return typeInfo.GetAllTypeInfo().Select(t => t.GetDeclaredProperty(name)).FirstOrDefault(pi => pi != null); } diff --git a/PKHeX.Drawing/QR/QRDecode.cs b/PKHeX.Drawing/QR/QRDecode.cs index 4485e5b0c..36d029e42 100644 --- a/PKHeX.Drawing/QR/QRDecode.cs +++ b/PKHeX.Drawing/QR/QRDecode.cs @@ -25,7 +25,11 @@ public static QRDecodeMsg GetQRData(string address, out byte[] result) string data; try { - data = NetUtil.GetStringFromURL(webURL); + var str = NetUtil.GetStringFromURL(webURL); + if (str is null) + return QRDecodeMsg.BadConnection; + + data = str; if (data.Contains("could not find")) return QRDecodeMsg.BadImage; diff --git a/PKHeX.Drawing/QR/QREncode.cs b/PKHeX.Drawing/QR/QREncode.cs index f7127f7b0..a3e033d49 100644 --- a/PKHeX.Drawing/QR/QREncode.cs +++ b/PKHeX.Drawing/QR/QREncode.cs @@ -6,7 +6,7 @@ namespace PKHeX.Drawing { public static class QREncode { - public static Image GenerateQRCode(MysteryGift mg) => GenerateQRCode(QRMessageUtil.GetMessage(mg)); + public static Image GenerateQRCode(DataMysteryGift mg) => GenerateQRCode(QRMessageUtil.GetMessage(mg)); public static Image GenerateQRCode(PKM pkm) => GenerateQRCode(QRMessageUtil.GetMessage(pkm)); public static Image GenerateQRCode7(PK7 pk7, int box = 0, int slot = 0, int num_copies = 1) diff --git a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.Designer.cs b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.Designer.cs index fe7bfd91a..9fe7271d0 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.Designer.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.tabMain = new System.Windows.Forms.TabControl(); this.Tab_Main = new System.Windows.Forms.TabPage(); this.FLP_Main = new System.Windows.Forms.FlowLayoutPanel(); @@ -217,6 +218,9 @@ private void InitializeComponent() this.TB_OT = new System.Windows.Forms.TextBox(); this.Label_OT = new System.Windows.Forms.Label(); this.Label_EncryptionConstant = new System.Windows.Forms.Label(); + this.SpeciesIDTip = new System.Windows.Forms.ToolTip(this.components); + this.NatureTip = new System.Windows.Forms.ToolTip(this.components); + this.Tip3 = new System.Windows.Forms.ToolTip(this.components); this.tabMain.SuspendLayout(); this.Tab_Main.SuspendLayout(); this.FLP_Main.SuspendLayout(); @@ -2208,7 +2212,7 @@ private void InitializeComponent() this.Tab_OTMisc.Location = new System.Drawing.Point(4, 22); this.Tab_OTMisc.Name = "Tab_OTMisc"; this.Tab_OTMisc.Padding = new System.Windows.Forms.Padding(3); - this.Tab_OTMisc.Size = new System.Drawing.Size(272, 539); + this.Tab_OTMisc.Size = new System.Drawing.Size(192, 74); this.Tab_OTMisc.TabIndex = 4; this.Tab_OTMisc.Text = "OT/Misc"; this.Tab_OTMisc.UseVisualStyleBackColor = true; @@ -2915,5 +2919,8 @@ private void InitializeComponent() private System.Windows.Forms.FlowLayoutPanel FLP_SizeCP; private SizeCP SizeCP; private System.Windows.Forms.PictureBox PB_Favorite; + private System.Windows.Forms.ToolTip SpeciesIDTip; + private System.Windows.Forms.ToolTip NatureTip; + private System.Windows.Forms.ToolTip Tip3; } } diff --git a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs index 742c41678..cafe01874 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/PKMEditor.cs @@ -118,7 +118,6 @@ public bool HideSecretValues public delegate SaveFile ReturnSAVEventHandler(object sender, EventArgs e); private readonly PictureBox[] movePB, relearnPB; - private readonly ToolTip Tip3 = new ToolTip(), NatureTip = new ToolTip(), SpeciesIDTip = new ToolTip(); public SaveFile RequestSaveFile => SaveFileRequested?.Invoke(this, EventArgs.Empty); public bool PKMIsUnsaved => FieldsLoaded && LastData?.Any(b => b != 0) == true && !LastData.SequenceEqual(CurrentPKM.Data); public bool IsEmptyOrEgg => CHK_IsEgg.Checked || CB_Species.SelectedIndex == 0; @@ -221,8 +220,8 @@ public void SetPKMFormatMode(int Format, PKM pk) private void SetPKMFormatExtraBytes(PKM pk) { - byte[] extraBytes = pk.ExtraBytes; - GB_ExtraBytes.Visible = GB_ExtraBytes.Enabled = extraBytes.Length != 0; + var extraBytes = pk.ExtraBytes; + GB_ExtraBytes.Visible = GB_ExtraBytes.Enabled = extraBytes.Count != 0; CB_ExtraBytes.Items.Clear(); foreach (byte b in extraBytes) CB_ExtraBytes.Items.Add($"0x{b:X2}"); diff --git a/PKHeX.WinForms/Controls/PKM Editor/StatEditor.Designer.cs b/PKHeX.WinForms/Controls/PKM Editor/StatEditor.Designer.cs index 94e1f6c3f..86aba98a2 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/StatEditor.Designer.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/StatEditor.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.FLP_Stats = new System.Windows.Forms.FlowLayoutPanel(); this.FLP_StatHeader = new System.Windows.Forms.FlowLayoutPanel(); this.FLP_HackedStats = new System.Windows.Forms.FlowLayoutPanel(); @@ -103,9 +104,10 @@ private void InitializeComponent() this.Label_CharacteristicPrefix = new System.Windows.Forms.Label(); this.L_Characteristic = new System.Windows.Forms.Label(); this.PAN_BTN = new System.Windows.Forms.Panel(); + this.BTN_RandomAVs = new System.Windows.Forms.Button(); this.BTN_RandomIVs = new System.Windows.Forms.Button(); this.BTN_RandomEVs = new System.Windows.Forms.Button(); - this.BTN_RandomAVs = new System.Windows.Forms.Button(); + this.EVTip = new System.Windows.Forms.ToolTip(this.components); this.FLP_Stats.SuspendLayout(); this.FLP_StatHeader.SuspendLayout(); this.FLP_HackedStats.SuspendLayout(); @@ -1071,6 +1073,16 @@ private void InitializeComponent() this.PAN_BTN.Size = new System.Drawing.Size(267, 31); this.PAN_BTN.TabIndex = 132; // + // BTN_RandomAVs + // + this.BTN_RandomAVs.Location = new System.Drawing.Point(137, 3); + this.BTN_RandomAVs.Name = "BTN_RandomAVs"; + this.BTN_RandomAVs.Size = new System.Drawing.Size(92, 23); + this.BTN_RandomAVs.TabIndex = 106; + this.BTN_RandomAVs.Text = "Randomize AVs"; + this.BTN_RandomAVs.UseVisualStyleBackColor = true; + this.BTN_RandomAVs.Click += new System.EventHandler(this.UpdateRandomAVs); + // // BTN_RandomIVs // this.BTN_RandomIVs.Location = new System.Drawing.Point(38, 3); @@ -1091,16 +1103,6 @@ private void InitializeComponent() this.BTN_RandomEVs.UseVisualStyleBackColor = true; this.BTN_RandomEVs.Click += new System.EventHandler(this.UpdateRandomEVs); // - // BTN_RandomAVs - // - this.BTN_RandomAVs.Location = new System.Drawing.Point(137, 3); - this.BTN_RandomAVs.Name = "BTN_RandomAVs"; - this.BTN_RandomAVs.Size = new System.Drawing.Size(92, 23); - this.BTN_RandomAVs.TabIndex = 106; - this.BTN_RandomAVs.Text = "Randomize AVs"; - this.BTN_RandomAVs.UseVisualStyleBackColor = true; - this.BTN_RandomAVs.Click += new System.EventHandler(this.UpdateRandomAVs); - // // StatEditor // this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit; @@ -1220,5 +1222,6 @@ private void InitializeComponent() private System.Windows.Forms.MaskedTextBox TB_AVSPE; private System.Windows.Forms.TextBox TB_AVTotal; private System.Windows.Forms.Button BTN_RandomAVs; + private System.Windows.Forms.ToolTip EVTip; } } diff --git a/PKHeX.WinForms/Controls/PKM Editor/StatEditor.cs b/PKHeX.WinForms/Controls/PKM Editor/StatEditor.cs index 86713b35a..a0f28682a 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/StatEditor.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/StatEditor.cs @@ -50,7 +50,6 @@ public bool Valid private readonly Label[] L_Stats; private readonly MaskedTextBox[] MT_EVs, MT_IVs, MT_AVs, MT_Stats, MT_Base; - private readonly ToolTip EVTip = new ToolTip(); private PKM pkm => MainEditor.pkm; private bool ChangingFields @@ -404,10 +403,6 @@ public void SetATKIVGender(int gender) public void LoadPartyStats(PKM pk) { - int size = pk.SIZE_PARTY; - if (pk.Data.Length != size) - Array.Resize(ref pk.Data, size); - Stat_HP.Text = pk.Stat_HPCurrent.ToString(); Stat_ATK.Text = pk.Stat_ATK.ToString(); Stat_DEF.Text = pk.Stat_DEF.ToString(); @@ -418,10 +413,6 @@ public void LoadPartyStats(PKM pk) public void SavePartyStats(PKM pk) { - int size = pk.SIZE_PARTY; - if (pk.Data.Length != size) - Array.Resize(ref pk.Data, size); - pk.Stat_HPCurrent = Util.ToInt32(Stat_HP.Text); pk.Stat_HPMax = Util.ToInt32(Stat_HP.Text); pk.Stat_ATK = Util.ToInt32(Stat_ATK.Text); diff --git a/PKHeX.WinForms/Controls/PKM Editor/TrainerID.Designer.cs b/PKHeX.WinForms/Controls/PKM Editor/TrainerID.Designer.cs index b44fa925d..cf8b0e3c2 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/TrainerID.Designer.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/TrainerID.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.FLP = new System.Windows.Forms.FlowLayoutPanel(); this.Label_TID = new System.Windows.Forms.Label(); this.TB_TID = new System.Windows.Forms.MaskedTextBox(); @@ -35,6 +36,7 @@ private void InitializeComponent() this.Label_SID = new System.Windows.Forms.Label(); this.TB_SID = new System.Windows.Forms.MaskedTextBox(); this.TB_SID7 = new System.Windows.Forms.MaskedTextBox(); + this.TSVTooltip = new System.Windows.Forms.ToolTip(this.components); this.FLP.SuspendLayout(); this.SuspendLayout(); // @@ -152,5 +154,6 @@ private void InitializeComponent() private System.Windows.Forms.Label Label_TID; private System.Windows.Forms.MaskedTextBox TB_TID7; private System.Windows.Forms.MaskedTextBox TB_SID7; + private System.Windows.Forms.ToolTip TSVTooltip; } } diff --git a/PKHeX.WinForms/Controls/PKM Editor/TrainerID.cs b/PKHeX.WinForms/Controls/PKM Editor/TrainerID.cs index 51c6dc818..6cbdf5aaf 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/TrainerID.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/TrainerID.cs @@ -12,7 +12,6 @@ public partial class TrainerID : UserControl private int Format = -1; private ITrainerID Trainer; - private readonly ToolTip TSVTooltip = new ToolTip(); public void UpdateTSV() { diff --git a/PKHeX.WinForms/Controls/SAV Editor/ContextMenuSAV.cs b/PKHeX.WinForms/Controls/SAV Editor/ContextMenuSAV.cs index cb2262071..65e3958b3 100644 --- a/PKHeX.WinForms/Controls/SAV Editor/ContextMenuSAV.cs +++ b/PKHeX.WinForms/Controls/SAV Editor/ContextMenuSAV.cs @@ -135,7 +135,7 @@ private static SlotViewInfo GetSenderInfo(ref object sender) var view = WinFormsUtil.FindFirstControlOfType>(pb); var loc = view.GetSlotData(pb); sender = pb; - return new SlotViewInfo {Slot = loc, View = view}; + return new SlotViewInfo(loc, view); } private static void ToggleItem(ToolStripItemCollection items, ToolStripItem item, bool visible, bool first = false) diff --git a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.Designer.cs b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.Designer.cs index f8d7d9395..c9e5e3e16 100644 --- a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.Designer.cs +++ b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.Designer.cs @@ -18,6 +18,8 @@ protected override void Dispose(bool disposing) components.Dispose(); } base.Dispose(disposing); + SortMenu?.Dispose(); + menu?.Dispose(); } #region Component Designer generated code diff --git a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs index 694fd32a0..2542efb80 100644 --- a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs +++ b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs @@ -507,11 +507,11 @@ private void B_SaveBoxBin_Click(object sender, EventArgs e) } // Subfunction Save Buttons // - private void B_OpenWondercards_Click(object sender, EventArgs e) => new SAV_Wondercard(SAV, sender as MysteryGift).ShowDialog(); + private void B_OpenWondercards_Click(object sender, EventArgs e) => new SAV_Wondercard(SAV, sender as DataMysteryGift).ShowDialog(); private void B_OpenPokepuffs_Click(object sender, EventArgs e) => new SAV_Pokepuff(SAV).ShowDialog(); private void B_OpenPokeBeans_Click(object sender, EventArgs e) => new SAV_Pokebean(SAV).ShowDialog(); private void B_OpenItemPouch_Click(object sender, EventArgs e) => new SAV_Inventory(SAV).ShowDialog(); - private void B_OpenBerryField_Click(object sender, EventArgs e) => new SAV_BerryFieldXY(SAV).ShowDialog(); + private void B_OpenBerryField_Click(object sender, EventArgs e) => new SAV_BerryFieldXY((SAV6XY)SAV).ShowDialog(); private void B_OpenPokeblocks_Click(object sender, EventArgs e) => new SAV_PokeBlockORAS(SAV).ShowDialog(); private void B_OpenSuperTraining_Click(object sender, EventArgs e) => new SAV_SuperTrain(SAV).ShowDialog(); private void B_OpenSecretBase_Click(object sender, EventArgs e) => new SAV_SecretBase(SAV).ShowDialog(); diff --git a/PKHeX.WinForms/Controls/SAV Editor/SlotChangeManager.cs b/PKHeX.WinForms/Controls/SAV Editor/SlotChangeManager.cs index a7a58fbf6..2ca25ffc4 100644 --- a/PKHeX.WinForms/Controls/SAV Editor/SlotChangeManager.cs +++ b/PKHeX.WinForms/Controls/SAV Editor/SlotChangeManager.cs @@ -91,7 +91,7 @@ public void DragEnter(object sender, DragEventArgs e) { var view = WinFormsUtil.FindFirstControlOfType>(pb); var src = view.GetSlotData(pb); - return new SlotViewInfo { Slot = src, View = view }; + return new SlotViewInfo(src, view); } public void MouseMove(object sender, MouseEventArgs e) diff --git a/PKHeX.WinForms/Controls/Slots/PokeGrid.cs b/PKHeX.WinForms/Controls/Slots/PokeGrid.cs index dc3fd40e3..2d0d4d7ef 100644 --- a/PKHeX.WinForms/Controls/Slots/PokeGrid.cs +++ b/PKHeX.WinForms/Controls/Slots/PokeGrid.cs @@ -48,6 +48,7 @@ private void Generate(int width, int height) { var x = padEdge + (column * (colWidth + border)); var pb = GetControl(sizeW, sizeH); + pb.SuspendLayout(); Controls.Add(pb); pb.Location = new Point(x, y); Entries.Add(pb); diff --git a/PKHeX.WinForms/MainWindow/Main.cs b/PKHeX.WinForms/MainWindow/Main.cs index 89ca33bbd..70be4217c 100644 --- a/PKHeX.WinForms/MainWindow/Main.cs +++ b/PKHeX.WinForms/MainWindow/Main.cs @@ -33,7 +33,7 @@ public Main() FormLoadInitialSettings(args, out bool showChangelog, out bool BAKprompt); InitializeComponent(); - C_SAV.EditEnv = new SaveDataEditor(null) { PKMEditor = PKME_Tabs }; + C_SAV.EditEnv = new SaveDataEditor(null, PKME_Tabs); FormLoadAddEvents(); #if DEBUG // translation updater -- all controls are added at this point -- call translate now if (DevUtil.IsUpdatingTranslations) @@ -750,7 +750,7 @@ private bool OpenSAV(SaveFile sav, string path) private void ResetSAVPKMEditors(SaveFile sav) { bool WindowToggleRequired = C_SAV.SAV?.Generation < 3 && sav.Generation >= 3; // version combobox refresh hack - C_SAV.EditEnv = new SaveDataEditor(sav) {PKMEditor = PKME_Tabs}; + C_SAV.EditEnv = new SaveDataEditor(sav, PKME_Tabs); var pk = sav.LoadTemplate(TemplatePath); var isBlank = pk.Data.SequenceEqual(sav.BlankPKM.Data); diff --git a/PKHeX.WinForms/Misc/QR.Designer.cs b/PKHeX.WinForms/Misc/QR.Designer.cs index 7c518d767..fb5415cde 100644 --- a/PKHeX.WinForms/Misc/QR.Designer.cs +++ b/PKHeX.WinForms/Misc/QR.Designer.cs @@ -1,8 +1,5 @@ -using System; -using System.ComponentModel; -using System.Drawing; +using System.ComponentModel; using System.Windows.Forms; -using PKHeX.Core; namespace PKHeX.WinForms { @@ -24,6 +21,7 @@ protected override void Dispose(bool disposing) components.Dispose(); } base.Dispose(disposing); + qr?.Dispose(); } #region Windows Form Designer generated code diff --git a/PKHeX.WinForms/Subforms/PKM Editors/RibbonEditor.Designer.cs b/PKHeX.WinForms/Subforms/PKM Editors/RibbonEditor.Designer.cs index 1fb53dbe6..b175d4a65 100644 --- a/PKHeX.WinForms/Subforms/PKM Editors/RibbonEditor.Designer.cs +++ b/PKHeX.WinForms/Subforms/PKM Editors/RibbonEditor.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.B_Save = new System.Windows.Forms.Button(); this.B_Cancel = new System.Windows.Forms.Button(); this.B_None = new System.Windows.Forms.Button(); @@ -36,6 +37,7 @@ private void InitializeComponent() this.SPLIT_Ribbons = new System.Windows.Forms.SplitContainer(); this.FLP_Ribbons = new System.Windows.Forms.FlowLayoutPanel(); this.TLP_Ribbons = new System.Windows.Forms.TableLayoutPanel(); + this.tipName = new System.Windows.Forms.ToolTip(this.components); this.PAN_Container.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.SPLIT_Ribbons)).BeginInit(); this.SPLIT_Ribbons.Panel1.SuspendLayout(); @@ -183,5 +185,6 @@ private void InitializeComponent() private System.Windows.Forms.TableLayoutPanel TLP_Ribbons; private System.Windows.Forms.FlowLayoutPanel FLP_Ribbons; private System.Windows.Forms.SplitContainer SPLIT_Ribbons; + private System.Windows.Forms.ToolTip tipName; } } \ No newline at end of file diff --git a/PKHeX.WinForms/Subforms/PKM Editors/RibbonEditor.cs b/PKHeX.WinForms/Subforms/PKM Editors/RibbonEditor.cs index c71ab2f72..1c956ff40 100644 --- a/PKHeX.WinForms/Subforms/PKM Editors/RibbonEditor.cs +++ b/PKHeX.WinForms/Subforms/PKM Editors/RibbonEditor.cs @@ -29,7 +29,6 @@ public RibbonEditor(PKM pk) private readonly IReadOnlyList riblist; private readonly PKM pkm; - private readonly ToolTip tipName = new ToolTip(); private const string PrefixNUD = "NUD_"; private const string PrefixLabel = "L_"; diff --git a/PKHeX.WinForms/Subforms/PKM Editors/Text.cs b/PKHeX.WinForms/Subforms/PKM Editors/Text.cs index 11205db3d..fbbef1fbb 100644 --- a/PKHeX.WinForms/Subforms/PKM Editors/Text.cs +++ b/PKHeX.WinForms/Subforms/PKM Editors/Text.cs @@ -23,10 +23,11 @@ public TrashEditor(TextBoxBase TB_NN, byte[] raw, SaveFile sav) if (raw != null) AddTrashEditing(raw.Length); - AddCharEditing(); + var f = FontUtil.GetPKXFont(12F); + AddCharEditing(f); TB_Text.MaxLength = TB_NN.MaxLength; TB_Text.Text = TB_NN.Text; - TB_Text.Font = pkxFont; + TB_Text.Font = f; if (FLP_Characters.Controls.Count == 0) { @@ -44,7 +45,6 @@ public TrashEditor(TextBoxBase TB_NN, byte[] raw, SaveFile sav) } private readonly List Bytes = new List(); - private readonly Font pkxFont = FontUtil.GetPKXFont(12F); public string FinalString; public byte[] FinalBytes { get; private set; } private readonly byte[] Raw; @@ -59,7 +59,7 @@ private void B_Save_Click(object sender, EventArgs e) Close(); } - private void AddCharEditing() + private void AddCharEditing(Font f) { ushort[] chars = GetChars(SAV.Generation); if (chars.Length == 0) @@ -69,7 +69,7 @@ private void AddCharEditing() foreach (ushort c in chars) { var l = GetLabel(((char)c).ToString()); - l.Font = pkxFont; + l.Font = f; l.AutoSize = false; l.Size = new Size(20, 20); l.Click += (s, e) => { if (TB_Text.Text.Length < TB_Text.MaxLength) TB_Text.AppendText(l.Text); }; diff --git a/PKHeX.WinForms/Subforms/SAV_Encounters.Designer.cs b/PKHeX.WinForms/Subforms/SAV_Encounters.Designer.cs index b453f7a1e..4bf953555 100644 --- a/PKHeX.WinForms/Subforms/SAV_Encounters.Designer.cs +++ b/PKHeX.WinForms/Subforms/SAV_Encounters.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.SCR_Box = new System.Windows.Forms.VScrollBar(); this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.Menu_Close = new System.Windows.Forms.ToolStripMenuItem(); @@ -36,6 +37,7 @@ private void InitializeComponent() this.Menu_SearchSettings = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_SearchAdvanced = new System.Windows.Forms.ToolStripMenuItem(); this.P_Results = new System.Windows.Forms.Panel(); + this.pokeGrid1 = new PKHeX.WinForms.Controls.PokeGrid(); this.CB_Species = new System.Windows.Forms.ComboBox(); this.CB_Move4 = new System.Windows.Forms.ComboBox(); this.CB_Move3 = new System.Windows.Forms.ComboBox(); @@ -56,8 +58,9 @@ private void InitializeComponent() this.FLP_Level = new System.Windows.Forms.FlowLayoutPanel(); this.CB_GameOrigin = new System.Windows.Forms.ComboBox(); this.L_Version = new System.Windows.Forms.Label(); + this.TypeFilters = new System.Windows.Forms.FlowLayoutPanel(); this.RTB_Instructions = new System.Windows.Forms.RichTextBox(); - this.pokeGrid1 = new PKHeX.WinForms.Controls.PokeGrid(); + this.hover = new System.Windows.Forms.ToolTip(this.components); this.menuStrip1.SuspendLayout(); this.P_Results.SuspendLayout(); this.TLP_Filters.SuspendLayout(); @@ -142,6 +145,15 @@ private void InitializeComponent() this.P_Results.Size = new System.Drawing.Size(285, 352); this.P_Results.TabIndex = 66; // + // pokeGrid1 + // + this.pokeGrid1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.pokeGrid1.Location = new System.Drawing.Point(2, 2); + this.pokeGrid1.Margin = new System.Windows.Forms.Padding(0); + this.pokeGrid1.Name = "pokeGrid1"; + this.pokeGrid1.Size = new System.Drawing.Size(251, 346); + this.pokeGrid1.TabIndex = 2; + // // CB_Species // this.CB_Species.Anchor = System.Windows.Forms.AnchorStyles.Left; @@ -353,6 +365,7 @@ private void InitializeComponent() this.TLP_Filters.Controls.Add(this.CB_GameOrigin, 1, 16); this.TLP_Filters.Controls.Add(this.FLP_Egg, 0, 0); this.TLP_Filters.Controls.Add(this.L_Version, 0, 16); + this.TLP_Filters.Controls.Add(this.TypeFilters, 1, 17); this.TLP_Filters.Location = new System.Drawing.Point(304, 16); this.TLP_Filters.Name = "TLP_Filters"; this.TLP_Filters.RowCount = 18; @@ -410,6 +423,14 @@ private void InitializeComponent() this.L_Version.Text = "OT Version:"; this.L_Version.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // + // TypeFilters + // + this.TypeFilters.Dock = System.Windows.Forms.DockStyle.Fill; + this.TypeFilters.Location = new System.Drawing.Point(72, 146); + this.TypeFilters.Name = "TypeFilters"; + this.TypeFilters.Size = new System.Drawing.Size(153, 210); + this.TypeFilters.TabIndex = 123; + // // RTB_Instructions // this.RTB_Instructions.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) @@ -420,15 +441,6 @@ private void InitializeComponent() this.RTB_Instructions.TabIndex = 119; this.RTB_Instructions.Text = ""; // - // pokeGrid1 - // - this.pokeGrid1.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; - this.pokeGrid1.Location = new System.Drawing.Point(2, 2); - this.pokeGrid1.Margin = new System.Windows.Forms.Padding(0); - this.pokeGrid1.Name = "pokeGrid1"; - this.pokeGrid1.Size = new System.Drawing.Size(251, 346); - this.pokeGrid1.TabIndex = 2; - // // SAV_Encounters // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -493,5 +505,7 @@ private void InitializeComponent() private System.Windows.Forms.ComboBox CB_GameOrigin; private System.Windows.Forms.Label L_Version; private Controls.PokeGrid pokeGrid1; + private System.Windows.Forms.FlowLayoutPanel TypeFilters; + private System.Windows.Forms.ToolTip hover; } } \ No newline at end of file diff --git a/PKHeX.WinForms/Subforms/SAV_Encounters.cs b/PKHeX.WinForms/Subforms/SAV_Encounters.cs index 8af89c749..309a330fb 100644 --- a/PKHeX.WinForms/Subforms/SAV_Encounters.cs +++ b/PKHeX.WinForms/Subforms/SAV_Encounters.cs @@ -47,7 +47,6 @@ public SAV_Encounters(PKMEditor f1) Counter = L_Count.Text; L_Viewed.Text = string.Empty; // invis for now - var hover = new ToolTip(); L_Viewed.MouseEnter += (sender, e) => hover.SetToolTip(L_Viewed, L_Viewed.Text); PopulateComboBoxes(); @@ -61,8 +60,7 @@ public SAV_Encounters(PKMEditor f1) p.ContextMenuStrip = mnu; WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage); - - TLP_Filters.Controls.Add(TypeFilters = GetTypeFilters(), 2, TLP_Filters.RowCount - 1); + GetTypeFilters(); // Load Data L_Count.Text = "Ready..."; @@ -75,9 +73,8 @@ public SAV_Encounters(PKMEditor f1) CenterToParent(); } - private static FlowLayoutPanel GetTypeFilters() + private void GetTypeFilters() { - var flp = new FlowLayoutPanel { Dock = DockStyle.Fill }; var types = (EncounterOrder[])Enum.GetValues(typeof(EncounterOrder)); var checks = types.Select(z => new CheckBox { @@ -90,11 +87,9 @@ private static FlowLayoutPanel GetTypeFilters() }).ToArray(); foreach (var chk in checks) { - flp.Controls.Add(chk); - flp.SetFlowBreak(chk, true); + TypeFilters.Controls.Add(chk); + TypeFilters.SetFlowBreak(chk, true); } - flp.AutoSize = true; - return flp; } private EncounterOrder[] GetTypes() @@ -110,7 +105,6 @@ private EncounterOrder[] GetTypes() private const int RES_MAX = 66; private const int RES_MIN = 6; private readonly string Counter; - private readonly FlowLayoutPanel TypeFilters; // Important Events private void ClickView(object sender, EventArgs e) diff --git a/PKHeX.WinForms/Subforms/SAV_MysteryGiftDB.cs b/PKHeX.WinForms/Subforms/SAV_MysteryGiftDB.cs index 56f216c0c..ea7ff1bdd 100644 --- a/PKHeX.WinForms/Subforms/SAV_MysteryGiftDB.cs +++ b/PKHeX.WinForms/Subforms/SAV_MysteryGiftDB.cs @@ -124,12 +124,12 @@ private void ClickSaveMG(object sender, EventArgs e) if (index < 0) return; var gift = Results[index]; - if (gift.Data == null) // WC3 + if (!(gift is DataMysteryGift g)) // e.g. WC3 { WinFormsUtil.Alert(MsgExportWC3DataFail); return; } - WinFormsUtil.ExportMGDialog(gift, SAV.Version); + WinFormsUtil.ExportMGDialog(g, SAV.Version); } private int GetSenderIndex(object sender) @@ -231,7 +231,7 @@ private void Menu_Export_Click(object sender, EventArgs e) string path = fbd.SelectedPath; Directory.CreateDirectory(path); - foreach (var gift in Results.Where(g => g.Data != null)) // WC3 have no data + foreach (var gift in Results.OfType()) // WC3 have no data File.WriteAllBytes(Path.Combine(path, Util.CleanFileName(gift.FileName)), gift.Data); } diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen4/SAV_Misc4.Designer.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen4/SAV_Misc4.Designer.cs index 87ae8abce..f4fd88302 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen4/SAV_Misc4.Designer.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen4/SAV_Misc4.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.B_Cancel = new System.Windows.Forms.Button(); this.B_Save = new System.Windows.Forms.Button(); this.TC_Misc = new System.Windows.Forms.TabControl(); @@ -103,9 +104,11 @@ private void InitializeComponent() this.B_AllSealsIllegal = new System.Windows.Forms.Button(); this.B_AllSealsLegal = new System.Windows.Forms.Button(); this.Tab_Poffins = new System.Windows.Forms.TabPage(); - this.Tab_PokeGear = new System.Windows.Forms.TabPage(); this.poffinCase4Editor1 = new PKHeX.WinForms.PoffinCase4Editor(); + this.Tab_PokeGear = new System.Windows.Forms.TabPage(); this.pokeGear4Editor1 = new PKHeX.WinForms.PokeGear4Editor(); + this.tip1 = new System.Windows.Forms.ToolTip(this.components); + this.tip2 = new System.Windows.Forms.ToolTip(this.components); this.TC_Misc.SuspendLayout(); this.TAB_Main.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.NUD_Coin)).BeginInit(); @@ -1207,6 +1210,14 @@ private void InitializeComponent() this.Tab_Poffins.Text = "Poffins"; this.Tab_Poffins.UseVisualStyleBackColor = true; // + // poffinCase4Editor1 + // + this.poffinCase4Editor1.Dock = System.Windows.Forms.DockStyle.Fill; + this.poffinCase4Editor1.Location = new System.Drawing.Point(3, 3); + this.poffinCase4Editor1.Name = "poffinCase4Editor1"; + this.poffinCase4Editor1.Size = new System.Drawing.Size(367, 233); + this.poffinCase4Editor1.TabIndex = 0; + // // Tab_PokeGear // this.Tab_PokeGear.Controls.Add(this.pokeGear4Editor1); @@ -1218,14 +1229,6 @@ private void InitializeComponent() this.Tab_PokeGear.Text = "PokeGear"; this.Tab_PokeGear.UseVisualStyleBackColor = true; // - // poffinCase4Editor1 - // - this.poffinCase4Editor1.Dock = System.Windows.Forms.DockStyle.Fill; - this.poffinCase4Editor1.Location = new System.Drawing.Point(3, 3); - this.poffinCase4Editor1.Name = "poffinCase4Editor1"; - this.poffinCase4Editor1.Size = new System.Drawing.Size(367, 233); - this.poffinCase4Editor1.TabIndex = 0; - // // pokeGear4Editor1 // this.pokeGear4Editor1.Dock = System.Windows.Forms.DockStyle.Fill; @@ -1375,5 +1378,7 @@ private void InitializeComponent() private PoffinCase4Editor poffinCase4Editor1; private System.Windows.Forms.TabPage Tab_PokeGear; private PokeGear4Editor pokeGear4Editor1; + private System.Windows.Forms.ToolTip tip1; + private System.Windows.Forms.ToolTip tip2; } } diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen4/SAV_Misc4.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen4/SAV_Misc4.cs index 33d0683a6..ad3f24182 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen4/SAV_Misc4.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen4/SAV_Misc4.cs @@ -198,7 +198,6 @@ private void B_AllFlyDest_Click(object sender, EventArgs e) #region Poketch private byte[] DotArtistByte; private byte[] ColorTable; - private readonly ToolTip tip1 = new ToolTip(); private void ReadPoketch() { @@ -426,7 +425,6 @@ private void PB_DotArtist_MouseClick(object sender, MouseEventArgs e) private string[][] BFT; private int[][] BFV; private string[] BFN; - private readonly ToolTip tip2 = new ToolTip(); private NumericUpDown[] HallNUDA; private bool HallStatUpdated; private int ofsHallStat = -1; diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.Designer.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.Designer.cs index ef4bb50a3..3484f6044 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.Designer.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.B_Cancel = new System.Windows.Forms.Button(); this.B_Save = new System.Windows.Forms.Button(); this.TC_Misc = new System.Windows.Forms.TabControl(); @@ -96,6 +97,8 @@ private void InitializeComponent() this.CB_Species = new System.Windows.Forms.ComboBox(); this.CB_Areas = new System.Windows.Forms.ComboBox(); this.LB_Slots = new System.Windows.Forms.ListBox(); + this.TipExpB = new System.Windows.Forms.ToolTip(this.components); + this.TipExpW = new System.Windows.Forms.ToolTip(this.components); this.TC_Misc.SuspendLayout(); this.TAB_Main.SuspendLayout(); this.GB_KeySystem.SuspendLayout(); @@ -1089,5 +1092,7 @@ private void InitializeComponent() private System.Windows.Forms.Label L_Area18; private System.Windows.Forms.NumericUpDown NUD_Unlocked; private System.Windows.Forms.Button B_RandForest; + private System.Windows.Forms.ToolTip TipExpB; + private System.Windows.Forms.ToolTip TipExpW; } } \ No newline at end of file diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.cs index b7be24ceb..ee3c7802c 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Misc5.cs @@ -287,7 +287,6 @@ private void B_AllKeys_Click(object sender, EventArgs e) private bool editing; private const int ofsFM = 0x25900; - private readonly ToolTip TipExpB = new ToolTip(), TipExpW = new ToolTip(); private NumericUpDown[] nudaE, nudaF; private ComboBox[] cba; private ToolTip[] ta; @@ -674,7 +673,7 @@ private void B_RandForest_Click(object sender, EventArgs e) source.Remove(slot); s.Species = slot.Species; s.Form = slot.Form; - s.Move = slot.Moves?[Util.Rand.Next(slot.Moves.Length)] ?? 0; + s.Move = slot.Moves[Util.Rand.Next(slot.Moves.Length)]; s.Gender = slot.Gender == -1 ? PersonalTable.B2W2[slot.Species].RandomGender() : slot.Gender; } ChangeArea(null, EventArgs.Empty); // refresh diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Pokedex5.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Pokedex5.cs index fb6f062a2..cf6c3b1a7 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Pokedex5.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen5/SAV_Pokedex5.cs @@ -107,7 +107,7 @@ private void GetEntry() int pk = species; // Load Partitions - var Dex = (Zukan5)SAV.Zukan; + var Dex = SAV.Zukan; CP[0].Checked = Dex.GetCaught(species); for (int i = 0; i < 4; i++) CP[i + 1].Checked = Dex.GetSeen(species, i); @@ -160,7 +160,7 @@ private void SetEntry() if (species < 0) return; - var Dex = (Zukan5)SAV.Zukan; + var Dex = SAV.Zukan; Dex.SetCaught(species, CP[0].Checked); for (int i = 0; i < 4; i++) Dex.SetSeen(species, i, CP[i + 1].Checked); diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_BerryFieldXY.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_BerryFieldXY.cs index ec6428c93..57b9846dc 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_BerryFieldXY.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_BerryFieldXY.cs @@ -6,13 +6,13 @@ namespace PKHeX.WinForms { public partial class SAV_BerryFieldXY : Form { - private readonly SAV6 SAV; + private readonly SAV6XY SAV; - public SAV_BerryFieldXY(SaveFile sav) + public SAV_BerryFieldXY(SAV6XY sav) { InitializeComponent(); WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage); - SAV = (SAV6)sav; + SAV = sav; listBox1.SelectedIndex = 0; } diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.Designer.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.Designer.cs index 5763fe1a8..bfc6bdcff 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.Designer.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.Designer.cs @@ -68,10 +68,12 @@ private void InitializeComponent() this.L_Level = new System.Windows.Forms.Label(); this.B_CopyText = new System.Windows.Forms.Button(); this.B_Delete = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); ((System.ComponentModel.ISupportInitialize)(this.bpkx)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.NUP_PartyIndex)).BeginInit(); this.GB_CurrentMoves.SuspendLayout(); this.GB_OT.SuspendLayout(); + this.groupBox1.SuspendLayout(); this.SuspendLayout(); // // LB_DataEntry @@ -111,7 +113,7 @@ private void InitializeComponent() this.RTB.Location = new System.Drawing.Point(72, 16); this.RTB.Name = "RTB"; this.RTB.ReadOnly = true; - this.RTB.Size = new System.Drawing.Size(220, 287); + this.RTB.Size = new System.Drawing.Size(221, 308); this.RTB.TabIndex = 1; this.RTB.Text = ""; this.RTB.WordWrap = false; @@ -119,7 +121,7 @@ private void InitializeComponent() // B_Close // this.B_Close.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.B_Close.Location = new System.Drawing.Point(529, 270); + this.B_Close.Location = new System.Drawing.Point(542, 291); this.B_Close.Name = "B_Close"; this.B_Close.Size = new System.Drawing.Size(76, 23); this.B_Close.TabIndex = 3; @@ -130,16 +132,16 @@ private void InitializeComponent() // bpkx // this.bpkx.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.bpkx.Location = new System.Drawing.Point(308, 99); + this.bpkx.Location = new System.Drawing.Point(15, 109); this.bpkx.Name = "bpkx"; - this.bpkx.Size = new System.Drawing.Size(42, 32); + this.bpkx.Size = new System.Drawing.Size(44, 32); this.bpkx.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage; this.bpkx.TabIndex = 31; this.bpkx.TabStop = false; // // NUP_PartyIndex // - this.NUP_PartyIndex.Location = new System.Drawing.Point(369, 47); + this.NUP_PartyIndex.Location = new System.Drawing.Point(76, 57); this.NUP_PartyIndex.Maximum = new decimal(new int[] { 6, 0, @@ -151,7 +153,7 @@ private void InitializeComponent() 0, 0}); this.NUP_PartyIndex.Name = "NUP_PartyIndex"; - this.NUP_PartyIndex.Size = new System.Drawing.Size(28, 20); + this.NUP_PartyIndex.Size = new System.Drawing.Size(30, 20); this.NUP_PartyIndex.TabIndex = 32; this.NUP_PartyIndex.Value = new decimal(new int[] { 1, @@ -163,7 +165,7 @@ private void InitializeComponent() // L_PartyNum // this.L_PartyNum.AutoSize = true; - this.L_PartyNum.Location = new System.Drawing.Point(300, 49); + this.L_PartyNum.Location = new System.Drawing.Point(7, 59); this.L_PartyNum.Name = "L_PartyNum"; this.L_PartyNum.Size = new System.Drawing.Size(63, 13); this.L_PartyNum.TabIndex = 33; @@ -174,26 +176,26 @@ private void InitializeComponent() this.CB_Species.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend; this.CB_Species.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems; this.CB_Species.FormattingEnabled = true; - this.CB_Species.Location = new System.Drawing.Point(483, 46); + this.CB_Species.Location = new System.Drawing.Point(190, 56); this.CB_Species.Name = "CB_Species"; - this.CB_Species.Size = new System.Drawing.Size(122, 21); + this.CB_Species.Size = new System.Drawing.Size(124, 21); this.CB_Species.TabIndex = 35; this.CB_Species.SelectedValueChanged += new System.EventHandler(this.UpdateSpecies); // // Label_Species // - this.Label_Species.Location = new System.Drawing.Point(428, 49); + this.Label_Species.Location = new System.Drawing.Point(135, 59); this.Label_Species.Name = "Label_Species"; - this.Label_Species.Size = new System.Drawing.Size(50, 13); + this.Label_Species.Size = new System.Drawing.Size(52, 13); this.Label_Species.TabIndex = 34; this.Label_Species.Text = "Species:"; this.Label_Species.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // CHK_Nicknamed // - this.CHK_Nicknamed.Location = new System.Drawing.Point(403, 73); + this.CHK_Nicknamed.Location = new System.Drawing.Point(110, 83); this.CHK_Nicknamed.Name = "CHK_Nicknamed"; - this.CHK_Nicknamed.Size = new System.Drawing.Size(80, 17); + this.CHK_Nicknamed.Size = new System.Drawing.Size(82, 17); this.CHK_Nicknamed.TabIndex = 36; this.CHK_Nicknamed.Text = "Nickname:"; this.CHK_Nicknamed.TextAlign = System.Drawing.ContentAlignment.MiddleRight; @@ -203,10 +205,10 @@ private void InitializeComponent() // TB_Nickname // this.TB_Nickname.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.TB_Nickname.Location = new System.Drawing.Point(483, 71); + this.TB_Nickname.Location = new System.Drawing.Point(190, 81); this.TB_Nickname.MaxLength = 12; this.TB_Nickname.Name = "TB_Nickname"; - this.TB_Nickname.Size = new System.Drawing.Size(122, 20); + this.TB_Nickname.Size = new System.Drawing.Size(124, 20); this.TB_Nickname.TabIndex = 37; this.TB_Nickname.TextChanged += new System.EventHandler(this.Write_Entry); this.TB_Nickname.MouseDown += new System.Windows.Forms.MouseEventHandler(this.ChangeNickname); @@ -215,19 +217,19 @@ private void InitializeComponent() // this.TB_EC.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; this.TB_EC.Font = new System.Drawing.Font("Courier New", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.TB_EC.Location = new System.Drawing.Point(545, 150); + this.TB_EC.Location = new System.Drawing.Point(252, 160); this.TB_EC.MaxLength = 8; this.TB_EC.Name = "TB_EC"; - this.TB_EC.Size = new System.Drawing.Size(60, 20); + this.TB_EC.Size = new System.Drawing.Size(62, 20); this.TB_EC.TabIndex = 63; this.TB_EC.Text = "12345678"; this.TB_EC.TextChanged += new System.EventHandler(this.Write_Entry); // // Label_EncryptionConstant // - this.Label_EncryptionConstant.Location = new System.Drawing.Point(438, 153); + this.Label_EncryptionConstant.Location = new System.Drawing.Point(145, 163); this.Label_EncryptionConstant.Name = "Label_EncryptionConstant"; - this.Label_EncryptionConstant.Size = new System.Drawing.Size(105, 13); + this.Label_EncryptionConstant.Size = new System.Drawing.Size(107, 13); this.Label_EncryptionConstant.TabIndex = 62; this.Label_EncryptionConstant.Text = "Encryption Constant:"; this.Label_EncryptionConstant.TextAlign = System.Drawing.ContentAlignment.MiddleRight; @@ -238,9 +240,9 @@ private void InitializeComponent() this.GB_CurrentMoves.Controls.Add(this.CB_Move3); this.GB_CurrentMoves.Controls.Add(this.CB_Move2); this.GB_CurrentMoves.Controls.Add(this.CB_Move1); - this.GB_CurrentMoves.Location = new System.Drawing.Point(299, 185); + this.GB_CurrentMoves.Location = new System.Drawing.Point(6, 195); this.GB_CurrentMoves.Name = "GB_CurrentMoves"; - this.GB_CurrentMoves.Size = new System.Drawing.Size(139, 112); + this.GB_CurrentMoves.Size = new System.Drawing.Size(141, 112); this.GB_CurrentMoves.TabIndex = 64; this.GB_CurrentMoves.TabStop = false; this.GB_CurrentMoves.Text = "Current Moves"; @@ -291,9 +293,9 @@ private void InitializeComponent() // // Label_HeldItem // - this.Label_HeldItem.Location = new System.Drawing.Point(403, 99); + this.Label_HeldItem.Location = new System.Drawing.Point(110, 109); this.Label_HeldItem.Name = "Label_HeldItem"; - this.Label_HeldItem.Size = new System.Drawing.Size(77, 13); + this.Label_HeldItem.Size = new System.Drawing.Size(79, 13); this.Label_HeldItem.TabIndex = 66; this.Label_HeldItem.Text = "Held Item:"; this.Label_HeldItem.TextAlign = System.Drawing.ContentAlignment.MiddleRight; @@ -303,9 +305,9 @@ private void InitializeComponent() this.CB_HeldItem.AutoCompleteMode = System.Windows.Forms.AutoCompleteMode.SuggestAppend; this.CB_HeldItem.AutoCompleteSource = System.Windows.Forms.AutoCompleteSource.ListItems; this.CB_HeldItem.FormattingEnabled = true; - this.CB_HeldItem.Location = new System.Drawing.Point(483, 96); + this.CB_HeldItem.Location = new System.Drawing.Point(190, 106); this.CB_HeldItem.Name = "CB_HeldItem"; - this.CB_HeldItem.Size = new System.Drawing.Size(122, 21); + this.CB_HeldItem.Size = new System.Drawing.Size(124, 21); this.CB_HeldItem.TabIndex = 65; this.CB_HeldItem.SelectedValueChanged += new System.EventHandler(this.Write_Entry); // @@ -317,9 +319,9 @@ private void InitializeComponent() this.GB_OT.Controls.Add(this.Label_OT); this.GB_OT.Controls.Add(this.Label_SID); this.GB_OT.Controls.Add(this.Label_TID); - this.GB_OT.Location = new System.Drawing.Point(444, 185); + this.GB_OT.Location = new System.Drawing.Point(151, 195); this.GB_OT.Name = "GB_OT"; - this.GB_OT.Size = new System.Drawing.Size(161, 75); + this.GB_OT.Size = new System.Drawing.Size(163, 75); this.GB_OT.TabIndex = 67; this.GB_OT.TabStop = false; this.GB_OT.Text = "Trainer Information"; @@ -389,7 +391,7 @@ private void InitializeComponent() // L_Victory // this.L_Victory.AutoSize = true; - this.L_Victory.Location = new System.Drawing.Point(300, 15); + this.L_Victory.Location = new System.Drawing.Point(7, 25); this.L_Victory.Name = "L_Victory"; this.L_Victory.Size = new System.Drawing.Size(82, 13); this.L_Victory.TabIndex = 68; @@ -398,10 +400,10 @@ private void InitializeComponent() // TB_VN // this.TB_VN.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.TB_VN.Location = new System.Drawing.Point(388, 12); + this.TB_VN.Location = new System.Drawing.Point(95, 22); this.TB_VN.Mask = "000"; this.TB_VN.Name = "TB_VN"; - this.TB_VN.Size = new System.Drawing.Size(30, 20); + this.TB_VN.Size = new System.Drawing.Size(32, 20); this.TB_VN.TabIndex = 6; this.TB_VN.Text = "000"; this.TB_VN.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; @@ -411,20 +413,20 @@ private void InitializeComponent() // this.CAL_MetDate.CustomFormat = "MM/dd/yyyy"; this.CAL_MetDate.Format = System.Windows.Forms.DateTimePickerFormat.Short; - this.CAL_MetDate.Location = new System.Drawing.Point(496, 12); + this.CAL_MetDate.Location = new System.Drawing.Point(203, 22); this.CAL_MetDate.MaxDate = new System.DateTime(2099, 12, 31, 0, 0, 0, 0); this.CAL_MetDate.MinDate = new System.DateTime(2000, 1, 1, 0, 0, 0, 0); this.CAL_MetDate.Name = "CAL_MetDate"; - this.CAL_MetDate.Size = new System.Drawing.Size(100, 20); + this.CAL_MetDate.Size = new System.Drawing.Size(102, 20); this.CAL_MetDate.TabIndex = 70; this.CAL_MetDate.Value = new System.DateTime(2000, 1, 1, 0, 0, 0, 0); this.CAL_MetDate.ValueChanged += new System.EventHandler(this.Write_Entry); // // Label_MetDate // - this.Label_MetDate.Location = new System.Drawing.Point(441, 15); + this.Label_MetDate.Location = new System.Drawing.Point(148, 25); this.Label_MetDate.Name = "Label_MetDate"; - this.Label_MetDate.Size = new System.Drawing.Size(55, 13); + this.Label_MetDate.Size = new System.Drawing.Size(57, 13); this.Label_MetDate.TabIndex = 69; this.Label_MetDate.Text = "Date:"; this.Label_MetDate.TextAlign = System.Drawing.ContentAlignment.MiddleRight; @@ -432,7 +434,7 @@ private void InitializeComponent() // B_Cancel // this.B_Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.B_Cancel.Location = new System.Drawing.Point(447, 270); + this.B_Cancel.Location = new System.Drawing.Point(460, 291); this.B_Cancel.Name = "B_Cancel"; this.B_Cancel.Size = new System.Drawing.Size(76, 23); this.B_Cancel.TabIndex = 71; @@ -443,9 +445,9 @@ private void InitializeComponent() // Label_Gender // this.Label_Gender.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Label_Gender.Location = new System.Drawing.Point(363, 138); + this.Label_Gender.Location = new System.Drawing.Point(70, 148); this.Label_Gender.Name = "Label_Gender"; - this.Label_Gender.Size = new System.Drawing.Size(16, 13); + this.Label_Gender.Size = new System.Drawing.Size(18, 13); this.Label_Gender.TabIndex = 72; this.Label_Gender.Text = "-"; this.Label_Gender.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; @@ -457,16 +459,16 @@ private void InitializeComponent() this.CB_Form.DropDownWidth = 85; this.CB_Form.Enabled = false; this.CB_Form.FormattingEnabled = true; - this.CB_Form.Location = new System.Drawing.Point(483, 123); + this.CB_Form.Location = new System.Drawing.Point(190, 133); this.CB_Form.Name = "CB_Form"; - this.CB_Form.Size = new System.Drawing.Size(122, 21); + this.CB_Form.Size = new System.Drawing.Size(124, 21); this.CB_Form.TabIndex = 74; this.CB_Form.SelectedIndexChanged += new System.EventHandler(this.Write_Entry); // // Label_Form // this.Label_Form.AutoSize = true; - this.Label_Form.Location = new System.Drawing.Point(447, 126); + this.Label_Form.Location = new System.Drawing.Point(154, 136); this.Label_Form.Name = "Label_Form"; this.Label_Form.Size = new System.Drawing.Size(33, 13); this.Label_Form.TabIndex = 73; @@ -475,7 +477,7 @@ private void InitializeComponent() // CHK_Shiny // this.CHK_Shiny.AutoSize = true; - this.CHK_Shiny.Location = new System.Drawing.Point(347, 139); + this.CHK_Shiny.Location = new System.Drawing.Point(54, 149); this.CHK_Shiny.Name = "CHK_Shiny"; this.CHK_Shiny.Size = new System.Drawing.Size(15, 14); this.CHK_Shiny.TabIndex = 75; @@ -485,7 +487,7 @@ private void InitializeComponent() // L_Shiny // this.L_Shiny.AutoSize = true; - this.L_Shiny.Location = new System.Drawing.Point(305, 138); + this.L_Shiny.Location = new System.Drawing.Point(12, 148); this.L_Shiny.Name = "L_Shiny"; this.L_Shiny.Size = new System.Drawing.Size(36, 13); this.L_Shiny.TabIndex = 76; @@ -494,10 +496,10 @@ private void InitializeComponent() // TB_Level // this.TB_Level.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.TB_Level.Location = new System.Drawing.Point(347, 157); + this.TB_Level.Location = new System.Drawing.Point(54, 167); this.TB_Level.Mask = "000"; this.TB_Level.Name = "TB_Level"; - this.TB_Level.Size = new System.Drawing.Size(30, 20); + this.TB_Level.Size = new System.Drawing.Size(32, 20); this.TB_Level.TabIndex = 77; this.TB_Level.Text = "001"; this.TB_Level.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; @@ -506,7 +508,7 @@ private void InitializeComponent() // L_Level // this.L_Level.AutoSize = true; - this.L_Level.Location = new System.Drawing.Point(305, 159); + this.L_Level.Location = new System.Drawing.Point(12, 169); this.L_Level.Name = "L_Level"; this.L_Level.Size = new System.Drawing.Size(36, 13); this.L_Level.TabIndex = 78; @@ -514,8 +516,8 @@ private void InitializeComponent() // // B_CopyText // - this.B_CopyText.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.B_CopyText.Location = new System.Drawing.Point(7, 280); + this.B_CopyText.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.B_CopyText.Location = new System.Drawing.Point(3, 301); this.B_CopyText.Name = "B_CopyText"; this.B_CopyText.Size = new System.Drawing.Size(59, 23); this.B_CopyText.TabIndex = 79; @@ -525,8 +527,8 @@ private void InitializeComponent() // // B_Delete // - this.B_Delete.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.B_Delete.Location = new System.Drawing.Point(7, 256); + this.B_Delete.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); + this.B_Delete.Location = new System.Drawing.Point(3, 277); this.B_Delete.Name = "B_Delete"; this.B_Delete.Size = new System.Drawing.Size(59, 23); this.B_Delete.TabIndex = 80; @@ -534,45 +536,53 @@ private void InitializeComponent() this.B_Delete.UseVisualStyleBackColor = true; this.B_Delete.Click += new System.EventHandler(this.B_Delete_Click); // + // groupBox1 + // + this.groupBox1.Controls.Add(this.L_Victory); + this.groupBox1.Controls.Add(this.bpkx); + this.groupBox1.Controls.Add(this.NUP_PartyIndex); + this.groupBox1.Controls.Add(this.TB_Level); + this.groupBox1.Controls.Add(this.L_PartyNum); + this.groupBox1.Controls.Add(this.L_Level); + this.groupBox1.Controls.Add(this.Label_Species); + this.groupBox1.Controls.Add(this.L_Shiny); + this.groupBox1.Controls.Add(this.CB_Species); + this.groupBox1.Controls.Add(this.CHK_Shiny); + this.groupBox1.Controls.Add(this.TB_Nickname); + this.groupBox1.Controls.Add(this.CB_Form); + this.groupBox1.Controls.Add(this.CHK_Nicknamed); + this.groupBox1.Controls.Add(this.Label_Form); + this.groupBox1.Controls.Add(this.Label_EncryptionConstant); + this.groupBox1.Controls.Add(this.Label_Gender); + this.groupBox1.Controls.Add(this.TB_EC); + this.groupBox1.Controls.Add(this.GB_CurrentMoves); + this.groupBox1.Controls.Add(this.CAL_MetDate); + this.groupBox1.Controls.Add(this.CB_HeldItem); + this.groupBox1.Controls.Add(this.Label_MetDate); + this.groupBox1.Controls.Add(this.Label_HeldItem); + this.groupBox1.Controls.Add(this.TB_VN); + this.groupBox1.Controls.Add(this.GB_OT); + this.groupBox1.Location = new System.Drawing.Point(299, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(323, 315); + this.groupBox1.TabIndex = 81; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Entry"; + // // SAV_HallOfFame // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(604, 301); + this.ClientSize = new System.Drawing.Size(621, 326); this.Controls.Add(this.B_Delete); this.Controls.Add(this.B_CopyText); - this.Controls.Add(this.TB_Level); - this.Controls.Add(this.L_Level); - this.Controls.Add(this.L_Shiny); - this.Controls.Add(this.CHK_Shiny); - this.Controls.Add(this.CB_Form); - this.Controls.Add(this.Label_Form); - this.Controls.Add(this.Label_Gender); this.Controls.Add(this.B_Cancel); - this.Controls.Add(this.CAL_MetDate); - this.Controls.Add(this.Label_MetDate); - this.Controls.Add(this.TB_VN); - this.Controls.Add(this.L_Victory); - this.Controls.Add(this.GB_OT); - this.Controls.Add(this.Label_HeldItem); - this.Controls.Add(this.CB_HeldItem); - this.Controls.Add(this.GB_CurrentMoves); - this.Controls.Add(this.TB_EC); - this.Controls.Add(this.Label_EncryptionConstant); - this.Controls.Add(this.CHK_Nicknamed); - this.Controls.Add(this.TB_Nickname); - this.Controls.Add(this.CB_Species); - this.Controls.Add(this.Label_Species); - this.Controls.Add(this.L_PartyNum); - this.Controls.Add(this.NUP_PartyIndex); - this.Controls.Add(this.bpkx); this.Controls.Add(this.B_Close); this.Controls.Add(this.RTB); this.Controls.Add(this.LB_DataEntry); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Controls.Add(this.groupBox1); this.Icon = global::PKHeX.WinForms.Properties.Resources.Icon; this.MaximizeBox = false; - this.MaximumSize = new System.Drawing.Size(620, 340); this.MinimizeBox = false; this.MinimumSize = new System.Drawing.Size(620, 340); this.Name = "SAV_HallOfFame"; @@ -583,8 +593,9 @@ private void InitializeComponent() this.GB_CurrentMoves.ResumeLayout(false); this.GB_OT.ResumeLayout(false); this.GB_OT.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); this.ResumeLayout(false); - this.PerformLayout(); } @@ -630,5 +641,6 @@ private void InitializeComponent() private System.Windows.Forms.Label L_Level; private System.Windows.Forms.Button B_CopyText; private System.Windows.Forms.Button B_Delete; + private System.Windows.Forms.GroupBox groupBox1; } } \ No newline at end of file diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs index 5c9f658d6..b2f4623be 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_HallOfFame.cs @@ -22,33 +22,6 @@ public SAV_HallOfFame(SaveFile sav) Array.Copy(SAV.Data, SAV.HoF, data, 0, data.Length); //Copy HoF section of save into Data Setup(); - editor_spec = new Control[]{ - GB_OT, - GB_CurrentMoves, - CB_Species, - CB_HeldItem, - TB_EC, - TB_VN, - CAL_MetDate, - CHK_Nicknamed, - CHK_Shiny, - L_PartyNum, - L_Victory, - L_Shiny, - L_Level, - Label_TID, - Label_Form, - Label_Gender, - Label_HeldItem, - Label_OT, - Label_TID, - Label_SID, - Label_Species, - TB_Level, - NUP_PartyIndex, - Label_EncryptionConstant, - Label_MetDate, - }; LB_DataEntry.SelectedIndex = 0; NUP_PartyIndex_ValueChanged(null, EventArgs.Empty); try { TB_Nickname.Font = TB_OT.Font = FontUtil.GetPKXFont(11); } @@ -61,8 +34,6 @@ public SAV_HallOfFame(SaveFile sav) private readonly IReadOnlyList gendersymbols = Main.GenderSymbols; private readonly byte[] data = new byte[0x1B40]; - private readonly Control[] editor_spec; - private void Setup() { CB_Species.Items.Clear(); @@ -120,16 +91,14 @@ private void DisplayEntry(object sender, EventArgs e) if (day == 0) { s.Add("No records in this slot."); - foreach (Control t in editor_spec) - t.Enabled = false; + groupBox1.Enabled = false; editing = false; NUP_PartyIndex_ValueChanged(sender, e); } else { - foreach (Control t in editor_spec) - t.Enabled = true; + groupBox1.Enabled = true; var moncount = AddEntries(offset, s, year, month, day); if (sender != null) diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Link6.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Link6.cs index 295529e51..336d6f64c 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Link6.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Link6.cs @@ -9,42 +9,28 @@ namespace PKHeX.WinForms public partial class SAV_Link6 : Form { private readonly SaveFile Origin; - private readonly ILink SAV; + private readonly ISaveBlock6Main SAV; + + private PL6 LinkInfo; public SAV_Link6(SaveFile sav) { InitializeComponent(); WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage); - SAV = (ILink)(Origin = sav).Clone(); + SAV = (ISaveBlock6Main)(Origin = sav).Clone(); foreach (var cb in TAB_Items.Controls.OfType()) { cb.InitializeBinding(); cb.DataSource = new BindingSource(GameInfo.ItemDataSource.Where(item => item.Value <= sav.MaxItemID).ToArray(), null); } - byte[] data = SAV.LinkBlock; - if (data == null) - { - WinFormsUtil.Alert("Invalid save file / Link Information"); - Close(); - return; - } - data = data.Slice(0x1FF, PL6.Size); - LoadLinkData(data); + LinkInfo = SAV.LinkBlock.GetLinkInfo(); + LoadLinkData(); } - private PL6 LinkInfo; - private void B_Save_Click(object sender, EventArgs e) { - byte[] data = new byte[SAV.LinkBlock.Length]; - Array.Copy(LinkInfo.Data, 0, data, 0x1FF, LinkInfo.Data.Length); - - // Fix Checksum just in case. - ushort ccitt = Checksums.CRC16_CCITT(data, 0x200, data.Length - 4 - 0x200); // [app,chk) - BitConverter.GetBytes(ccitt).CopyTo(data, data.Length - 4); - - SAV.LinkBlock = data; - Origin.SetData(((SaveFile)SAV).Data, 0); + SAV.LinkBlock.SetLinkInfo(LinkInfo); + Origin.CopyChangesFrom((SaveFile)SAV); Close(); } @@ -63,8 +49,9 @@ private void B_Import_Click(object sender, EventArgs e) { WinFormsUtil.Alert("Invalid file length"); return; } byte[] data = File.ReadAllBytes(ofd.FileName); + LinkInfo = new PL6(data); - LoadLinkData(data); + LoadLinkData(); B_Export.Enabled = true; } @@ -81,10 +68,8 @@ private void B_Export_Click(object sender, EventArgs e) WinFormsUtil.Alert("Pokémon Link data saved to:" + Environment.NewLine + sfd.FileName); } - private void LoadLinkData(byte[] data) + private void LoadLinkData() { - LinkInfo = new PL6(data); - RTB_LinkSource.Text = LinkInfo.Origin; CHK_LinkAvailable.Checked = LinkInfo.PL_enabled; diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_PokedexXY.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_PokedexXY.cs index 5977386e9..ad726646c 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_PokedexXY.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_PokedexXY.cs @@ -16,7 +16,7 @@ public SAV_PokedexXY(SaveFile sav) InitializeComponent(); WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage); SAV = (SAV6XY)(Origin = sav).Clone(); - Zukan = (Zukan6XY)SAV.Zukan; + Zukan = SAV.Blocks.Zukan; CP = new[] { CHK_P1, CHK_P2, CHK_P3, CHK_P4, CHK_P5, CHK_P6, CHK_P7, CHK_P8, CHK_P9, }; CL = new[] { CHK_L1, CHK_L2, CHK_L3, CHK_L4, CHK_L5, CHK_L6, CHK_L7, }; diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.Designer.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.Designer.cs index aee00d105..52f7cdfb2 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.Designer.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.Designer.cs @@ -28,6 +28,7 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.B_Cancel = new System.Windows.Forms.Button(); this.B_Save = new System.Windows.Forms.Button(); this.TB_OTName = new System.Windows.Forms.TextBox(); @@ -154,6 +155,8 @@ private void InitializeComponent() this.PG_CurrentAppearance = new System.Windows.Forms.PropertyGrid(); this.L_TRNick = new System.Windows.Forms.Label(); this.TB_TRNick = new System.Windows.Forms.TextBox(); + this.Tip1 = new System.Windows.Forms.ToolTip(this.components); + this.Tip2 = new System.Windows.Forms.ToolTip(this.components); this.GB_Sayings.SuspendLayout(); this.GB_MaisonBest.SuspendLayout(); this.GB_MaisonCurrent.SuspendLayout(); @@ -1725,5 +1728,7 @@ private void InitializeComponent() private Subforms.Save_Editors.TrainerStat TrainerStats; private System.Windows.Forms.PropertyGrid PG_CurrentAppearance; private System.Windows.Forms.CheckBox CHK_MegaRayquazaUnlocked; + private System.Windows.Forms.ToolTip Tip1; + private System.Windows.Forms.ToolTip Tip2; } } diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.cs index 9bc36ba50..bf74e096a 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.cs @@ -69,7 +69,6 @@ public SAV_Trainer(SaveFile sav) } private readonly bool editing; - private readonly ToolTip Tip1 = new ToolTip(), Tip2 = new ToolTip(); private readonly MaskedTextBox[] MaisonRecords; private readonly CheckBox[] cba; private bool MapUpdated; @@ -172,7 +171,7 @@ private void GetTextBoxes() if (SAV is SAV6XY xy) { - var xystat = ((MyStatus6XY) xy.Status); + var xystat = (MyStatus6XY)xy.Status; PG_CurrentAppearance.SelectedObject = xystat.Fashion; TB_TRNick.Text = xystat.OT_Nick; } @@ -330,7 +329,7 @@ private void ChangeFFFF(object sender, EventArgs e) private void GiveAllAccessories(object sender, EventArgs e) { if (SAV is SAV6XY xy) - xy.UnlockAllAccessories(); + xy.Blocks.Fashion6XY.UnlockAllAccessories(); } private void UpdateCountry(object sender, EventArgs e) diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_FestivalPlaza.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_FestivalPlaza.cs index fa25b7140..a8553b941 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_FestivalPlaza.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_FestivalPlaza.cs @@ -301,7 +301,7 @@ private void LoadBattleAgency() var m = (int)NUD_Trainers[i].Maximum; NUD_Trainers[i].Value = (uint)j > m ? m : j; } - B_AgentGlass.Enabled = (SAV.GetData(SAV.Fashion + 0xD0, 1)[0] & 1) == 0; + B_AgentGlass.Enabled = (SAV.GetData(SAV.FashionBlock.Offset + 0xD0, 1)[0] & 1) == 0; } private void LoadPictureBox() @@ -733,7 +733,7 @@ private void B_AgentGlass_Click(object sender, EventArgs e) { if (NUD_Grade.Value < 30 && DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Agent Sunglasses is reward of Grade 30.", "Continue?")) return; - SAV.SetData(new byte[] { 3 }, SAV.Fashion + 0xD0); + SAV.SetData(new byte[] { 3 }, SAV.FashionBlock.Offset + 0xD0); B_AgentGlass.Enabled = false; System.Media.SystemSounds.Asterisk.Play(); } diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_PokedexGG.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_PokedexGG.cs index bdc49f0e0..9939a6254 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_PokedexGG.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_PokedexGG.cs @@ -29,7 +29,7 @@ public SAV_PokedexGG(SaveFile sav) CB_Species.InitializeBinding(); CB_Species.DataSource = new BindingSource(GameInfo.SpeciesDataSource.Skip(1).ToList(), null); - Dex = SAV.Zukan; + Dex = SAV.Blocks.Zukan; var Species = GameInfo.Strings.Species; var names = Dex.GetEntryNames(Species); diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7.cs index e31f93f03..63b063865 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7.cs @@ -534,13 +534,13 @@ private void B_Fashion_Click(object sender, EventArgs e) byte[] data1 = SAV is SAV7USUM ? SAV.Gender == 0 ? Properties.Resources.fashion_m_uu : Properties.Resources.fashion_f_uu : SAV.Gender == 0 ? Properties.Resources.fashion_m_sm : Properties.Resources.fashion_f_sm; - SAV.SetData(data1, SAV.Fashion); + SAV.SetData(data1, SAV.FashionBlock.Offset); break; case 2: // Everything byte[] data2 = SAV is SAV7USUM ? SAV.Gender == 0 ? Properties.Resources.fashion_m_uu_illegal : Properties.Resources.fashion_f_uu_illegal : SAV.Gender == 0 ? Properties.Resources.fashion_m_sm_illegal : Properties.Resources.fashion_f_sm_illegal; - SAV.SetData(data2, SAV.Fashion); + SAV.SetData(data2, SAV.FashionBlock.Offset); break; default: return; diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7GG.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7GG.cs index a4438a722..204f81e39 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7GG.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7GG.cs @@ -65,9 +65,9 @@ private void LoadTrainerInfo() { // Get Data TB_OTName.Text = SAV.OT; - TB_RivalName.Text = SAV.Misc.Rival; + TB_RivalName.Text = SAV.Blocks.Misc.Rival; CB_Language.SelectedValue = SAV.Language; - MT_Money.Text = SAV.Misc.Money.ToString(); + MT_Money.Text = SAV.Blocks.Misc.Money.ToString(); CB_Game.SelectedValue = SAV.Game; CB_Gender.SelectedIndex = SAV.Gender; @@ -93,7 +93,7 @@ private void SaveTrainerInfo() SAV.Language = WinFormsUtil.GetIndex(CB_Language); SAV.OT = TB_OTName.Text; - SAV.Misc.Rival = TB_RivalName.Text; + SAV.Blocks.Misc.Rival = TB_RivalName.Text; // Save PlayTime SAV.PlayedHours = ushort.Parse(MT_Hours.Text); diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_PokedexSWSH.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_PokedexSWSH.cs index 03c096dff..166ac91a1 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_PokedexSWSH.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_PokedexSWSH.cs @@ -8,15 +8,15 @@ namespace PKHeX.WinForms { public partial class SAV_PokedexSWSH : Form { - private readonly SaveFile Origin; - private readonly SAV8 SAV; + private readonly SAV8SWSH Origin; + private readonly SAV8SWSH SAV; - public SAV_PokedexSWSH(SaveFile sav) + public SAV_PokedexSWSH(SAV8SWSH sav) { InitializeComponent(); WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage); - SAV = (SAV8)(Origin = sav).Clone(); - Dex = SAV.Zukan; + SAV = (SAV8SWSH)(Origin = sav).Clone(); + Dex = SAV.Blocks.Zukan; CP = new[] { CHK_P1, CHK_P2, CHK_P3, CHK_P4, CHK_P5, CHK_P6, CHK_P7, CHK_P8, CHK_P9, }; CL = new[] { CHK_L1, CHK_L2, CHK_L3, CHK_L4, CHK_L5, CHK_L6, CHK_L7, CHK_L8, CHK_L9, }; diff --git a/PKHeX.WinForms/Subforms/Save Editors/SAV_EventWork.cs b/PKHeX.WinForms/Subforms/Save Editors/SAV_EventWork.cs index 4d89d2237..931fb69b3 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/SAV_EventWork.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/SAV_EventWork.cs @@ -20,10 +20,9 @@ public SAV_EventWork(SaveFile sav) WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage); if (sav is SAV7b s7b) - SAV = s7b.EventWork; + SAV = s7b.Blocks.EventWork; else if (sav is SAV8SWSH s8ss) - SAV = s8ss.EventWork; - SAV = ((SAV7b) sav).EventWork; + SAV = s8ss.Blocks.EventWork; Origin = sav; DragEnter += Main_DragEnter; diff --git a/PKHeX.WinForms/Subforms/Save Editors/SAV_MailBox.cs b/PKHeX.WinForms/Subforms/Save Editors/SAV_MailBox.cs index 72a10e108..18c2d648f 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/SAV_MailBox.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/SAV_MailBox.cs @@ -69,7 +69,11 @@ public SAV_MailBox(SaveFile sav) case SAV3 sav3: m = new Mail3[6 + 10]; for (int i = 0; i < m.Length; i++) - m[i] = new Mail3(sav3, i); + { + var ofs = sav3.GetMailOffset(i); + var data = sav.GetData(ofs, Mail3.SIZE); + m[i] = new Mail3(data, ofs, sav3.Japanese); + } MailItemID = Enumerable.Range(0x79, 12).ToArray(); PartyBoxCount = 6; @@ -79,8 +83,11 @@ public SAV_MailBox(SaveFile sav) for (int i = 0; i < p.Count; i++) m[i] = new Mail4(((PK4)p[i]).HeldMailData); for (int i = p.Count, j = 0; i < m.Length; i++, j++) - m[i] = new Mail4(sav4, j); - var l4 = m.Last() as Mail4; + { + int ofs = sav4.GetMailOffset(j); + m[i] = new Mail4(sav4.GetMailData(ofs), ofs); + } + var l4 = (Mail4)m.Last(); ResetVer = l4.AuthorVersion; ResetLang = l4.AuthorLanguage; MailItemID = Enumerable.Range(0x89, 12).ToArray(); @@ -91,8 +98,12 @@ public SAV_MailBox(SaveFile sav) for (int i = 0; i < p.Count; i++) m[i] = new Mail5(((PK5)p[i]).HeldMailData); for (int i = p.Count, j = 0; i < m.Length; i++, j++) - m[i] = new Mail5(sav5, j); - var l5 = m.Last() as Mail5; + { + int ofs = sav5.GetMailOffset(j); + var data = sav5.GetMailData(ofs); + m[i] = new Mail5(data, ofs); + } + var l5 = (Mail5)m.Last(); ResetVer = l5.AuthorVersion; ResetLang = l5.AuthorLanguage; MailItemID = Enumerable.Range(0x89, 12).ToArray(); diff --git a/PKHeX.WinForms/Subforms/Save Editors/SAV_Wondercard.cs b/PKHeX.WinForms/Subforms/Save Editors/SAV_Wondercard.cs index 2bf082ea2..d1147defe 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/SAV_Wondercard.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/SAV_Wondercard.cs @@ -15,7 +15,7 @@ public partial class SAV_Wondercard : Form private readonly SaveFile Origin; private readonly SaveFile SAV; - public SAV_Wondercard(SaveFile sav, MysteryGift g = null) + public SAV_Wondercard(SaveFile sav, DataMysteryGift g = null) { InitializeComponent(); WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage); @@ -61,7 +61,7 @@ public SAV_Wondercard(SaveFile sav, MysteryGift g = null) } private readonly MysteryGiftAlbum mga; - private MysteryGift mg; + private DataMysteryGift mg; private readonly PictureBox[] pba; // Repopulation Functions @@ -80,7 +80,7 @@ private void SetGiftBoxes() } } - private void ViewGiftData(MysteryGift g) + private void ViewGiftData(DataMysteryGift g) { try { @@ -129,7 +129,7 @@ private void B_Import_Click(object sender, EventArgs e) if (import.ShowDialog() != DialogResult.OK) return; string path = import.FileName; - MysteryGift g = MysteryGift.GetMysteryGift(File.ReadAllBytes(path), Path.GetExtension(path)); + var g = MysteryGift.GetMysteryGift(File.ReadAllBytes(path), Path.GetExtension(path)); if (g == null) { WinFormsUtil.Error(MsgMysteryGiftInvalid, path); @@ -191,7 +191,7 @@ private void ClickSet(object sender, EventArgs e) return; } SetBackground(index, Properties.Resources.slotSet); - mga.Gifts[index] = mg.Clone(); + mga.Gifts[index] = (DataMysteryGift)mg.Clone(); SetGiftBoxes(); SetCardID(mg.CardID); } @@ -201,7 +201,8 @@ private void ClickDelete(object sender, EventArgs e) var pb = WinFormsUtil.GetUnderlyingControl(sender); int index = Array.IndexOf(pba, pb); - mga.Gifts[index].Data = new byte[mga.Gifts[index].Data.Length]; + var arr = mga.Gifts[index].Data; + Array.Clear(arr, 0, arr.Length); // Shuffle blank card down int i = index; @@ -237,7 +238,7 @@ private void B_Save_Click(object sender, EventArgs e) foreach (var o in LB_Received.Items) flags[Util.ToUInt32(o.ToString())] = true; - mga.Flags = flags; + flags.CopyTo(mga.Flags, 0); SAV.GiftAlbum = mga; Origin.CopyChangesFrom(SAV); @@ -305,7 +306,7 @@ private void ClickQR(object sender, EventArgs e) private void ExportQRFromView() { - if (mg.Data.All(z => z == 0)) + if (mg.Empty) { WinFormsUtil.Alert(MsgMysteryGiftSlotNone); return; @@ -339,7 +340,7 @@ private void ImportQRToView(string url) return; string[] types = mga.Gifts.Select(g => g.Type).Distinct().ToArray(); - MysteryGift gift = MysteryGift.GetMysteryGift(data); + var gift = MysteryGift.GetMysteryGift(data); string giftType = gift.Type; if (mga.Gifts.All(card => card.Data.Length != data.Length)) @@ -416,15 +417,15 @@ private void BoxSlot_DragDrop(object sender, DragEventArgs e) return; } SetBackground(index, Properties.Resources.slotSet); - mga.Gifts[index] = gift.Clone(); + mga.Gifts[index] = (DataMysteryGift)gift.Clone(); SetCardID(mga.Gifts[index].CardID); ViewGiftData(mga.Gifts[index]); } else // Swap Data { - MysteryGift s1 = mga.Gifts[index]; - MysteryGift s2 = mga.Gifts[wc_slot]; + DataMysteryGift s1 = mga.Gifts[index]; + DataMysteryGift s2 = mga.Gifts[wc_slot]; if (s2 is PCD && s1 is PGT) { diff --git a/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.Designer.cs b/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.Designer.cs index 587cb5d01..f75e985f0 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.Designer.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.Designer.cs @@ -28,10 +28,12 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.NUD_Stat = new System.Windows.Forms.NumericUpDown(); this.L_Offset = new System.Windows.Forms.Label(); this.L_Value = new System.Windows.Forms.Label(); this.CB_Stats = new System.Windows.Forms.ComboBox(); + this.Tip = new System.Windows.Forms.ToolTip(this.components); ((System.ComponentModel.ISupportInitialize)(this.NUD_Stat)).BeginInit(); this.SuspendLayout(); // @@ -100,5 +102,6 @@ private void InitializeComponent() private System.Windows.Forms.Label L_Offset; private System.Windows.Forms.Label L_Value; private System.Windows.Forms.ComboBox CB_Stats; + private System.Windows.Forms.ToolTip Tip; } } diff --git a/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.cs b/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.cs index f4e27c010..7702f688e 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.cs @@ -9,7 +9,6 @@ namespace PKHeX.WinForms.Subforms.Save_Editors public partial class TrainerStat : UserControl { public TrainerStat() => InitializeComponent(); - private readonly ToolTip Tip = new ToolTip(); private bool Editing; private ITrainerStatRecord SAV; private Dictionary RecordList; // index, description diff --git a/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.resx b/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.resx index 1af7de150..c0adda1ac 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.resx +++ b/PKHeX.WinForms/Subforms/Save Editors/TrainerStat.resx @@ -117,4 +117,7 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + \ No newline at end of file diff --git a/PKHeX.WinForms/Util/FontUtil.cs b/PKHeX.WinForms/Util/FontUtil.cs index 891590429..a1938d24f 100644 --- a/PKHeX.WinForms/Util/FontUtil.cs +++ b/PKHeX.WinForms/Util/FontUtil.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Drawing; using System.Drawing.Text; @@ -30,8 +31,14 @@ static FontUtil() public static Font GetPKXFont(float size) { + if (GeneratedFonts.TryGetValue(size, out var f)) + return f; var family = CustomFonts.Families.Length == 0 ? FontFamily.GenericSansSerif : CustomFonts.Families[0]; - return new Font(family, size); + var font = new Font(family, size); + GeneratedFonts.Add(size, font); + return font; } + + private static readonly Dictionary GeneratedFonts = new Dictionary(); } } diff --git a/PKHeX.WinForms/Util/WinFormsUtil.cs b/PKHeX.WinForms/Util/WinFormsUtil.cs index d79dae12b..8376f6b12 100644 --- a/PKHeX.WinForms/Util/WinFormsUtil.cs +++ b/PKHeX.WinForms/Util/WinFormsUtil.cs @@ -361,7 +361,7 @@ private static void ExportSAV(SaveFile sav, string path) /// to be saved. /// Game the gift originates from /// Result of whether or not the file was saved. - public static bool ExportMGDialog(MysteryGift gift, GameVersion origin) + public static bool ExportMGDialog(DataMysteryGift gift, GameVersion origin) { using var sfd = new SaveFileDialog { diff --git a/Tests/PKHeX.Core.Tests/Legality/LegalityTests.cs b/Tests/PKHeX.Core.Tests/Legality/LegalityTests.cs index 2da53b9b8..b64b68f0f 100644 --- a/Tests/PKHeX.Core.Tests/Legality/LegalityTests.cs +++ b/Tests/PKHeX.Core.Tests/Legality/LegalityTests.cs @@ -48,11 +48,13 @@ private static void VerifyAll(string folder, string name, bool isValid) var data = File.ReadAllBytes(file); var format = PKX.GetPKMFormatFromExtension(file[file.Length - 1], -1); format.Should().BeLessOrEqualTo(PKX.Generation, "filename is expected to have a valid extension"); - var pkm = PKMConverter.GetPKMfromBytes(data, prefer: format); - pkm.Should().NotBeNull($"the PKM '{new FileInfo(file).Name}' should have been loaded"); ParseSettings.AllowGBCartEra = fi.DirectoryName.Contains("GBCartEra"); ParseSettings.AllowGen1Tradeback = fi.DirectoryName.Contains("1 Tradeback"); + var pkm = PKMConverter.GetPKMfromBytes(data, prefer: format); + pkm.Should().NotBeNull($"the PKM '{new FileInfo(file).Name}' should have been loaded"); + if (pkm == null) + continue; var legality = new LegalityAnalysis(pkm); legality.Valid.Should().Be(isValid, $"because the file '{fi.Directory.Name}\\{fi.Name}' should be {(isValid ? "Valid" : "Invalid")}"); ctr++; diff --git a/Tests/PKHeX.Core.Tests/Saves/PokeDex.cs b/Tests/PKHeX.Core.Tests/Saves/PokeDex.cs index cf999aab6..cced843d9 100644 --- a/Tests/PKHeX.Core.Tests/Saves/PokeDex.cs +++ b/Tests/PKHeX.Core.Tests/Saves/PokeDex.cs @@ -57,7 +57,7 @@ private static void CheckDexFlags5(SaveFile sav, int species, int form, int regi var formDex = dex + 8 + (regionSize * 9); int fc = sav.Personal[species].FormeCount; - var bit = ((SAV5)sav).Zukan.DexFormIndexFetcher(species, fc, 0); + var bit = ((SAV5)sav).Zukan.DexFormIndexFetcher(species, fc); if (bit < 0) return; bit += form;