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