diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index 99935ecf4..02155c017 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -964,10 +964,10 @@ public void TransferPropertiesWithReflection(PKM Source, PKM Destination) // Only transfer declared properties not defined in PKM.cs but in the actual type var SourceProperties = ReflectUtil.GetPropertiesCanWritePublicDeclared(Source.GetType()); var DestinationProperties = ReflectUtil.GetPropertiesCanWritePublicDeclared(Destination.GetType()); - foreach (string property in SourceProperties.Intersect(DestinationProperties)) + foreach (string property in SourceProperties.Intersect(DestinationProperties).Reverse()) { var prop = ReflectUtil.GetValue(this, property); - if (prop != null) + if (prop != null && !(prop is byte[])) ReflectUtil.SetValue(Destination, property, prop); } } diff --git a/PKHeX.Core/PKM/PKMConverter.cs b/PKHeX.Core/PKM/PKMConverter.cs index 795141df8..88f385050 100644 --- a/PKHeX.Core/PKM/PKMConverter.cs +++ b/PKHeX.Core/PKM/PKMConverter.cs @@ -16,6 +16,7 @@ public static class PKMConverter public static string OT_Name { get; private set; } = "PKHeX"; public static int OT_Gender { get; private set; } // Male public static int Language { get; private set; } = 1; // en + public static bool AllowIncompatibleConversion { private get; set; } public static void UpdateConfig(int SUBREGION, int COUNTRY, int _3DSREGION, string TRAINERNAME, int TRAINERGENDER, int LANGUAGE) { @@ -213,6 +214,21 @@ public static PKM ConvertToType(PKM pk, Type PKMType, out string comment) return pk; } + var pkm = ConvertPKM(pk, PKMType, fromType, out comment); + if (!AllowIncompatibleConversion || pkm != null) + return pkm; + + // Try Incompatible Conversion + pkm = GetBlank(PKMType); + TransferProperties(pk, pkm); + if (!SaveUtil.IsPKMCompatibleWithModifications(pkm)) + return null; + comment = "Converted via reflection."; + return pkm; + } + + private static PKM ConvertPKM(PKM pk, Type PKMType, Type fromType, out string comment) + { if (IsNotTransferrable(pk, out comment)) return null; @@ -226,6 +242,17 @@ public static PKM ConvertToType(PKM pk, Type PKMType, out string comment) return null; } + var pkm = ConvertPKM(pk, PKMType, fromType, toFormat, ref comment); + + comment = pkm == null + ? $"Cannot convert a {fromType.Name} to a {PKMType.Name}." + : $"Converted from {fromType.Name} to {PKMType.Name}."; + return pkm; + } + + + private static PKM ConvertPKM(PKM pk, Type PKMType, Type fromType, int toFormat, ref string comment) + { PKM pkm = pk.Clone(); if (pkm.IsEgg) ForceHatchPKM(pkm); @@ -246,7 +273,7 @@ public static PKM ConvertToType(PKM pk, Type PKMType, out string comment) if (pk.Species > 151) { comment = $"Cannot convert a {PKX.GetSpeciesName(pkm.Species, pkm.Japanese ? 1 : 2)} to {PKMType.Name}"; - return null; + return pkm; } pkm = ((PK2)pk).ConvertToPK1(); pkm.ClearInvalidMoves(); @@ -295,7 +322,7 @@ public static PKM ConvertToType(PKM pk, Type PKMType, out string comment) if (pkm.Species == 25 && pkm.AltForm != 0) // cosplay pikachu { comment = "Cannot transfer Cosplay Pikachu forward."; - return null; + return pkm; } pkm = ((PK6) pkm).ConvertToPK7(); if (toFormat == 7) @@ -304,11 +331,6 @@ public static PKM ConvertToType(PKM pk, Type PKMType, out string comment) case nameof(PK7): break; } - - comment = pkm == null - ? $"Cannot convert a {fromType.Name} to a {PKMType.Name}." - : $"Converted from {fromType.Name} to {PKMType.Name}."; - return pkm; } @@ -426,7 +448,8 @@ public static bool TryMakePKMCompatible(PKM pk, PKM target, out string c, out PK { pkm = null; c = $"Can't load {pk.GetType().Name}s to Gen{target.Format} saves."; - return false; + if (!AllowIncompatibleConversion) + return false; } if (target.Format < 3 && pk.Japanese != target.Japanese) { @@ -434,7 +457,8 @@ public static bool TryMakePKMCompatible(PKM pk, PKM target, out string c, out PK var strs = new[] { "International", "Japanese" }; var val = target.Japanese ? 0 : 1; c = $"Cannot load {strs[val]} {pk.GetType().Name}s to {strs[val ^ 1]} saves."; - return false; + if (!AllowIncompatibleConversion) + return false; } pkm = ConvertToType(pk, target.GetType(), out c); Debug.WriteLine(c); diff --git a/PKHeX.Core/Saves/SaveUtil.cs b/PKHeX.Core/Saves/SaveUtil.cs index 84ba95a44..bf7eec07e 100644 --- a/PKHeX.Core/Saves/SaveUtil.cs +++ b/PKHeX.Core/Saves/SaveUtil.cs @@ -1132,11 +1132,38 @@ public static bool IsPKMCompatibleWithModifications(SaveFile SAV, PKM pk) pk.ClearInvalidMoves(); if (pk.EVs.Any(ev => ev > SAV.MaxEV)) pk.EVs = pk.EVs.Select(ev => Math.Min(SAV.MaxEV, ev)).ToArray(); - if (pk.IVs.Any(ev => ev > SAV.MaxEV)) + if (pk.IVs.Any(iv => iv > SAV.MaxIV)) pk.IVs = pk.IVs.Select(iv => Math.Min(SAV.MaxIV, iv)).ToArray(); return true; } + /// + /// Checks if the is compatible with the input , and makes any necessary modifications to force compatibility. + /// + /// Should only be used when forcing a backwards conversion to sanitize the PKM fields to the target format. + /// If the PKM is compatible, some properties may be forced to sanitized values. + /// PKM input that is to be sanity checked. + /// Indication whether or not the PKM is compatible. + public static bool IsPKMCompatibleWithModifications(PKM pk) + { + if (pk.Species > pk.MaxSpeciesID) + return false; + + if (pk.HeldItem > pk.MaxItemID) + pk.HeldItem = 0; + if (pk.Nickname.Length > pk.NickLength) + pk.Nickname = pk.Nickname.Substring(0, pk.NickLength); + if (pk.OT_Name.Length > pk.OTLength) + pk.OT_Name = pk.OT_Name.Substring(0, pk.OTLength); + if (pk.Moves.Any(move => move > pk.MaxMoveID)) + pk.ClearInvalidMoves(); + if (pk.EVs.Any(ev => ev > pk.MaxEV)) + pk.EVs = pk.EVs.Select(ev => Math.Min(pk.MaxEV, ev)).ToArray(); + if (pk.IVs.Any(iv => iv > pk.MaxIV)) + pk.IVs = pk.IVs.Select(iv => Math.Min(pk.MaxIV, iv)).ToArray(); + + return true; + } /// /// Sets the details of a path to a object. diff --git a/PKHeX.WinForms/MainWindow/Main.cs b/PKHeX.WinForms/MainWindow/Main.cs index b1dd46972..91c1ab9cf 100644 --- a/PKHeX.WinForms/MainWindow/Main.cs +++ b/PKHeX.WinForms/MainWindow/Main.cs @@ -39,7 +39,10 @@ public Main() Show(); WindowState = FormWindowState.Normal; if (HaX) + { + PKMConverter.AllowIncompatibleConversion = true; WinFormsUtil.Alert("Illegal mode activated.", "Please behave."); + } else if (showChangelog) new About().ShowDialog(); @@ -100,8 +103,10 @@ private void FormLoadInitialSettings(string[] args, out bool showChangelog, out BAKprompt = false; CB_MainLanguage.Items.AddRange(main_langlist); - C_SAV.HaX = PKME_Tabs.HaX = HaX = args.Any(x => string.Equals(x.Trim('-'), nameof(HaX), StringComparison.CurrentCultureIgnoreCase)) + HaX = args.Any(x => string.Equals(x.Trim('-'), nameof(HaX), StringComparison.CurrentCultureIgnoreCase)) || Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName).EndsWith(nameof(HaX)); + + PKMConverter.AllowIncompatibleConversion = C_SAV.HaX = PKME_Tabs.HaX = HaX; PB_Legal.Visible = !HaX; int languageID = 1; // English