diff --git a/PKHeX/MainWindow/Main.cs b/PKHeX/MainWindow/Main.cs
index 0096f76c0..6c99d57fa 100644
--- a/PKHeX/MainWindow/Main.cs
+++ b/PKHeX/MainWindow/Main.cs
@@ -181,7 +181,7 @@ public Main()
if (path != null && File.Exists(path))
openQuick(path, force: true);
else
- loadSAV(SAV, null);
+ openSAV(SAV, null);
}
// Splash Screen closes on its own.
@@ -633,10 +633,7 @@ private void openQuick(string path, bool force = false)
}
private void openFile(byte[] input, string path, string ext)
{
- MysteryGift tg; PKM temp; string c;
- byte[] footer = new byte[0];
- byte[] header = new byte[0];
- SaveUtil.CheckHeaderFooter(ref input, ref header, ref footer);
+ SaveFile sav; MysteryGift tg; PKM temp; string c;
#region Powersaves Read-Only Conversion
if (input.Length == 0x10009C) // Resize to 1MB
{
@@ -661,23 +658,25 @@ private void openFile(byte[] input, string path, string ext)
if (BitConverter.ToUInt32(psdata, psdata.Length - 0x1F0) != SaveUtil.BEEF)
{ Util.Error("The data file is not a valid save file", path); return; }
- openSAV(psdata, path);
+ openSAV(new SAV6(psdata), path);
}
#endregion
#region SAV/PKM
- else if (SaveUtil.getSAVGeneration(input) != -1)
+ else if ((sav = SaveUtil.getVariantSAV(input)) != null)
{
- openSAV(input, path);
- SAV.Footer = footer;
- SAV.Header = header;
+ openSAV(sav, path);
}
else if ((temp = PKMConverter.getPKMfromBytes(input)) != null)
{
PKM pk = PKMConverter.convertToFormat(temp, SAV.PKMType, out c);
if (pk == null)
Util.Alert("Conversion failed.", c);
- else if (SAV.Generation < 3 && (pk is PK1 ? ((PK1)pk).Japanese : ((PK2)pk).Japanese) != SAV.GetJapanese)
- Util.Alert($"Cannot load {(SAV.GetJapanese ? "an International" : "a Japanese")} {pk.GetType().Name} in {(SAV.GetJapanese ? "a Japanese" : "an International")} save file.");
+ else if (SAV.Generation < 3 && ((pk as PK1)?.Japanese ?? ((PK2)pk).Japanese) != SAV.Japanese)
+ {
+ string a_lang = SAV.Japanese ? "an International" : "a Japanese";
+ string pk_type = pk.GetType().Name;
+ Util.Alert($"Cannot load {a_lang} {pk_type} in {a_lang} save file.");
+ }
else
populateFields(pk);
Console.WriteLine(c);
@@ -723,17 +722,11 @@ private void openFile(byte[] input, string path, string ext)
else if ((tg = MysteryGift.getMysteryGift(input, ext)) != null)
{
if (!tg.IsPokémon)
- {
- Util.Alert("Mystery Gift is not a Pokémon.", path);
- return;
- }
+ { Util.Alert("Mystery Gift is not a Pokémon.", path); return; }
+
temp = tg.convertToPKM(SAV);
- if (temp.Format == SAV.Generation && ModifierKeys == Keys.Control && SAV.HasWondercards)
- {
- B_OpenWondercards_Click(tg, null);
- return;
- }
PKM pk = PKMConverter.convertToFormat(temp, SAV.PKMType, out c);
+
if (pk == null)
Util.Alert("Conversion failed.", c);
else
@@ -784,7 +777,7 @@ private bool openXOR(byte[] input, string path)
// Save file is now decrypted!
// Trigger Loading of the decrypted save file.
- openSAV(decryptedPS, path);
+ openSAV(new SAV6(decryptedPS), path);
// Abort the opening of a non-cyber file.
return true;
@@ -793,47 +786,49 @@ private bool openXOR(byte[] input, string path)
if (xorpath != exepath || loop++ > 0) return false; // no xorpad compatible
xorpath = Path.GetDirectoryName(path); goto check;
}
- private void openSAV(byte[] input, string path)
+ private void openSAV(SaveFile sav, string path)
{
- SaveFile sav = SaveUtil.getVariantSAV(input);
if (sav == null || sav.Version == GameVersion.Invalid)
{ Util.Error("Invalid save file loaded. Aborting.", path); return; }
- if (sav.Generation == 3) // Japanese Save files are different. Get isJapanese
+
+ // Finish setting up the save file.
+ if (sav.IndeterminateGame && sav.Generation == 3)
{
- if (sav.Version == GameVersion.Unknown)
+ // Hacky cheats invalidated the Game Code value.
+ var drGame = Util.Prompt(MessageBoxButtons.YesNoCancel,
+ "Unknown Gen3 Game Detected. Select Origins:",
+ "Yes: Ruby / Sapphire" + Environment.NewLine +
+ "No: Emerald" + Environment.NewLine +
+ "Cancel: FireRed / LeafGreen");
+
+ switch (drGame) // Reset save file info
{
- // Hacky cheats invalidated the Game Code value.
- var drGame = Util.Prompt(MessageBoxButtons.YesNoCancel,
- "Unknown Gen3 Game Detected. Select Origins:",
- "Yes: Ruby / Sapphire" + Environment.NewLine +
- "No: Emerald" + Environment.NewLine +
- "Cancel: FireRed / LeafGreen");
-
- if (drGame == DialogResult.Yes)
- sav = new SAV3(sav.BAK, GameVersion.RS);
- else if (drGame == DialogResult.No)
- sav = new SAV3(sav.BAK, GameVersion.E);
- else
- sav = new SAV3(sav.BAK, GameVersion.FRLG);
- }
- var drJP = Util.Prompt(MessageBoxButtons.YesNoCancel, $"Generation 3 ({sav.Version}) Save File detected. Select Origins:", "Yes: International" + Environment.NewLine + "No: Japanese");
- if (drJP == DialogResult.Cancel)
- return;
- sav.Japanese = drJP == DialogResult.No;
-
- if (sav.Version == GameVersion.FRLG)
- {
- var drFRLG = Util.Prompt(MessageBoxButtons.YesNoCancel, $"{sav.Version} detected. Select version...", "Yes: FireRed" + Environment.NewLine + "No: LeafGreen");
- if (drFRLG == DialogResult.Cancel)
- return;
-
- sav.Personal = drFRLG == DialogResult.Yes ? PersonalTable.FR : PersonalTable.LG;
+ case DialogResult.Yes: sav = new SAV3(sav.BAK, GameVersion.RS); break;
+ case DialogResult.No: sav = new SAV3(sav.BAK, GameVersion.E); break;
+ case DialogResult.Cancel: sav = new SAV3(sav.BAK, GameVersion.FRLG); break;
+ default: return;
}
}
- loadSAV(sav, path);
- }
- private void loadSAV(SaveFile sav, string path)
- {
+ if (sav.IndeterminateLanguage)
+ {
+ // Japanese Save files are different. Get isJapanese
+ var drJP = Util.Prompt(MessageBoxButtons.YesNoCancel, $"{sav.Version} Save File detected. Select language...",
+ "Yes: International" + Environment.NewLine + "No: Japanese");
+ if (drJP == DialogResult.Cancel)
+ return;
+
+ sav.Japanese = drJP == DialogResult.No;
+ }
+ if (sav.IndeterminateSubVersion && sav.Version == GameVersion.FRLG)
+ {
+ var drFRLG = Util.Prompt(MessageBoxButtons.YesNoCancel, $"{sav.Version} detected. Select version...",
+ "Yes: FireRed" + Environment.NewLine + "No: LeafGreen");
+ if (drFRLG == DialogResult.Cancel)
+ return;
+
+ sav.Personal = drFRLG == DialogResult.Yes ? PersonalTable.FR : PersonalTable.LG;
+ }
+
// clean fields
PKM pk = preparePKM();
populateFields(SAV.BlankPKM);
@@ -2400,7 +2395,7 @@ private void updateOriginGame(object sender, EventArgs e)
GameVersion Version = (GameVersion)Util.getIndex(CB_GameOrigin);
// check if differs
- GameVersion newTrack = SaveUtil.getVersionGroup(Version);
+ GameVersion newTrack = SaveUtil.getMetLocationVersionGroup(Version);
if (newTrack != origintrack)
{
var met_list = getLocationList(Version, SAV.Generation, egg:false);
diff --git a/PKHeX/Saves/SAV3.cs b/PKHeX/Saves/SAV3.cs
index 835377a4e..61f9f22e7 100644
--- a/PKHeX/Saves/SAV3.cs
+++ b/PKHeX/Saves/SAV3.cs
@@ -157,6 +157,9 @@ public override byte[] Write(bool DSV)
// Configuration
public override SaveFile Clone() { return new SAV3(Write(DSV:false), Version); }
+ public override bool IndeterminateGame => Version == GameVersion.Unknown;
+ public override bool IndeterminateLanguage => true; // Unknown JP/International
+ public override bool IndeterminateSubVersion => Version == GameVersion.FRLG;
public override int SIZE_STORED => PKX.SIZE_3STORED;
public override int SIZE_PARTY => PKX.SIZE_3PARTY;
diff --git a/PKHeX/Saves/SaveFile.cs b/PKHeX/Saves/SaveFile.cs
index 4e00d1326..2a771a4c4 100644
--- a/PKHeX/Saves/SaveFile.cs
+++ b/PKHeX/Saves/SaveFile.cs
@@ -20,10 +20,11 @@ public abstract class SaveFile
public abstract string Filter { get; }
public byte[] Footer { protected get; set; } = new byte[0]; // .dsv
public byte[] Header { protected get; set; } = new byte[0]; // .gci
- public bool Japanese { protected get; set; }
+ public bool Japanese { get; set; }
public string PlayTimeString => $"{PlayedHours}ː{PlayedMinutes.ToString("00")}ː{PlayedSeconds.ToString("00")}"; // not :
-
- public bool GetJapanese => Japanese;
+ public virtual bool IndeterminateGame => false;
+ public virtual bool IndeterminateLanguage => false;
+ public virtual bool IndeterminateSubVersion => false;
// General PKM Properties
public abstract Type PKMType { get; }
@@ -367,7 +368,6 @@ public void setPartySlot(PKM pkm, int offset, bool? trade = null, bool? dex = nu
PartyCount = i + 1;
setData(pkm.EncryptedPartyData, offset);
- Console.WriteLine("");
Edited = true;
}
public virtual void setStoredSlot(PKM pkm, int offset, bool? trade = null, bool? dex = null)
diff --git a/PKHeX/Saves/SaveUtil.cs b/PKHeX/Saves/SaveUtil.cs
index 4c77a0861..3b80c2820 100644
--- a/PKHeX/Saves/SaveUtil.cs
+++ b/PKHeX/Saves/SaveUtil.cs
@@ -37,6 +37,9 @@ public enum GameVersion
ORASDEMO = 107,
ORAS = 108,
SM = 109,
+
+ // Extra Game Groupings (Generation)
+ Gen1, Gen2, Gen3, Gen4, Gen5, Gen6, Gen7
}
public static class SaveUtil
@@ -75,29 +78,33 @@ public static class SaveUtil
/// Determines the generation of the given save data.
/// Save data of which to determine the generation
/// Version Identifier or Invalid if type cannot be determined.
- public static int getSAVGeneration(byte[] data)
+ public static GameVersion getSAVGeneration(byte[] data)
{
if (getIsG1SAV(data) != GameVersion.Invalid)
- return 1;
+ return GameVersion.Gen1;
if (getIsG2SAV(data) != GameVersion.Invalid)
- return 2;
+ return GameVersion.Gen2;
if (getIsG3SAV(data) != GameVersion.Invalid)
- return 3;
- if (getIsG3COLOSAV(data) != GameVersion.Invalid)
- return (int)GameVersion.COLO;
- if (getIsG3XDSAV(data) != GameVersion.Invalid)
- return (int)GameVersion.XD;
- if (getIsG3BOXSAV(data) != GameVersion.Invalid)
- return (int)GameVersion.RSBOX;
+ return GameVersion.Gen3;
if (getIsG4SAV(data) != GameVersion.Invalid)
- return 4;
- if (getIsG4BRSAV(data) != GameVersion.Invalid)
- return (int) GameVersion.BATREV;
+ return GameVersion.Gen4;
if (getIsG5SAV(data) != GameVersion.Invalid)
- return 5;
+ return GameVersion.Gen5;
if (getIsG6SAV(data) != GameVersion.Invalid)
- return 6;
- return -1;
+ return GameVersion.Gen6;
+ if (getIsG7SAV(data) != GameVersion.Invalid)
+ return GameVersion.Gen7;
+
+ 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;
+
+ return GameVersion.Invalid;
}
/// Determines the type of 1st gen save
/// Save data of which to determine the type
@@ -400,11 +407,16 @@ public static GameVersion getIsG6SAV(byte[] data)
}
return GameVersion.Invalid;
}
+ public static GameVersion getIsG7SAV(byte[] data)
+ {
+ // return GameVersion.Gen7;
+ return GameVersion.Invalid;
+ }
/// Determines the Version Grouping of an input Version ID
/// Version of which to determine the group
/// Version Group Identifier or Invalid if type cannot be determined.
- public static GameVersion getVersionGroup(GameVersion Version)
+ public static GameVersion getMetLocationVersionGroup(GameVersion Version)
{
switch (Version)
{
@@ -466,31 +478,34 @@ public static GameVersion getVersionGroup(GameVersion Version)
/// An appropriate type of save file for the given data, or null if the save data is invalid.
public static SaveFile getVariantSAV(byte[] data)
{
+ // Pre-check for header/footer signatures
+ SaveFile sav;
+ byte[] header = new byte[0], footer = new byte[0];
+ CheckHeaderFooter(ref data, ref header, ref footer);
+
switch (getSAVGeneration(data))
{
- case 1:
- return new SAV1(data);
- case 2:
- return new SAV2(data);
- case 3:
- return new SAV3(data);
- case (int)GameVersion.RSBOX:
- return new SAV3RSBox(data);
- case (int)GameVersion.COLO:
- return new SAV3Colosseum(data);
- case (int)GameVersion.XD:
- return new SAV3XD(data);
- case 4:
- return new SAV4(data);
- case (int)GameVersion.BATREV:
- return new SAV4BR(data);
- case 5:
- return new SAV5(data);
- case 6:
- return new SAV6(data);
- default:
- return null;
+ // Main Games
+ case GameVersion.Gen1: sav = new SAV1(data); break;
+ case GameVersion.Gen2: sav = new SAV2(data); break;
+ case GameVersion.Gen3: sav = new SAV3(data); break;
+ case GameVersion.Gen4: sav = new SAV4(data); break;
+ case GameVersion.Gen5: sav = new SAV5(data); break;
+ case GameVersion.Gen6: sav = new SAV6(data); break;
+ //case GameVersion.Gen7: sav = new SAV7(data); break;
+
+ // Side Games
+ case GameVersion.COLO: sav = new SAV3Colosseum(data); break;
+ case GameVersion.XD: sav = new SAV3XD(data); break;
+ case GameVersion.RSBOX: sav = new SAV3RSBox(data); break;
+ case GameVersion.BATREV: sav = new SAV4BR(data); break;
+
+ // No pattern matched
+ default: return null;
}
+ sav.Header = header;
+ sav.Footer = footer;
+ return sav;
}
///
@@ -546,7 +561,7 @@ public static IEnumerable getSavesFromFolder(string folderPath, bool dee
}
///
- /// Determines whether the save data size is valid for 6th generation saves.
+ /// Determines whether the save data size is valid for autodetecting saves.
///
/// Size in bytes of the save data
/// A boolean indicating whether or not the save data size is valid.
@@ -554,13 +569,14 @@ public static bool SizeValidSAV(int size)
{
switch (size)
{
+ case SIZE_G3RAW:
+ case SIZE_G3RAWHALF:
+
+ case SIZE_G4RAW: // Gen4/5
+
case SIZE_G6XY:
case SIZE_G6ORASDEMO:
case SIZE_G6ORAS:
- case SIZE_G5B2W2:
- case SIZE_G4RAW:
- case SIZE_G3RAW:
- case SIZE_G3RAWHALF:
return true;
default:
return false;