mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-05-09 04:24:36 -05:00
* Detect encounter trades that evolve on trade and have not been evolved Detect generation 1 pokemon with special catch rates : krabby trade and Pokemon Stadium Detect generation 1 pokemon that evolve on trade and have been traded but not evolved Detect pokemon with tradeback status any but with only encounters from the other GB generation, that means they are WasTradeback Detect pokemon with moves from the other GB generation, change tradebackstatus to WasTradeback * Fix dppt surfing and fishing encounter type, is is surfing because the battle background is the same as other surfingfishing encounters Fix headbutt encounter type, the encounter type depends on the battle background used when battle a pokemon, for headbutt it changes with the player tile, is the player is in a city it will be building encounter, in a grass tile tall grass, in water it is surfingfishing and cave inside a cave. Some locations have more than one possible encounter type, for example routes with trees near the grass, near the water and near non-combat tiles. Also added slot type headbutt special for the special trees, those trees are all in routes and are only adjacent to non-combat tiles * Fix encounter type for missing areas with multiple grass encounters types: Mt Coronet, Mt Silver Cave and Stark Mountain (Issue # 1095) * Fixes and typos * Check for non-japanese e-reader pokemon, is unreleased
4678 lines
197 KiB
C#
4678 lines
197 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Media;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Windows.Forms;
|
|
using PKHeX.Core;
|
|
using PKHeX.Core.Properties;
|
|
using System.Configuration;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace PKHeX.WinForms
|
|
{
|
|
public partial class Main : Form
|
|
{
|
|
public Main()
|
|
{
|
|
#region Initialize Form
|
|
new Thread(() => new SplashScreen().ShowDialog()).Start();
|
|
DragInfo.slotPkmSource = SAV.BlankPKM.EncryptedPartyData;
|
|
InitializeComponent();
|
|
|
|
// Check for Updates
|
|
L_UpdateAvailable.Click += (sender, e) => Process.Start(ThreadPath);
|
|
new Thread(() =>
|
|
{
|
|
string data = NetUtil.getStringFromURL(VersionPath);
|
|
if (data == null)
|
|
return;
|
|
try
|
|
{
|
|
DateTime upd = DateTime.ParseExact(data, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None);
|
|
DateTime cur = DateTime.ParseExact(Resources.ProgramVersion, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None);
|
|
|
|
if (upd <= cur)
|
|
return;
|
|
|
|
string message = $"New Update Available! {upd:d}";
|
|
if (InvokeRequired)
|
|
try { Invoke((MethodInvoker) delegate { L_UpdateAvailable.Visible = true; L_UpdateAvailable.Text = message; }); }
|
|
catch { L_UpdateAvailable.Visible = true; L_UpdateAvailable.Text = message; }
|
|
else { L_UpdateAvailable.Visible = true; L_UpdateAvailable.Text = message; }
|
|
}
|
|
catch { }
|
|
}).Start();
|
|
|
|
setPKMFormatMode(SAV.Generation, SAV.Version);
|
|
|
|
// Set up form properties and arrays.
|
|
SlotPictureBoxes = new[] {
|
|
bpkx1, bpkx2, bpkx3, bpkx4, bpkx5, bpkx6,
|
|
bpkx7, bpkx8, bpkx9, bpkx10,bpkx11,bpkx12,
|
|
bpkx13,bpkx14,bpkx15,bpkx16,bpkx17,bpkx18,
|
|
bpkx19,bpkx20,bpkx21,bpkx22,bpkx23,bpkx24,
|
|
bpkx25,bpkx26,bpkx27,bpkx28,bpkx29,bpkx30,
|
|
|
|
ppkx1, ppkx2, ppkx3, ppkx4, ppkx5, ppkx6,
|
|
bbpkx1,bbpkx2,bbpkx3,bbpkx4,bbpkx5,bbpkx6,
|
|
|
|
dcpkx1, dcpkx2, gtspkx, fusedpkx,subepkx1,subepkx2,subepkx3,
|
|
};
|
|
relearnPB = new[] { PB_WarnRelearn1, PB_WarnRelearn2, PB_WarnRelearn3, PB_WarnRelearn4 };
|
|
movePB = new[] { PB_WarnMove1, PB_WarnMove2, PB_WarnMove3, PB_WarnMove4 };
|
|
Label_Species.ResetForeColor();
|
|
|
|
// Set up Language Selection
|
|
foreach (var cbItem in main_langlist)
|
|
CB_MainLanguage.Items.Add(cbItem);
|
|
|
|
// ToolTips for Drag&Drop
|
|
new ToolTip().SetToolTip(dragout, "PKM QuickSave");
|
|
|
|
// Box Drag & Drop
|
|
foreach (PictureBox pb in SlotPictureBoxes)
|
|
{
|
|
pb.AllowDrop = true; // The PictureBoxes have their own drag&drop event handlers (pbBoxSlot)
|
|
pb.GiveFeedback += (sender, e) => { e.UseDefaultCursors = false; };
|
|
}
|
|
dragout.GiveFeedback += (sender, e) => { e.UseDefaultCursors = false; };
|
|
GiveFeedback += (sender, e) => { e.UseDefaultCursors = false; };
|
|
foreach (TabPage tab in tabMain.TabPages)
|
|
{
|
|
tab.AllowDrop = true;
|
|
tab.DragDrop += tabMain_DragDrop;
|
|
tab.DragEnter += tabMain_DragEnter;
|
|
}
|
|
foreach (TabPage tab in tabBoxMulti.TabPages)
|
|
{
|
|
tab.AllowDrop = true;
|
|
tab.DragDrop += tabMain_DragDrop;
|
|
tab.DragEnter += tabMain_DragEnter;
|
|
}
|
|
|
|
GB_OT.Click += clickGT;
|
|
GB_nOT.Click += clickGT;
|
|
GB_Daycare.Click += switchDaycare;
|
|
GB_CurrentMoves.Click += clickMoves;
|
|
GB_RelearnMoves.Click += clickMoves;
|
|
|
|
TB_Nickname.Font = FontUtil.getPKXFont(11);
|
|
TB_OT.Font = (Font)TB_Nickname.Font.Clone();
|
|
TB_OTt2.Font = (Font)TB_Nickname.Font.Clone();
|
|
|
|
Menu_Modify.DropDown.Closing += (sender, e) =>
|
|
{
|
|
if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
|
|
e.Cancel = true;
|
|
};
|
|
Menu_Options.DropDown.Closing += (sender, e) =>
|
|
{
|
|
if (!Menu_Unicode.Selected)
|
|
return;
|
|
if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
|
|
e.Cancel = true;
|
|
};
|
|
|
|
// Box to Tabs D&D
|
|
dragout.AllowDrop = true;
|
|
|
|
FLP_SAVtools.Scroll += WinFormsUtil.PanelScroll;
|
|
|
|
// Add Legality check to right click context menus
|
|
// ToolStripItem can't be in multiple contextmenus, so put the item back when closing.
|
|
var cm = new[]{mnuV, mnuVSD};
|
|
foreach (var c in cm)
|
|
{
|
|
c.Opening += (sender, e) =>
|
|
{
|
|
var items = ((ContextMenuStrip)sender).Items;
|
|
if (ModifierKeys == Keys.Control)
|
|
items.Add(mnuLLegality);
|
|
else if (items.Contains(mnuLLegality))
|
|
items.Remove(mnuLLegality);
|
|
};
|
|
}
|
|
mnuL.Opening += (sender, e) =>
|
|
{
|
|
if (mnuL.Items[0] != mnuLLegality)
|
|
mnuL.Items.Insert(0, mnuLLegality);
|
|
};
|
|
|
|
// Load Event Databases
|
|
refreshMGDB();
|
|
|
|
#endregion
|
|
#region Localize & Populate Fields
|
|
string[] args = Environment.GetCommandLineArgs();
|
|
string filename = args.Length > 0 ? Path.GetFileNameWithoutExtension(args[0])?.ToLower() : "";
|
|
HaX = filename?.IndexOf("hax", StringComparison.Ordinal) >= 0;
|
|
|
|
bool showChangelog = false;
|
|
bool BAKprompt = false;
|
|
int languageID = 1; // English
|
|
try
|
|
{
|
|
ConfigUtil.checkConfig();
|
|
loadConfig(out BAKprompt, out showChangelog, out languageID);
|
|
}
|
|
catch (ConfigurationErrorsException e)
|
|
{
|
|
// Delete the settings if they exist
|
|
var settingsFilename = (e.InnerException as ConfigurationErrorsException)?.Filename;
|
|
if (!string.IsNullOrEmpty(settingsFilename) && File.Exists(settingsFilename))
|
|
deleteConfig(settingsFilename);
|
|
else
|
|
WinFormsUtil.Error("Unable to load settings.", e);
|
|
}
|
|
CB_MainLanguage.SelectedIndex = languageID;
|
|
|
|
InitializeFields();
|
|
|
|
#endregion
|
|
#region Load Initial File(s)
|
|
string pkmArg = null;
|
|
foreach (string arg in args.Skip(1)) // skip .exe
|
|
{
|
|
var fi = new FileInfo(arg);
|
|
if (!fi.Exists)
|
|
continue;
|
|
|
|
if (PKX.getIsPKM(fi.Length))
|
|
pkmArg = arg;
|
|
else
|
|
openQuick(arg, force: true);
|
|
}
|
|
if (!SAV.Exportable) // No SAV loaded from exe args
|
|
{
|
|
string path = null;
|
|
try
|
|
{
|
|
string cgse = "";
|
|
string pathCache = CyberGadgetUtil.GetCacheFolder();
|
|
if (Directory.Exists(pathCache))
|
|
cgse = Path.Combine(pathCache);
|
|
if (!SaveUtil.detectSaveFile(out path, cgse))
|
|
WinFormsUtil.Error(path);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ErrorWindow.ShowErrorDialog("An error occurred while attempting to auto-load your save file.", ex, true);
|
|
}
|
|
|
|
if (path != null && File.Exists(path))
|
|
openQuick(path, force: true);
|
|
else
|
|
{
|
|
openSAV(SAV, null);
|
|
SAV.Edited = false; // Prevents form close warning from showing until changes are made
|
|
}
|
|
}
|
|
if (pkmArg != null)
|
|
openQuick(pkmArg, force: true);
|
|
|
|
formInitialized = true; // Splash Screen closes on its own.
|
|
BringToFront();
|
|
WindowState = FormWindowState.Minimized;
|
|
Show();
|
|
WindowState = FormWindowState.Normal;
|
|
if (HaX) WinFormsUtil.Alert("Illegal mode activated.", "Please behave.");
|
|
|
|
if (showChangelog)
|
|
new About().ShowDialog();
|
|
|
|
if (BAKprompt && !Directory.Exists(BackupPath))
|
|
promptBackup();
|
|
|
|
#endregion
|
|
}
|
|
|
|
#region Important Variables
|
|
public static SaveFile SAV = SaveUtil.getBlankSAV(GameVersion.SN, "PKHeX");
|
|
public static PKM pkm = SAV.BlankPKM; // Tab Pokemon Data Storage
|
|
private LegalityAnalysis Legality = new LegalityAnalysis(pkm);
|
|
|
|
public static string curlanguage = "en";
|
|
public static string[] gendersymbols = { "♂", "♀", "-" };
|
|
public static bool unicode;
|
|
|
|
public static volatile bool formInitialized;
|
|
private static bool fieldsInitialized, fieldsLoaded, loadingSAV;
|
|
private static int colorizedbox = -1;
|
|
private static Image colorizedcolor;
|
|
private static int colorizedslot;
|
|
public static bool HaX;
|
|
private static readonly Image mixedHighlight = ImageUtil.ChangeOpacity(Resources.slotSet, 0.5);
|
|
private static readonly string[] main_langlist =
|
|
{
|
|
"日本語", // JPN
|
|
"English", // ENG
|
|
"Français", // FRE
|
|
"Italiano", // ITA
|
|
"Deutsch", // GER
|
|
"Español", // SPA
|
|
"한국어", // KOR
|
|
"中文", // CHN
|
|
"Português", // Portuguese
|
|
};
|
|
private static GameVersion origintrack;
|
|
private readonly PictureBox[] SlotPictureBoxes, movePB, relearnPB;
|
|
private readonly ToolTip Tip1 = new ToolTip(), Tip2 = new ToolTip(), Tip3 = new ToolTip(), NatureTip = new ToolTip(), EVTip = new ToolTip();
|
|
#endregion
|
|
|
|
#region Path Variables
|
|
|
|
public static string WorkingDirectory => WinFormsUtil.IsClickonceDeployed ? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "PKHeX") : Application.StartupPath;
|
|
public static string DatabasePath => Path.Combine(WorkingDirectory, "pkmdb");
|
|
public static string MGDatabasePath => Path.Combine(WorkingDirectory, "mgdb");
|
|
private static string BackupPath => Path.Combine(WorkingDirectory, "bak");
|
|
private const string ThreadPath = @"https://projectpokemon.org/PKHeX/";
|
|
private const string VersionPath = @"https://raw.githubusercontent.com/kwsch/PKHeX/master/PKHeX/Resources/text/version.txt";
|
|
|
|
#endregion
|
|
|
|
#region //// MAIN MENU FUNCTIONS ////
|
|
private void loadConfig(out bool BAKprompt, out bool showChangelog, out int languageID)
|
|
{
|
|
BAKprompt = false;
|
|
showChangelog = false;
|
|
languageID = 1;
|
|
|
|
var Settings = Properties.Settings.Default;
|
|
Settings.Upgrade();
|
|
|
|
unicode = Menu_Unicode.Checked = Settings.Unicode;
|
|
updateUnicode();
|
|
SaveFile.SetUpdateDex = Menu_ModifyDex.Checked = Settings.SetUpdateDex;
|
|
SaveFile.SetUpdatePKM = Menu_ModifyPKM.Checked = Settings.SetUpdatePKM;
|
|
Menu_FlagIllegal.Checked = Settings.FlagIllegal;
|
|
Menu_ModifyUnset.Checked = Settings.ModifyUnset;
|
|
|
|
// Select Language
|
|
string l = Settings.Language;
|
|
int lang = Array.IndexOf(GameInfo.lang_val, l);
|
|
if (lang < 0)
|
|
lang = Array.IndexOf(GameInfo.lang_val, "en");
|
|
if (lang > -1)
|
|
languageID = lang;
|
|
|
|
// Version Check
|
|
if (Settings.Version.Length > 0) // already run on system
|
|
{
|
|
int lastrev; int.TryParse(Settings.Version, out lastrev);
|
|
int currrev; int.TryParse(Resources.ProgramVersion, out currrev);
|
|
|
|
showChangelog = lastrev < currrev;
|
|
}
|
|
|
|
// BAK Prompt
|
|
if (!Settings.BAKPrompt)
|
|
BAKprompt = Settings.BAKPrompt = true;
|
|
|
|
Settings.Version = Resources.ProgramVersion;
|
|
}
|
|
private static void deleteConfig(string settingsFilename)
|
|
{
|
|
var dr = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "PKHeX's settings are corrupt. Would you like to reset the settings?",
|
|
"Yes to delete the settings or No to close the program.");
|
|
|
|
if (dr == DialogResult.Yes)
|
|
{
|
|
File.Delete(settingsFilename);
|
|
WinFormsUtil.Alert("The settings have been deleted", "Please restart the program.");
|
|
}
|
|
Process.GetCurrentProcess().Kill();
|
|
}
|
|
// Main Menu Strip UI Functions
|
|
private void mainMenuOpen(object sender, EventArgs e)
|
|
{
|
|
string pkx = pkm.Extension;
|
|
string ekx = 'e' + pkx.Substring(1, pkx.Length-1);
|
|
|
|
string supported = string.Join(";", SAV.PKMExtensions.Select(s => "*."+s).Concat(new[] {"*.pkm"}));
|
|
OpenFileDialog ofd = new OpenFileDialog
|
|
{
|
|
Filter = "All Files|*.*" +
|
|
$"|Supported Files|main;*.sav;*.dat;*.gci;*.bin;*.{ekx};{supported};*.bak" +
|
|
"|3DS Main Files|main" +
|
|
"|Save Files|*.sav;*.dat;*.gci" +
|
|
$"|Decrypted PKM File|{supported}" +
|
|
$"|Encrypted PKM File|*.{ekx}" +
|
|
"|Binary File|*.bin" +
|
|
"|Backup File|*.bak"
|
|
};
|
|
|
|
// Detect main
|
|
string cgse = "";
|
|
string path;
|
|
string pathCache = CyberGadgetUtil.GetCacheFolder();
|
|
if (Directory.Exists(pathCache))
|
|
cgse = Path.Combine(pathCache);
|
|
if (!SaveUtil.detectSaveFile(out path, cgse))
|
|
WinFormsUtil.Error(path);
|
|
|
|
if (path != null)
|
|
{ ofd.FileName = path; }
|
|
|
|
if (ofd.ShowDialog() == DialogResult.OK)
|
|
openQuick(ofd.FileName);
|
|
}
|
|
private void mainMenuSave(object sender, EventArgs e)
|
|
{
|
|
if (!verifiedPKM()) return;
|
|
PKM pk = preparePKM();
|
|
string pkx = pk.Extension;
|
|
string ekx = 'e' + pkx.Substring(1, pkx.Length - 1);
|
|
SaveFileDialog sfd = new SaveFileDialog
|
|
{
|
|
Filter = $"Decrypted PKM File|*.{pkx}" +
|
|
(SAV.Generation > 2 ? "" : $"|Encrypted PKM File|*.{ekx}") +
|
|
"|Binary File|*.bin" +
|
|
"|All Files|*.*",
|
|
DefaultExt = pkx,
|
|
FileName = Util.CleanFileName(pk.FileName)
|
|
};
|
|
if (sfd.ShowDialog() != DialogResult.OK) return;
|
|
string path = sfd.FileName;
|
|
string ext = Path.GetExtension(path);
|
|
|
|
if (File.Exists(path))
|
|
{
|
|
// File already exists, save a .bak
|
|
string bakpath = path + ".bak";
|
|
if (!File.Exists(bakpath))
|
|
{
|
|
byte[] backupfile = File.ReadAllBytes(path);
|
|
File.WriteAllBytes(bakpath, backupfile);
|
|
}
|
|
}
|
|
|
|
if (new[] {".ekx", "."+ekx, ".bin"}.Contains(ext))
|
|
File.WriteAllBytes(path, pk.EncryptedPartyData);
|
|
else if (new[] { "."+pkx }.Contains(ext))
|
|
File.WriteAllBytes(path, pk.DecryptedBoxData);
|
|
else
|
|
{
|
|
WinFormsUtil.Error($"Foreign File Extension: {ext}", "Exporting as encrypted.");
|
|
File.WriteAllBytes(path, pkm.EncryptedPartyData);
|
|
}
|
|
}
|
|
private void mainMenuExit(object sender, EventArgs e)
|
|
{
|
|
if (ModifierKeys == Keys.Control) // Hotkey Triggered
|
|
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Quit PKHeX?")) return;
|
|
Close();
|
|
}
|
|
private void mainMenuAbout(object sender, EventArgs e)
|
|
{
|
|
// Open a new form with the About details.
|
|
new About().ShowDialog();
|
|
}
|
|
// Sub Menu Options
|
|
private void mainMenuBoxReport(object sender, EventArgs e)
|
|
{
|
|
var z = Application.OpenForms.Cast<Form>().FirstOrDefault(form => form.GetType() == typeof(frmReport)) as frmReport;
|
|
if (z != null)
|
|
{ WinFormsUtil.CenterToForm(z, this); z.BringToFront(); return; }
|
|
|
|
frmReport ReportForm = new frmReport();
|
|
ReportForm.Show();
|
|
ReportForm.PopulateData(SAV.BoxData);
|
|
}
|
|
private void mainMenuDatabase(object sender, EventArgs e)
|
|
{
|
|
if (ModifierKeys == Keys.Shift)
|
|
{
|
|
var c = Application.OpenForms.Cast<Form>().FirstOrDefault(form => form.GetType() == typeof(KChart)) as KChart;
|
|
if (c != null)
|
|
{ WinFormsUtil.CenterToForm(c, this); c.BringToFront(); }
|
|
else
|
|
new KChart().Show();
|
|
return;
|
|
}
|
|
|
|
var z = Application.OpenForms.Cast<Form>().FirstOrDefault(form => form.GetType() == typeof(SAV_Database)) as SAV_Database;
|
|
if (z != null)
|
|
{ WinFormsUtil.CenterToForm(z, this); z.BringToFront(); return; }
|
|
|
|
if (Directory.Exists(DatabasePath))
|
|
new SAV_Database(this).Show();
|
|
else
|
|
WinFormsUtil.Alert("PKHeX's database was not found.",
|
|
$"Please dump all boxes from a save file, then ensure the '{DatabasePath}' folder exists.");
|
|
}
|
|
private void mainMenuMysteryDM(object sender, EventArgs e)
|
|
{
|
|
var z = Application.OpenForms.Cast<Form>().FirstOrDefault(form => form.GetType() == typeof(SAV_MysteryGiftDB)) as SAV_MysteryGiftDB;
|
|
if (z != null)
|
|
{ WinFormsUtil.CenterToForm(z, this); z.BringToFront(); return; }
|
|
|
|
new SAV_MysteryGiftDB(this).Show();
|
|
|
|
}
|
|
private void mainMenuUnicode(object sender, EventArgs e)
|
|
{
|
|
Properties.Settings.Default.Unicode = unicode = Menu_Unicode.Checked;
|
|
updateUnicode();
|
|
}
|
|
private void mainMenuModifyDex(object sender, EventArgs e)
|
|
{
|
|
Properties.Settings.Default.SetUpdateDex = SaveFile.SetUpdateDex = Menu_ModifyDex.Checked;
|
|
}
|
|
private void mainMenuModifyUnset(object sender, EventArgs e)
|
|
{
|
|
Properties.Settings.Default.ModifyUnset = Menu_ModifyUnset.Checked;
|
|
}
|
|
private void mainMenuModifyPKM(object sender, EventArgs e)
|
|
{
|
|
Properties.Settings.Default.SetUpdatePKM = SaveFile.SetUpdatePKM = Menu_ModifyPKM.Checked;
|
|
}
|
|
private void mainMenuFlagIllegal(object sender, EventArgs e)
|
|
{
|
|
Properties.Settings.Default.FlagIllegal = Menu_FlagIllegal.Checked;
|
|
updateBoxViewers(all:true);
|
|
setPKXBoxes();
|
|
}
|
|
private void mainMenuBoxLoad(object sender, EventArgs e)
|
|
{
|
|
string path = "";
|
|
if (Directory.Exists(DatabasePath))
|
|
{
|
|
DialogResult ld = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Load from PKHeX's database?");
|
|
if (ld == DialogResult.Yes)
|
|
path = DatabasePath;
|
|
else if (ld == DialogResult.No)
|
|
{
|
|
// open folder dialog
|
|
FolderBrowserDialog fbd = new FolderBrowserDialog();
|
|
if (fbd.ShowDialog() == DialogResult.OK)
|
|
path = fbd.SelectedPath;
|
|
}
|
|
else return;
|
|
}
|
|
else
|
|
{
|
|
// open folder dialog
|
|
FolderBrowserDialog fbd = new FolderBrowserDialog();
|
|
if (fbd.ShowDialog() == DialogResult.OK)
|
|
path = fbd.SelectedPath;
|
|
}
|
|
loadBoxesFromDB(path);
|
|
}
|
|
private void mainMenuBoxDump(object sender, EventArgs e)
|
|
{
|
|
string path;
|
|
bool separate = false;
|
|
// Dump all of box content to files.
|
|
DialogResult ld = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Save to PKHeX's database?");
|
|
if (ld == DialogResult.Yes)
|
|
{
|
|
path = DatabasePath;
|
|
if (!Directory.Exists(path))
|
|
Directory.CreateDirectory(path);
|
|
}
|
|
else if (ld == DialogResult.No)
|
|
{
|
|
separate = DialogResult.Yes == WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Save each box separately?");
|
|
|
|
// open folder dialog
|
|
FolderBrowserDialog fbd = new FolderBrowserDialog();
|
|
if (fbd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
path = fbd.SelectedPath;
|
|
}
|
|
else return;
|
|
|
|
string result;
|
|
SAV.dumpBoxes(path, out result, separate);
|
|
WinFormsUtil.Alert(result);
|
|
}
|
|
private void mainMenuBoxDumpSingle(object sender, EventArgs e)
|
|
{
|
|
// open folder dialog
|
|
FolderBrowserDialog fbd = new FolderBrowserDialog();
|
|
if (fbd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
string result;
|
|
SAV.dumpBox(fbd.SelectedPath, out result, CB_BoxSelect.SelectedIndex);
|
|
WinFormsUtil.Alert(result);
|
|
}
|
|
private void manMenuBatchEditor(object sender, EventArgs e)
|
|
{
|
|
new BatchEditor(preparePKM()).ShowDialog();
|
|
setPKXBoxes(); // refresh
|
|
updateBoxViewers();
|
|
}
|
|
// Misc Options
|
|
private void clickShowdownImportPKM(object sender, EventArgs e)
|
|
{
|
|
if (!formInitialized)
|
|
return;
|
|
if (!Clipboard.ContainsText())
|
|
{ WinFormsUtil.Alert("Clipboard does not contain text."); return; }
|
|
|
|
// Get Simulator Data
|
|
ShowdownSet Set = new ShowdownSet(Clipboard.GetText());
|
|
|
|
if (Set.Species < 0)
|
|
{ WinFormsUtil.Alert("Set data not found in clipboard."); return; }
|
|
|
|
if (Set.Nickname != null && Set.Nickname.Length > SAV.NickLength)
|
|
Set.Nickname = Set.Nickname.Substring(0, SAV.NickLength);
|
|
|
|
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Import this set?", Set.getText()))
|
|
{ return; }
|
|
|
|
if (Set.InvalidLines.Any())
|
|
WinFormsUtil.Alert("Invalid lines detected:", string.Join(Environment.NewLine, Set.InvalidLines));
|
|
|
|
// Set Species & Nickname
|
|
CB_Species.SelectedValue = Set.Species;
|
|
CHK_Nicknamed.Checked = Set.Nickname != null;
|
|
if (Set.Nickname != null)
|
|
TB_Nickname.Text = Set.Nickname;
|
|
if (Set.Gender != null)
|
|
{
|
|
int Gender = PKX.getGender(Set.Gender);
|
|
Label_Gender.Text = gendersymbols[Gender];
|
|
Label_Gender.ForeColor = Gender == 2 ? Label_Species.ForeColor : (Gender == 1 ? Color.Red : Color.Blue);
|
|
}
|
|
|
|
// Set Form
|
|
string[] formStrings = PKX.getFormList(Set.Species,
|
|
Util.getTypesList("en"),
|
|
Util.getFormsList("en"), gendersymbols, SAV.Generation);
|
|
int form = 0;
|
|
for (int i = 0; i < formStrings.Length; i++)
|
|
if (formStrings[i].Contains(Set.Form ?? ""))
|
|
{ form = i; break; }
|
|
CB_Form.SelectedIndex = Math.Min(CB_Form.Items.Count-1, form);
|
|
|
|
// Set Ability
|
|
int[] abilities = SAV.Personal.getAbilities(Set.Species, form);
|
|
int ability = Array.IndexOf(abilities, Set.Ability);
|
|
if (ability < 0) ability = 0;
|
|
CB_Ability.SelectedIndex = ability;
|
|
ComboBox[] m = {CB_Move1, CB_Move2, CB_Move3, CB_Move4};
|
|
for (int i = 0; i < 4; i++) m[i].SelectedValue = Set.Moves[i];
|
|
|
|
// Set Item and Nature
|
|
CB_HeldItem.SelectedValue = Set.Item < 0 ? 0 : Set.Item;
|
|
CB_Nature.SelectedValue = Set.Nature < 0 ? 0 : Set.Nature;
|
|
|
|
// Set IVs
|
|
TB_HPIV.Text = Set.IVs[0].ToString();
|
|
TB_ATKIV.Text = Set.IVs[1].ToString();
|
|
TB_DEFIV.Text = Set.IVs[2].ToString();
|
|
TB_SPAIV.Text = Set.IVs[4].ToString();
|
|
TB_SPDIV.Text = Set.IVs[5].ToString();
|
|
TB_SPEIV.Text = Set.IVs[3].ToString();
|
|
|
|
// Set EVs
|
|
TB_HPEV.Text = Set.EVs[0].ToString();
|
|
TB_ATKEV.Text = Set.EVs[1].ToString();
|
|
TB_DEFEV.Text = Set.EVs[2].ToString();
|
|
TB_SPAEV.Text = Set.EVs[4].ToString();
|
|
TB_SPDEV.Text = Set.EVs[5].ToString();
|
|
TB_SPEEV.Text = Set.EVs[3].ToString();
|
|
|
|
// Set Level and Friendship
|
|
TB_Level.Text = Set.Level.ToString();
|
|
TB_Friendship.Text = Set.Friendship.ToString();
|
|
|
|
// Reset IV/EVs
|
|
updateRandomPID(sender, e);
|
|
updateRandomEC(sender, e);
|
|
ComboBox[] p = {CB_PPu1, CB_PPu2, CB_PPu3, CB_PPu4};
|
|
for (int i = 0; i < 4; i++)
|
|
p[i].SelectedIndex = m[i].SelectedIndex != 0 ? 3 : 0; // max PP
|
|
|
|
if (Set.Shiny) updateShinyPID(sender, e);
|
|
pkm = preparePKM();
|
|
updateLegality();
|
|
}
|
|
private void clickShowdownExportPKM(object sender, EventArgs e)
|
|
{
|
|
if (!formInitialized)
|
|
return;
|
|
if (!verifiedPKM())
|
|
{ WinFormsUtil.Alert("Fix data before exporting."); return; }
|
|
|
|
Clipboard.SetText(preparePKM().ShowdownText);
|
|
WinFormsUtil.Alert("Exported Showdown Set to Clipboard:", Clipboard.GetText());
|
|
}
|
|
private void clickShowdownExportParty(object sender, EventArgs e)
|
|
{
|
|
if (SAV.PartyData.Length <= 0) return;
|
|
try
|
|
{
|
|
Clipboard.SetText(
|
|
SAV.PartyData.Aggregate("", (current, pk) => current + pk.ShowdownText
|
|
+ Environment.NewLine + Environment.NewLine).Trim());
|
|
WinFormsUtil.Alert("Showdown Team (Party) set to Clipboard.");
|
|
}
|
|
catch { }
|
|
}
|
|
private void clickShowdownExportBattleBox(object sender, EventArgs e)
|
|
{
|
|
if (SAV.BattleBoxData.Length <= 0) return;
|
|
try
|
|
{
|
|
Clipboard.SetText(
|
|
SAV.BattleBoxData.Aggregate("", (current, pk) => current + pk.ShowdownText
|
|
+ Environment.NewLine + Environment.NewLine).Trim());
|
|
WinFormsUtil.Alert("Showdown Team (Battle Box) set to Clipboard.");
|
|
}
|
|
catch { }
|
|
}
|
|
private void clickOpenTempFolder(object sender, EventArgs e)
|
|
{
|
|
string path = CyberGadgetUtil.GetTempFolder();
|
|
if (Directory.Exists(Path.Combine(path, "root")))
|
|
Process.Start("explorer.exe", Path.Combine(path, "root"));
|
|
else if (Directory.Exists(path))
|
|
Process.Start("explorer.exe", path);
|
|
else
|
|
WinFormsUtil.Alert("Can't find the temporary file.", "Make sure the Cyber Gadget software is paused.");
|
|
}
|
|
private void clickOpenCacheFolder(object sender, EventArgs e)
|
|
{
|
|
string path = CyberGadgetUtil.GetCacheFolder();
|
|
if (Directory.Exists(path))
|
|
Process.Start("explorer.exe", path);
|
|
else
|
|
WinFormsUtil.Alert("Can't find the cache folder.");
|
|
}
|
|
private void clickOpenSDFFolder(object sender, EventArgs e)
|
|
{
|
|
string path = Path.GetPathRoot(Util.get3DSLocation());
|
|
if (path != null && Directory.Exists(path = Path.Combine(path, "filer", "UserSaveData")))
|
|
Process.Start("explorer.exe", path);
|
|
else
|
|
WinFormsUtil.Alert("Can't find the SaveDataFiler folder.");
|
|
}
|
|
private void clickOpenSDBFolder(object sender, EventArgs e)
|
|
{
|
|
string path3DS = Path.GetPathRoot(Util.get3DSLocation());
|
|
string path;
|
|
if (path3DS != null && Directory.Exists(path = Path.Combine(path3DS, "SaveDataBackup")))
|
|
Process.Start("explorer.exe", path);
|
|
else
|
|
WinFormsUtil.Alert("Can't find the SaveDataBackup folder.");
|
|
}
|
|
|
|
// Main Menu Subfunctions
|
|
private void openQuick(string path, bool force = false)
|
|
{
|
|
if (!(CanFocus || force))
|
|
{
|
|
SystemSounds.Asterisk.Play();
|
|
return;
|
|
}
|
|
// detect if it is a folder (load into boxes or not)
|
|
if (Directory.Exists(path))
|
|
{ loadBoxesFromDB(path); return; }
|
|
|
|
string ext = Path.GetExtension(path);
|
|
FileInfo fi = new FileInfo(path);
|
|
if (fi.Length > 0x10009C && fi.Length != 0x380000 && ! SAV3GCMemoryCard.IsMemoryCardSize(fi.Length))
|
|
WinFormsUtil.Error("Input file is too large." + Environment.NewLine + $"Size: {fi.Length} bytes", path);
|
|
else if (fi.Length < 32)
|
|
WinFormsUtil.Error("Input file is too small." + Environment.NewLine + $"Size: {fi.Length} bytes", path);
|
|
else
|
|
{
|
|
byte[] input; try { input = File.ReadAllBytes(path); }
|
|
catch (Exception e) { WinFormsUtil.Error("Unable to load file. It could be in use by another program.\nPath: " + path, e); return; }
|
|
|
|
#if DEBUG
|
|
openFile(input, path, ext);
|
|
#else
|
|
try { openFile(input, path, ext); }
|
|
catch (Exception e) { WinFormsUtil.Error("Unable to load file.\nPath: " + path, e); }
|
|
#endif
|
|
}
|
|
}
|
|
private void openFile(byte[] input, string path, string ext)
|
|
{
|
|
SaveFile sav; MysteryGift tg; PKM temp; string c;
|
|
#region Powersaves Read-Only Conversion
|
|
if (input.Length == 0x10009C) // Resize to 1MB
|
|
{
|
|
Array.Copy(input, 0x9C, input, 0, 0x100000);
|
|
Array.Resize(ref input, 0x100000);
|
|
}
|
|
// Verify the Data Input Size is Proper
|
|
if (input.Length == 0x100000)
|
|
{
|
|
if (openXOR(input, path)) // Check if we can load the save via xorpad
|
|
return; // only if a save is loaded we abort
|
|
if (BitConverter.ToUInt64(input, 0x10) != 0) // encrypted save
|
|
{ WinFormsUtil.Error("PKHeX only edits decrypted save files." + Environment.NewLine + "This save file is not decrypted.", path); return; }
|
|
|
|
DialogResult sdr = WinFormsUtil.Prompt(MessageBoxButtons.YesNoCancel, "Press Yes to load the sav at 0x3000", "Press No for the one at 0x82000");
|
|
if (sdr == DialogResult.Cancel)
|
|
return;
|
|
int savshift = sdr == DialogResult.Yes ? 0 : 0x7F000;
|
|
byte[] psdata = input.Skip(0x5400 + savshift).Take(SaveUtil.SIZE_G6ORAS).ToArray();
|
|
|
|
if (BitConverter.ToUInt32(psdata, SaveUtil.SIZE_G6ORAS - 0x1F0) == SaveUtil.BEEF)
|
|
Array.Resize(ref psdata, SaveUtil.SIZE_G6ORAS); // set to ORAS size
|
|
else if (BitConverter.ToUInt32(psdata, SaveUtil.SIZE_G6XY - 0x1F0) == SaveUtil.BEEF)
|
|
Array.Resize(ref psdata, SaveUtil.SIZE_G6XY); // set to X/Y size
|
|
else if (BitConverter.ToUInt32(psdata, SaveUtil.SIZE_G7SM - 0x1F0) == SaveUtil.BEEF)
|
|
Array.Resize(ref psdata, SaveUtil.SIZE_G7SM); // set to S/M size
|
|
else
|
|
{ WinFormsUtil.Error("The data file is not a valid save file", path); return; }
|
|
|
|
openSAV(SaveUtil.getVariantSAV(psdata), path);
|
|
}
|
|
#endregion
|
|
#region SAV/PKM
|
|
else if ((sav = SaveUtil.getVariantSAV(input)) != null)
|
|
{
|
|
openSAV(sav, path);
|
|
}
|
|
else if ((SAV3GCMemoryCard.IsMemoryCardSize(input)))
|
|
{
|
|
SAV3GCMemoryCard MC = CheckGCMemoryCard(input, path);
|
|
if (MC == null)
|
|
return;
|
|
if ((sav = SaveUtil.getVariantSAV(MC)) != null)
|
|
{
|
|
openSAV(sav, path);
|
|
}
|
|
else
|
|
WinFormsUtil.Error("Attempted to load an unsupported file type/size.",
|
|
$"File Loaded:{Environment.NewLine}{path}",
|
|
$"File Size:{Environment.NewLine}{input.Length} bytes (0x{input.Length:X4})");
|
|
}
|
|
else if ((temp = PKMConverter.getPKMfromBytes(input, prefer: ext.Length > 0 ? (ext.Last() - 0x30)&7 : SAV.Generation)) != null)
|
|
{
|
|
PKM pk = PKMConverter.convertToFormat(temp, SAV.PKMType, out c);
|
|
if (pk == null)
|
|
WinFormsUtil.Alert("Conversion failed.", c);
|
|
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;
|
|
WinFormsUtil.Alert($"Cannot load {a_lang} {pk_type} in {a_lang} save file.");
|
|
}
|
|
else
|
|
populateFields(pk);
|
|
Console.WriteLine(c);
|
|
}
|
|
#endregion
|
|
#region PC/Box Data
|
|
else if (BitConverter.ToUInt16(input, 4) == 0 && BitConverter.ToUInt32(input, 8) > 0 && PKX.getIsPKM(input.Length / SAV.BoxSlotCount / SAV.BoxCount) || PKX.getIsPKM(input.Length / SAV.BoxSlotCount))
|
|
{
|
|
if (SAV.getPCBin().Length == input.Length)
|
|
{
|
|
if (SAV.getBoxHasLockedSlot(0, SAV.BoxCount - 1))
|
|
WinFormsUtil.Alert("Battle Box slots prevent loading of PC data.");
|
|
else if (SAV.setPCBin(input))
|
|
WinFormsUtil.Alert("PC Binary loaded.");
|
|
else
|
|
{
|
|
WinFormsUtil.Alert("Binary is not compatible with save file.", "Current SAV Generation: " + SAV.Generation);
|
|
return;
|
|
}
|
|
}
|
|
else if (SAV.getBoxBin(CB_BoxSelect.SelectedIndex).Length == input.Length)
|
|
{
|
|
if (SAV.getBoxHasLockedSlot(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex))
|
|
WinFormsUtil.Alert("Battle Box slots in box prevent loading of box data.");
|
|
else if (SAV.setBoxBin(input, CB_BoxSelect.SelectedIndex))
|
|
WinFormsUtil.Alert("Box Binary loaded.");
|
|
else
|
|
{
|
|
WinFormsUtil.Alert("Binary is not compatible with save file.", "Current SAV Generation: " + SAV.Generation);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WinFormsUtil.Alert("Binary is not compatible with save file.", "Current SAV Generation: " + SAV.Generation);
|
|
return;
|
|
}
|
|
setPKXBoxes();
|
|
updateBoxViewers();
|
|
}
|
|
#endregion
|
|
#region Battle Video
|
|
else if (BattleVideo.getIsValid(input))
|
|
{
|
|
BattleVideo b = BattleVideo.getVariantBattleVideo(input);
|
|
if (SAV.Generation != b.Generation)
|
|
{ WinFormsUtil.Alert($"Cannot load a Gen{b.Generation} Battle Video to a different generation save file."); return; }
|
|
|
|
if (WinFormsUtil.Prompt(MessageBoxButtons.YesNo, $"Load Battle Video Pokémon data to {CB_BoxSelect.Text}?", "The box will be overwritten.") != DialogResult.Yes)
|
|
return;
|
|
|
|
bool? noSetb = getPKMSetOverride();
|
|
PKM[] data = b.BattlePKMs;
|
|
int offset = SAV.getBoxOffset(CB_BoxSelect.SelectedIndex);
|
|
int slotSkipped = 0;
|
|
for (int i = 0; i < 24; i++)
|
|
{
|
|
if (SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, i))
|
|
{ slotSkipped++; continue; }
|
|
SAV.setStoredSlot(data[i], offset + i*SAV.SIZE_STORED, noSetb);
|
|
}
|
|
|
|
if (slotSkipped > 0)
|
|
WinFormsUtil.Alert($"Skipped {slotSkipped} locked slot{(slotSkipped > 1 ? "s" : "")}.");
|
|
|
|
setPKXBoxes();
|
|
updateBoxViewers();
|
|
}
|
|
#endregion
|
|
#region Mystery Gift (Templates)
|
|
else if ((tg = MysteryGift.getMysteryGift(input, ext)) != null)
|
|
{
|
|
if (!tg.IsPokémon)
|
|
{ WinFormsUtil.Alert("Mystery Gift is not a Pokémon.", path); return; }
|
|
|
|
temp = tg.convertToPKM(SAV);
|
|
PKM pk = PKMConverter.convertToFormat(temp, SAV.PKMType, out c);
|
|
|
|
if (pk == null)
|
|
WinFormsUtil.Alert("Conversion failed.", c);
|
|
else
|
|
populateFields(pk);
|
|
Console.WriteLine(c);
|
|
}
|
|
#endregion
|
|
else
|
|
WinFormsUtil.Error("Attempted to load an unsupported file type/size.",
|
|
$"File Loaded:{Environment.NewLine}{path}",
|
|
$"File Size:{Environment.NewLine}{input.Length} bytes (0x{input.Length:X4})");
|
|
}
|
|
private bool openXOR(byte[] input, string path)
|
|
{
|
|
// try to get a save file via xorpad in same folder
|
|
string[] pads = Directory.GetFiles(path);
|
|
var s = SaveUtil.getSAVfromXORpads(input, pads);
|
|
|
|
if (s == null) // failed to find xorpad in path folder
|
|
{
|
|
// try again
|
|
pads = Directory.GetFiles(WorkingDirectory);
|
|
s = SaveUtil.getSAVfromXORpads(input, pads);
|
|
}
|
|
|
|
if (s == null)
|
|
return false; // failed
|
|
|
|
openSAV(s, s.FileName);
|
|
return true;
|
|
}
|
|
private static GameVersion SelectMemoryCardSaveGame(SAV3GCMemoryCard MC)
|
|
{
|
|
if (MC.SaveGameCount == 1)
|
|
return MC.SelectedGameVersion;
|
|
|
|
var games = new List<ComboItem>();
|
|
if (MC.HasCOLO) games.Add(new ComboItem { Text = "Colosseum", Value = (int)GameVersion.COLO });
|
|
if (MC.HasXD) games.Add(new ComboItem { Text = "XD", Value = (int)GameVersion.XD });
|
|
if (MC.HasRSBOX) games.Add(new ComboItem { Text = "RS Box", Value = (int)GameVersion.RSBOX });
|
|
|
|
WinFormsUtil.Alert("Multiple games detected", "Select a game to edit.");
|
|
var dialog = new SAV_GameSelect(games.ToArray());
|
|
dialog.ShowDialog();
|
|
return dialog.Result;
|
|
}
|
|
private static SAV3GCMemoryCard CheckGCMemoryCard(byte[] Data, string path)
|
|
{
|
|
SAV3GCMemoryCard MC = new SAV3GCMemoryCard();
|
|
GCMemoryCardState MCState = MC.LoadMemoryCardFile(Data);
|
|
switch (MCState)
|
|
{
|
|
default: { WinFormsUtil.Error("Invalid or corrupted GC Memory Card. Aborting.", path); return null; }
|
|
case GCMemoryCardState.NoPkmSaveGame: { WinFormsUtil.Error("GC Memory Card without any Pokémon save file. Aborting.", path); return null; }
|
|
case GCMemoryCardState.DuplicateCOLO:
|
|
case GCMemoryCardState.DuplicateXD:
|
|
case GCMemoryCardState.DuplicateRSBOX: { WinFormsUtil.Error("GC Memory Card with duplicated game save files. Aborting.", path); return null; }
|
|
case GCMemoryCardState.MultipleSaveGame:
|
|
{
|
|
GameVersion Game = SelectMemoryCardSaveGame(MC);
|
|
if (Game == GameVersion.Invalid) //Cancel
|
|
return null;
|
|
MC.SelectSaveGame(Game);
|
|
break;
|
|
}
|
|
case GCMemoryCardState.SaveGameCOLO: { MC.SelectSaveGame(GameVersion.COLO); break; }
|
|
case GCMemoryCardState.SaveGameXD: { MC.SelectSaveGame(GameVersion.XD); break; }
|
|
case GCMemoryCardState.SaveGameRSBOX: { MC.SelectSaveGame(GameVersion.RSBOX); break; }
|
|
}
|
|
return MC;
|
|
}
|
|
|
|
private void StoreLegalSaveGameData(SaveFile sav)
|
|
{
|
|
Legal.SavegameJapanese = sav.Japanese;
|
|
Legal.EReaderBerryIsEnigma = sav.eBerryIsEnigma;
|
|
Legal.EReaderBerryName = sav.eBerryName;
|
|
Legal.Savegame_Gender = sav.Gender;
|
|
Legal.Savegame_TID = sav.TID;
|
|
Legal.Savegame_SID = sav.SID;
|
|
Legal.Savegame_OT = sav.OT;
|
|
Legal.Savegame_Version = sav.Version;
|
|
}
|
|
|
|
private void openSAV(SaveFile sav, string path)
|
|
{
|
|
if (sav == null || sav.Version == GameVersion.Invalid)
|
|
{ WinFormsUtil.Error("Invalid save file loaded. Aborting.", path); return; }
|
|
|
|
if (!string.IsNullOrEmpty(path)) // If path is null, this is the default save
|
|
{
|
|
if (sav.RequiresMemeCrypto && !MemeCrypto.CanUseMemeCrypto())
|
|
{
|
|
WinFormsUtil.Error("Your platform does not support the required cryptography components.", "In order to be able to save your changes, you must either upgrade to a newer version of Windows or disable FIPS compliance mode.");
|
|
// Don't abort loading; user can still view save and fix checksum on another platform.
|
|
}
|
|
}
|
|
// Finish setting up the save file.
|
|
if (sav.Generation == 1)
|
|
{
|
|
// Ask the user if it is a VC save file or if it is from a physical cartridge.
|
|
// Necessary for legality checking possibilities that are only obtainable on GSC (non VC) or event distributions.
|
|
var drVC = WinFormsUtil.Prompt(MessageBoxButtons.YesNoCancel, $"{sav.Version} Save File detected. Is this a Virtual Console Save File?",
|
|
"Yes: Virtual Console" + Environment.NewLine + "No: Physical Cartridge");
|
|
if (drVC == DialogResult.Cancel)
|
|
return;
|
|
Legal.AllowGBCartEra = drVC == DialogResult.No; // physical cart selected
|
|
if (Legal.AllowGBCartEra && sav.Generation == 1)
|
|
{
|
|
var drTradeback = WinFormsUtil.Prompt(MessageBoxButtons.YesNoCancel, $"Generation {SAV.Generation} Save File detected. Allow tradebacks from Generation 2 for legality purposes?",
|
|
"Yes: Allow Generation 2 tradeback learnsets" + Environment.NewLine + "No: Don't allow Generation 2 tradeback learnsets");
|
|
Legal.AllowGen1Tradeback = drTradeback == DialogResult.Yes;
|
|
}
|
|
else
|
|
Legal.AllowGen1Tradeback = false;
|
|
}
|
|
else
|
|
Legal.AllowGBCartEra = Legal.AllowGen1Tradeback = sav.Generation == 2;
|
|
|
|
if (sav.Generation == 3 && (sav.IndeterminateGame || ModifierKeys == Keys.Control))
|
|
{
|
|
WinFormsUtil.Alert($"Generation {SAV.Generation} Save File detected.", "Select version.");
|
|
var g = new[] {GameVersion.R, GameVersion.S, GameVersion.E, GameVersion.FR, GameVersion.LG};
|
|
var games = g.Select(z => GameInfo.VersionDataSource.First(v => v.Value == (int)z));
|
|
var dialog = new SAV_GameSelect(games);
|
|
dialog.ShowDialog();
|
|
|
|
switch (dialog.Result) // Reset save file info
|
|
{
|
|
case GameVersion.R:
|
|
case GameVersion.S: sav = new SAV3(sav.BAK, GameVersion.RS); break;
|
|
case GameVersion.E: sav = new SAV3(sav.BAK, GameVersion.E); break;
|
|
case GameVersion.FR:
|
|
case GameVersion.LG: sav = new SAV3(sav.BAK, GameVersion.FRLG); break;
|
|
default: return;
|
|
}
|
|
if (sav.Version == GameVersion.FRLG)
|
|
sav.Personal = dialog.Result == GameVersion.FR ? PersonalTable.FR : PersonalTable.LG;
|
|
}
|
|
else if (sav.IndeterminateSubVersion && sav.Version == GameVersion.FRLG)
|
|
{
|
|
string fr = GameInfo.VersionDataSource.First(r => r.Value == (int)GameVersion.FR).Text;
|
|
string lg = GameInfo.VersionDataSource.First(l => l.Value == (int)GameVersion.LG).Text;
|
|
const string dual = "{0}/{1} Save File Detected.";
|
|
WinFormsUtil.Alert(string.Format(dual, fr, lg), "Select version.");
|
|
var g = new[] {GameVersion.FR, GameVersion.LG};
|
|
var games = g.Select(z => GameInfo.VersionDataSource.First(v => v.Value == (int)z));
|
|
var dialog = new SAV_GameSelect(games);
|
|
dialog.ShowDialog();
|
|
|
|
sav.Personal = dialog.Result == GameVersion.FR ? PersonalTable.FR : PersonalTable.LG;
|
|
}
|
|
|
|
if (sav.IndeterminateLanguage)
|
|
{
|
|
// Japanese Save files are different. Get isJapanese
|
|
var drJP = WinFormsUtil.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;
|
|
}
|
|
StoreLegalSaveGameData(sav);
|
|
loadingSAV = true;
|
|
|
|
// clean fields
|
|
bool WindowToggleRequired = SAV.Generation < 3 && sav.Generation >= 3; // version combobox refresh hack
|
|
bool WindowTranslationRequired = false;
|
|
PKM pk = preparePKM();
|
|
populateFields(SAV.BlankPKM);
|
|
SAV = sav;
|
|
|
|
string title = $"PKH{(HaX ? "a" : "e")}X ({Resources.ProgramVersion}) - " + $"{SAV.GetType().Name}: ";
|
|
if (path != null) // Actual save file
|
|
{
|
|
SAV.FilePath = Path.GetDirectoryName(path);
|
|
SAV.FileName = Path.GetExtension(path) == ".bak"
|
|
? Path.GetFileName(path).Split(new[] { " [" }, StringSplitOptions.None)[0]
|
|
: Path.GetFileName(path);
|
|
Text = title + $"{Path.GetFileNameWithoutExtension(Util.CleanFileName(SAV.BAKName))}"; // more descriptive
|
|
|
|
// If backup folder exists, save a backup.
|
|
string backupName = Path.Combine(BackupPath, Util.CleanFileName(SAV.BAKName));
|
|
if (SAV.Exportable && Directory.Exists(BackupPath) && !File.Exists(backupName))
|
|
File.WriteAllBytes(backupName, SAV.BAK);
|
|
|
|
GB_SAVtools.Visible = true;
|
|
}
|
|
else // Blank save file
|
|
{
|
|
SAV.FilePath = null;
|
|
SAV.FileName = "Blank Save File";
|
|
Text = title + $"{SAV.FileName} [{SAV.OT} ({SAV.Version})]";
|
|
|
|
GB_SAVtools.Visible = false;
|
|
}
|
|
Menu_ExportSAV.Enabled = B_VerifyCHK.Enabled = SAV.Exportable;
|
|
|
|
// Close subforms that are save dependent
|
|
Type[] f = { typeof(SAV_BoxViewer) };
|
|
foreach (var form in Application.OpenForms.Cast<Form>().Where(form => f.Contains(form.GetType())).ToArray())
|
|
form.Close();
|
|
|
|
setBoxNames(); // Display the Box Names
|
|
if (SAV.HasBox)
|
|
{
|
|
int startBox = path == null ? 0 : SAV.CurrentBox; // FF if BattleBox
|
|
if (startBox > SAV.BoxCount - 1) { tabBoxMulti.SelectedIndex = 1; CB_BoxSelect.SelectedIndex = 0; }
|
|
else { tabBoxMulti.SelectedIndex = 0; CB_BoxSelect.SelectedIndex = startBox; }
|
|
}
|
|
setPKXBoxes(); // Reload all of the PKX Windows
|
|
|
|
// Hide content if not present in game.
|
|
GB_SUBE.Visible = SAV.HasSUBE;
|
|
PB_Locked.Visible = SAV.HasBattleBox && SAV.BattleBoxLocked;
|
|
|
|
if (!SAV.HasBox && tabBoxMulti.TabPages.Contains(Tab_Box))
|
|
tabBoxMulti.TabPages.Remove(Tab_Box);
|
|
else if (SAV.HasBox && !tabBoxMulti.TabPages.Contains(Tab_Box))
|
|
{
|
|
tabBoxMulti.TabPages.Insert(0, Tab_Box);
|
|
WindowTranslationRequired = true;
|
|
}
|
|
Menu_LoadBoxes.Enabled = Menu_DumpBoxes.Enabled = Menu_Report.Enabled = Menu_Modify.Enabled = B_SaveBoxBin.Enabled = SAV.HasBox;
|
|
|
|
int BoxTab = tabBoxMulti.TabPages.IndexOf(Tab_Box);
|
|
int PartyTab = tabBoxMulti.TabPages.IndexOf(Tab_PartyBattle);
|
|
|
|
if (!SAV.HasParty && tabBoxMulti.TabPages.Contains(Tab_PartyBattle))
|
|
tabBoxMulti.TabPages.Remove(Tab_PartyBattle);
|
|
else if (SAV.HasParty && !tabBoxMulti.TabPages.Contains(Tab_PartyBattle))
|
|
{
|
|
int index = BoxTab;
|
|
if (index < 0)
|
|
index = -1;
|
|
tabBoxMulti.TabPages.Insert(index + 1, Tab_PartyBattle);
|
|
WindowTranslationRequired = true;
|
|
}
|
|
|
|
if (!SAV.HasDaycare && tabBoxMulti.TabPages.Contains(Tab_Other))
|
|
tabBoxMulti.TabPages.Remove(Tab_Other);
|
|
else if (SAV.HasDaycare && !tabBoxMulti.TabPages.Contains(Tab_Other))
|
|
{
|
|
int index = PartyTab;
|
|
if (index < 0)
|
|
index = BoxTab;
|
|
if (index < 0)
|
|
index = -1;
|
|
tabBoxMulti.TabPages.Insert(index + 1, Tab_Other);
|
|
WindowTranslationRequired = true;
|
|
}
|
|
|
|
if (path != null) // Actual save file
|
|
{
|
|
PAN_BattleBox.Visible = L_BattleBox.Visible = L_ReadOnlyPBB.Visible = SAV.HasBattleBox;
|
|
GB_Daycare.Visible = SAV.HasDaycare;
|
|
GB_Fused.Visible = SAV.HasFused;
|
|
GB_GTS.Visible = SAV.HasGTS;
|
|
B_OpenSecretBase.Enabled = SAV.HasSecretBase;
|
|
B_OpenPokepuffs.Enabled = SAV.HasPuff;
|
|
B_OpenPokeBeans.Enabled = SAV.Generation == 7;
|
|
B_OpenZygardeCells.Enabled = SAV.Generation == 7;
|
|
B_OUTPasserby.Enabled = SAV.HasPSS;
|
|
B_OpenBoxLayout.Enabled = SAV.HasBoxWallpapers;
|
|
B_OpenWondercards.Enabled = SAV.HasWondercards;
|
|
B_OpenSuperTraining.Enabled = SAV.HasSuperTrain;
|
|
B_OpenHallofFame.Enabled = SAV.HasHoF;
|
|
B_OpenOPowers.Enabled = SAV.HasOPower;
|
|
B_OpenPokedex.Enabled = SAV.HasPokeDex;
|
|
B_OpenBerryField.Enabled = SAV.HasBerryField && SAV.XY;
|
|
B_OpenFriendSafari.Enabled = SAV.XY;
|
|
B_OpenPokeblocks.Enabled = SAV.HasPokeBlock;
|
|
B_JPEG.Visible = SAV.HasJPEG;
|
|
B_OpenEventFlags.Enabled = SAV.HasEvents;
|
|
B_OpenLinkInfo.Enabled = SAV.HasLink;
|
|
B_CGearSkin.Enabled = SAV.Generation == 5;
|
|
|
|
B_OpenTrainerInfo.Enabled = B_OpenItemPouch.Enabled = SAV.HasParty; // Box RS
|
|
B_OpenMiscEditor.Enabled = SAV is SAV3 || SAV.DP || SAV.HGSS;
|
|
|
|
B_OpenHoneyTreeEditor.Enabled = SAV.DP || SAV.Pt;
|
|
B_OpenRTCEditor.Enabled = SAV.RS || SAV.E;
|
|
}
|
|
GB_SAVtools.Visible = (path != null) && FLP_SAVtools.Controls.Cast<Control>().Any(c => c.Enabled);
|
|
foreach (Control c in FLP_SAVtools.Controls.Cast<Control>())
|
|
c.Visible = c.Enabled;
|
|
|
|
|
|
// Generational Interface
|
|
Tip1.RemoveAll(); Tip2.RemoveAll(); Tip3.RemoveAll(); // TSV/PSV
|
|
|
|
FLP_Country.Visible = FLP_SubRegion.Visible = FLP_3DSRegion.Visible = SAV.Generation >= 6;
|
|
Label_EncryptionConstant.Visible = BTN_RerollEC.Visible = TB_EC.Visible = SAV.Generation >= 6;
|
|
GB_nOT.Visible = GB_RelearnMoves.Visible = BTN_Medals.Visible = BTN_History.Visible = SAV.Generation >= 6;
|
|
PB_Legal.Visible = PB_WarnMove1.Visible = PB_WarnMove2.Visible = PB_WarnMove3.Visible = PB_WarnMove4.Visible = SAV.Generation >= 6;
|
|
|
|
PB_MarkPentagon.Visible = SAV.Generation >= 6;
|
|
PB_MarkAlola.Visible = PB_MarkVC.Visible = PB_MarkHorohoro.Visible = SAV.Generation >= 7;
|
|
TB_Secure1.Visible = TB_Secure2.Visible = L_Secure1.Visible = L_Secure2.Visible = SAV.Exportable && SAV.Generation >= 6;
|
|
TB_GameSync.Visible = L_GameSync.Visible = SAV.Exportable && SAV.Generation >= 6;
|
|
|
|
FLP_NSparkle.Visible = L_NSparkle.Visible = CHK_NSparkle.Visible = SAV.Generation == 5;
|
|
|
|
CB_Form.Visible = Label_Form.Visible = CHK_AsEgg.Visible = GB_EggConditions.Visible = PB_Mark5.Visible = PB_Mark6.Visible = SAV.Generation >= 4;
|
|
|
|
DEV_Ability.Enabled = DEV_Ability.Visible = SAV.Generation > 3 && HaX;
|
|
CB_Ability.Visible = !DEV_Ability.Enabled && SAV.Generation >= 3;
|
|
FLP_Nature.Visible = SAV.Generation >= 3;
|
|
FLP_Ability.Visible = SAV.Generation >= 3;
|
|
FLP_Language.Visible = SAV.Generation >= 3;
|
|
GB_ExtraBytes.Visible = GB_ExtraBytes.Enabled = SAV.Generation >= 3;
|
|
GB_Markings.Visible = SAV.Generation >= 3;
|
|
BTN_Ribbons.Visible = SAV.Generation >= 3;
|
|
CB_HPType.Enabled = CB_Form.Enabled = SAV.Generation >= 3;
|
|
BTN_RerollPID.Visible = Label_PID.Visible = TB_PID.Visible = Label_SID.Visible = TB_SID.Visible = SAV.Generation >= 3;
|
|
|
|
FLP_FriendshipForm.Visible = SAV.Generation >= 2;
|
|
FLP_HeldItem.Visible = SAV.Generation >= 2;
|
|
CHK_IsEgg.Visible = Label_Gender.Visible = SAV.Generation >= 2;
|
|
FLP_PKRS.Visible = FLP_EggPKRSRight.Visible = SAV.Generation >= 2;
|
|
Label_OTGender.Visible = SAV.Generation >= 2;
|
|
|
|
if (SAV.Version == GameVersion.BATREV)
|
|
{
|
|
L_SaveSlot.Visible = CB_SaveSlot.Visible = true;
|
|
CB_SaveSlot.DisplayMember = "Text"; CB_SaveSlot.ValueMember = "Value";
|
|
CB_SaveSlot.DataSource = new BindingSource(((SAV4BR) SAV).SaveSlots.Select(i => new ComboItem
|
|
{
|
|
Text = ((SAV4BR) SAV).SaveNames[i],
|
|
Value = i
|
|
}).ToList(), null);
|
|
CB_SaveSlot.SelectedValue = ((SAV4BR)SAV).CurrentSlot;
|
|
}
|
|
else
|
|
L_SaveSlot.Visible = CB_SaveSlot.Visible = false;
|
|
|
|
FLP_Purification.Visible = FLP_ShadowID.Visible = SAV.Version == GameVersion.COLO || SAV.Version == GameVersion.XD;
|
|
NUD_ShadowID.Maximum = SAV.MaxShadowID;
|
|
|
|
// HaX override, needs to be after DEV_Ability enabled assignment.
|
|
TB_AbilityNumber.Visible = SAV.Generation >= 6 && DEV_Ability.Enabled;
|
|
|
|
// Met Tab
|
|
FLP_MetDate.Visible = SAV.Generation >= 4;
|
|
FLP_Fateful.Visible = FLP_Ball.Visible = FLP_OriginGame.Visible = SAV.Generation >= 3;
|
|
FLP_MetLocation.Visible = FLP_MetLevel.Visible = SAV.Generation >= 2;
|
|
FLP_TimeOfDay.Visible = SAV.Generation == 2;
|
|
|
|
// Stats
|
|
FLP_StatsTotal.Visible = SAV.Generation >= 3;
|
|
FLP_Characteristic.Visible = SAV.Generation >= 3;
|
|
FLP_HPType.Visible = SAV.Generation >= 2;
|
|
|
|
PAN_Contest.Visible = SAV.Generation >= 3;
|
|
|
|
// Second daycare slot
|
|
SlotPictureBoxes[43].Visible = SAV.Generation >= 2;
|
|
|
|
if (sav.Generation == 1)
|
|
{
|
|
FLP_SpD.Visible = false;
|
|
Label_SPA.Visible = false;
|
|
Label_SPC.Visible = true;
|
|
TB_HPIV.Enabled = false;
|
|
MaskedTextBox[] evControls = { TB_SPAEV, TB_HPEV, TB_ATKEV, TB_DEFEV, TB_SPEEV, TB_SPDEV };
|
|
foreach (var ctrl in evControls)
|
|
{
|
|
ctrl.Mask = "00000";
|
|
ctrl.Size = Stat_HP.Size;
|
|
}
|
|
}
|
|
else if (sav.Generation == 2)
|
|
{
|
|
FLP_SpD.Visible = true;
|
|
Label_SPA.Visible = true;
|
|
Label_SPC.Visible = false;
|
|
TB_SPDEV.Enabled = TB_SPDIV.Enabled = false;
|
|
TB_HPIV.Enabled = false;
|
|
MaskedTextBox[] evControls = { TB_SPAEV, TB_HPEV, TB_ATKEV, TB_DEFEV, TB_SPEEV, TB_SPDEV };
|
|
foreach (var ctrl in evControls)
|
|
{
|
|
ctrl.Mask = "00000";
|
|
ctrl.Size = Stat_HP.Size;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLP_SpD.Visible = true;
|
|
Label_SPA.Visible = true;
|
|
Label_SPC.Visible = false;
|
|
TB_SPDEV.Enabled = TB_SPDIV.Enabled = true;
|
|
TB_HPIV.Enabled = true;
|
|
MaskedTextBox[] evControls = { TB_SPAEV, TB_HPEV, TB_ATKEV, TB_DEFEV, TB_SPEEV, TB_SPDEV };
|
|
foreach (var ctrl in evControls)
|
|
{
|
|
ctrl.Mask = "000";
|
|
ctrl.Size = TB_ExtraByte.Size;
|
|
}
|
|
}
|
|
|
|
// Recenter PKM SubEditors
|
|
FLP_PKMEditors.Location = new Point((Tab_OTMisc.Width - FLP_PKMEditors.Width) / 2, FLP_PKMEditors.Location.Y);
|
|
|
|
bool init = fieldsInitialized;
|
|
fieldsInitialized = fieldsLoaded = false;
|
|
|
|
switch (SAV.Generation)
|
|
{
|
|
case 6:
|
|
TB_GameSync.Enabled = SAV.GameSyncID != null;
|
|
TB_GameSync.MaxLength = SAV.GameSyncIDSize;
|
|
TB_GameSync.Text = (SAV.GameSyncID ?? 0.ToString()).PadLeft(SAV.GameSyncIDSize, '0');
|
|
TB_Secure1.Text = SAV.Secure1?.ToString("X16");
|
|
TB_Secure2.Text = SAV.Secure2?.ToString("X16");
|
|
break;
|
|
case 7:
|
|
TB_GameSync.Enabled = SAV.GameSyncID != null;
|
|
TB_GameSync.MaxLength = SAV.GameSyncIDSize;
|
|
TB_GameSync.Text = (SAV.GameSyncID ?? 0.ToString()).PadLeft(SAV.GameSyncIDSize, '0');
|
|
TB_Secure1.Text = SAV.Secure1?.ToString("X16");
|
|
TB_Secure2.Text = SAV.Secure2?.ToString("X16");
|
|
break;
|
|
}
|
|
pkm = pkm.GetType() != SAV.PKMType ? SAV.BlankPKM : pk;
|
|
if (pkm.Format < 3)
|
|
pkm = SAV.BlankPKM;
|
|
populateFilteredDataSources();
|
|
populateFields(pkm);
|
|
fieldsInitialized |= init;
|
|
|
|
// SAV Specific Limits
|
|
TB_OT.MaxLength = SAV.OTLength;
|
|
TB_OTt2.MaxLength = SAV.OTLength;
|
|
TB_Nickname.MaxLength = SAV.NickLength;
|
|
|
|
// Hide Unused Tabs
|
|
if (SAV.Generation == 1 && tabMain.TabPages.Contains(Tab_Met))
|
|
tabMain.TabPages.Remove(Tab_Met);
|
|
else if (SAV.Generation != 1 && !tabMain.TabPages.Contains(Tab_Met))
|
|
{
|
|
tabMain.TabPages.Insert(1, Tab_Met);
|
|
WindowTranslationRequired = true;
|
|
}
|
|
|
|
// Common HaX Interface
|
|
CHK_HackedStats.Enabled = CHK_HackedStats.Visible = MT_Level.Enabled = MT_Level.Visible = MT_Form.Enabled = MT_Form.Visible = HaX;
|
|
TB_Level.Visible = !HaX;
|
|
|
|
// Setup PKM Preparation/Extra Bytes
|
|
setPKMFormatMode(SAV.Generation, SAV.Version);
|
|
|
|
// pk2 save files do not have an Origin Game stored. Prompt the met location list to update.
|
|
if (SAV.Generation == 2)
|
|
updateOriginGame(null, null);
|
|
|
|
// Refresh PK* conversion info
|
|
PKMConverter.updateConfig(SAV.SubRegion, SAV.Country, SAV.ConsoleRegion, SAV.OT, SAV.Gender, SAV.Language);
|
|
|
|
if (WindowTranslationRequired) // force update -- re-added controls may be untranslated
|
|
{
|
|
// Keep window title
|
|
title = Text;
|
|
WinFormsUtil.TranslateInterface(this, curlanguage);
|
|
Text = title;
|
|
}
|
|
if (WindowToggleRequired) // Version combobox selectedvalue needs a little help, only updates once it is visible
|
|
{
|
|
tabMain.SelectedTab = Tab_Met; // parent tab of CB_GameOrigin
|
|
tabMain.SelectedTab = Tab_Main; // first tab
|
|
}
|
|
|
|
// No changes made yet
|
|
UndoStack.Clear(); Menu_Undo.Enabled = false;
|
|
RedoStack.Clear(); Menu_Redo.Enabled = false;
|
|
|
|
if (!string.IsNullOrWhiteSpace(path)) // Actual Save
|
|
{
|
|
// Check location write protection
|
|
bool locked = true;
|
|
try { locked = File.GetAttributes(path).HasFlag(FileAttributes.ReadOnly); }
|
|
catch { }
|
|
|
|
if (locked)
|
|
WinFormsUtil.Alert("File's location is write protected:\n" + path,
|
|
"If the path is a removable disk (SD card), please ensure the write protection switch is not set.");
|
|
}
|
|
|
|
TemplateFields();
|
|
loadingSAV = false;
|
|
SAV.Edited = false;
|
|
|
|
// Indicate audibly the save is loaded
|
|
SystemSounds.Beep.Play();
|
|
}
|
|
|
|
private static void refreshMGDB()
|
|
{
|
|
var g4 = getPCDDB(Resources.pcd);
|
|
var g5 = getPGFDB(Resources.pgf);
|
|
var g6 = getWC6DB(Resources.wc6, Resources.wc6full);
|
|
var g7 = getWC7DB(Resources.wc7, Resources.wc7full);
|
|
|
|
if (Directory.Exists(MGDatabasePath))
|
|
foreach (var file in Directory.GetFiles(MGDatabasePath, "*", SearchOption.AllDirectories))
|
|
{
|
|
var fi = new FileInfo(file);
|
|
if (!MysteryGift.getIsMysteryGift(fi.Length))
|
|
continue;
|
|
|
|
var gift = MysteryGift.getMysteryGift(File.ReadAllBytes(file), fi.Extension);
|
|
switch (gift?.Format)
|
|
{
|
|
case 4: g4.Add(gift); continue;
|
|
case 5: g5.Add(gift); continue;
|
|
case 6: g6.Add(gift); continue;
|
|
case 7: g7.Add(gift); continue;
|
|
}
|
|
}
|
|
|
|
Legal.MGDB_G4 = g4.ToArray();
|
|
Legal.MGDB_G5 = g5.ToArray();
|
|
Legal.MGDB_G6 = g6.ToArray();
|
|
Legal.MGDB_G7 = g7.ToArray();
|
|
}
|
|
private static HashSet<MysteryGift> getPCDDB(byte[] bin)
|
|
{
|
|
var db = new HashSet<MysteryGift>();
|
|
for (int i = 0; i < bin.Length; i += PCD.Size)
|
|
{
|
|
byte[] data = new byte[PCD.Size];
|
|
Buffer.BlockCopy(bin, i, data, 0, PCD.Size);
|
|
db.Add(new PCD(data));
|
|
}
|
|
return db;
|
|
}
|
|
private static HashSet<MysteryGift> getPGFDB(byte[] bin)
|
|
{
|
|
var db = new HashSet<MysteryGift>();
|
|
for (int i = 0; i < bin.Length; i += PGF.Size)
|
|
{
|
|
byte[] data = new byte[PGF.Size];
|
|
Buffer.BlockCopy(bin, i, data, 0, PGF.Size);
|
|
db.Add(new PGF(data));
|
|
}
|
|
return db;
|
|
}
|
|
private static HashSet<MysteryGift> getWC6DB(byte[] wc6bin, byte[] wc6full)
|
|
{
|
|
var db = new HashSet<MysteryGift>();
|
|
for (int i = 0; i < wc6bin.Length; i += WC6.Size)
|
|
{
|
|
byte[] data = new byte[WC6.Size];
|
|
Buffer.BlockCopy(wc6bin, i, data, 0, WC6.Size);
|
|
db.Add(new WC6(data));
|
|
}
|
|
for (int i = 0; i < wc6full.Length; i += WC6.SizeFull)
|
|
{
|
|
byte[] data = new byte[WC6.SizeFull];
|
|
Buffer.BlockCopy(wc6full, i, data, 0, WC6.SizeFull);
|
|
db.Add(new WC6(data));
|
|
}
|
|
return db;
|
|
}
|
|
private static HashSet<MysteryGift> getWC7DB(byte[] wc7bin, byte[] wc7full)
|
|
{
|
|
var db = new HashSet<MysteryGift>();
|
|
for (int i = 0; i < wc7bin.Length; i += WC7.Size)
|
|
{
|
|
byte[] data = new byte[WC7.Size];
|
|
Buffer.BlockCopy(wc7bin, i, data, 0, WC7.Size);
|
|
db.Add(new WC7(data));
|
|
}
|
|
for (int i = 0; i < wc7full.Length; i += WC7.SizeFull)
|
|
{
|
|
byte[] data = new byte[WC7.SizeFull];
|
|
Buffer.BlockCopy(wc7full, i, data, 0, WC7.SizeFull);
|
|
db.Add(new WC7(data));
|
|
}
|
|
return db;
|
|
}
|
|
|
|
// Language Translation
|
|
private void changeMainLanguage(object sender, EventArgs e)
|
|
{
|
|
if (CB_MainLanguage.SelectedIndex < 8)
|
|
curlanguage = GameInfo.lang_val[CB_MainLanguage.SelectedIndex];
|
|
|
|
// Set the culture (makes it easy to pass language to other forms)
|
|
Properties.Settings.Default.Language = curlanguage;
|
|
Thread.CurrentThread.CurrentCulture = new CultureInfo(curlanguage.Substring(0, 2));
|
|
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
|
|
|
|
PKM pk = SAV.getPKM((fieldsInitialized ? preparePKM() : pkm).Data);
|
|
bool alreadyInit = fieldsInitialized;
|
|
fieldsInitialized = false;
|
|
Menu_Options.DropDown.Close();
|
|
InitializeStrings();
|
|
InitializeLanguage();
|
|
string ProgramTitle = Text;
|
|
WinFormsUtil.TranslateInterface(this, curlanguage); // Translate the UI to language.
|
|
Text = ProgramTitle;
|
|
// Recenter PKM SubEditors
|
|
FLP_PKMEditors.Location = new Point((Tab_OTMisc.Width - FLP_PKMEditors.Width)/2, FLP_PKMEditors.Location.Y);
|
|
populateFields(pk); // put data back in form
|
|
fieldsInitialized |= alreadyInit;
|
|
}
|
|
private void InitializeStrings()
|
|
{
|
|
string l = curlanguage;
|
|
GameInfo.Strings = GameInfo.getStrings(l);
|
|
|
|
// Update Legality Strings
|
|
// Clipboard.SetText(string.Join(Environment.NewLine, Util.getLocalization(typeof(LegalityCheckStrings))));
|
|
Task.Run(() => Util.setLocalization(typeof(LegalityCheckStrings)));
|
|
|
|
// Force an update to the met locations
|
|
origintrack = GameVersion.Unknown;
|
|
|
|
// Update Legality Analysis strings
|
|
LegalityAnalysis.movelist = GameInfo.Strings.movelist;
|
|
LegalityAnalysis.specieslist = GameInfo.Strings.specieslist;
|
|
|
|
if (fieldsInitialized)
|
|
updateIVs(null, null); // Prompt an update for the characteristics
|
|
}
|
|
#endregion
|
|
|
|
#region //// PKX WINDOW FUNCTIONS ////
|
|
private void InitializeFields()
|
|
{
|
|
// Now that the ComboBoxes are ready, load the data.
|
|
fieldsInitialized = true;
|
|
pkm.RefreshChecksum();
|
|
|
|
// Load Data
|
|
populateFields(pkm);
|
|
TemplateFields();
|
|
CB_BoxSelect.SelectedIndex = 0;
|
|
}
|
|
private void TemplateFields()
|
|
{
|
|
CB_GameOrigin.SelectedIndex = 0;
|
|
CB_Move1.SelectedValue = 1;
|
|
TB_OT.Text = "PKHeX";
|
|
TB_TID.Text = 12345.ToString();
|
|
TB_SID.Text = 54321.ToString();
|
|
int curlang = Array.IndexOf(GameInfo.lang_val, curlanguage);
|
|
CB_Language.SelectedIndex = curlang > CB_Language.Items.Count - 1 ? 1 : curlang;
|
|
CB_Ball.SelectedIndex = Math.Min(0, CB_Ball.Items.Count - 1);
|
|
CB_Country.SelectedIndex = Math.Min(0, CB_Country.Items.Count - 1);
|
|
CAL_MetDate.Value = CAL_EggDate.Value = DateTime.Today;
|
|
CB_Species.SelectedValue = SAV.MaxSpeciesID;
|
|
CHK_Nicknamed.Checked = false;
|
|
lastData = null;
|
|
}
|
|
private void InitializeLanguage()
|
|
{
|
|
ComboBox[] cbs =
|
|
{
|
|
CB_Country, CB_SubRegion, CB_3DSReg, CB_Language, CB_Ball, CB_HeldItem, CB_Species, DEV_Ability,
|
|
CB_Nature, CB_EncounterType, CB_GameOrigin, CB_HPType
|
|
};
|
|
foreach (var cb in cbs) { cb.DisplayMember = "Text"; cb.ValueMember = "Value"; }
|
|
|
|
// Set the various ComboBox DataSources up with their allowed entries
|
|
setCountrySubRegion(CB_Country, "countries");
|
|
CB_3DSReg.DataSource = Util.getUnsortedCBList("regions3ds");
|
|
|
|
GameInfo.InitializeDataSources(GameInfo.Strings);
|
|
|
|
CB_EncounterType.DataSource = Util.getCBList(GameInfo.Strings.encountertypelist, new[] { 0 }, Legal.Gen4EncounterTypes);
|
|
CB_HPType.DataSource = Util.getCBList(GameInfo.Strings.types.Skip(1).Take(16).ToArray(), null);
|
|
CB_Nature.DataSource = new BindingSource(GameInfo.NatureDataSource, null);
|
|
|
|
populateFilteredDataSources();
|
|
}
|
|
private void populateFilteredDataSources()
|
|
{
|
|
GameInfo.setItemDataSource(HaX, SAV.MaxItemID, SAV.HeldItems, SAV.Generation, SAV.Version, GameInfo.Strings);
|
|
if (SAV.Generation > 1)
|
|
CB_HeldItem.DataSource = new BindingSource(GameInfo.ItemDataSource.Where(i => i.Value <= SAV.MaxItemID).ToList(), null);
|
|
|
|
var languages = Util.getUnsortedCBList("languages");
|
|
if (SAV.Generation < 7)
|
|
languages = languages.Where(l => l.Value <= 8).ToList(); // Korean
|
|
CB_Language.DataSource = languages;
|
|
|
|
CB_Ball.DataSource = new BindingSource(GameInfo.BallDataSource.Where(b => b.Value <= SAV.MaxBallID).ToList(), null);
|
|
CB_Species.DataSource = new BindingSource(GameInfo.SpeciesDataSource.Where(s => s.Value <= SAV.MaxSpeciesID).ToList(), null);
|
|
DEV_Ability.DataSource = new BindingSource(GameInfo.AbilityDataSource.Where(a => a.Value <= SAV.MaxAbilityID).ToList(), null);
|
|
CB_GameOrigin.DataSource = new BindingSource(GameInfo.VersionDataSource.Where(g => g.Value <= SAV.MaxGameID || SAV.Generation >= 3 && g.Value == 15).ToList(), null);
|
|
|
|
// Set the Move ComboBoxes too..
|
|
GameInfo.MoveDataSource = (HaX ? GameInfo.HaXMoveDataSource : GameInfo.LegalMoveDataSource).Where(m => m.Value <= SAV.MaxMoveID).ToList(); // Filter Z-Moves if appropriate
|
|
foreach (ComboBox cb in new[] { CB_Move1, CB_Move2, CB_Move3, CB_Move4, CB_RelearnMove1, CB_RelearnMove2, CB_RelearnMove3, CB_RelearnMove4 })
|
|
{
|
|
cb.DisplayMember = "Text"; cb.ValueMember = "Value";
|
|
cb.DataSource = new BindingSource(GameInfo.MoveDataSource, null);
|
|
}
|
|
}
|
|
private Action getFieldsfromPKM;
|
|
private Func<PKM> getPKMfromFields;
|
|
private byte[] lastData;
|
|
private bool PKMIsUnsaved => fieldsInitialized && Menu_ModifyUnset.Checked && !loadingSAV && lastData != null && lastData.Any(b => b != 0) && !lastData.SequenceEqual(preparePKM().Data);
|
|
|
|
private void setPKMFormatMode(int Format, GameVersion version)
|
|
{
|
|
byte[] extraBytes = new byte[0];
|
|
switch (Format)
|
|
{
|
|
case 1:
|
|
getFieldsfromPKM = populateFieldsPK1;
|
|
getPKMfromFields = preparePK1;
|
|
break;
|
|
case 2:
|
|
getFieldsfromPKM = populateFieldsPK2;
|
|
getPKMfromFields = preparePK2;
|
|
break;
|
|
case 3:
|
|
if (version == GameVersion.COLO)
|
|
{
|
|
getFieldsfromPKM = populateFieldsCK3;
|
|
getPKMfromFields = prepareCK3;
|
|
extraBytes = CK3.ExtraBytes;
|
|
break;
|
|
}
|
|
if (version == GameVersion.XD)
|
|
{
|
|
getFieldsfromPKM = populateFieldsXK3;
|
|
getPKMfromFields = prepareXK3;
|
|
extraBytes = XK3.ExtraBytes;
|
|
break;
|
|
}
|
|
getFieldsfromPKM = populateFieldsPK3;
|
|
getPKMfromFields = preparePK3;
|
|
extraBytes = PK3.ExtraBytes;
|
|
break;
|
|
case 4:
|
|
if (version == GameVersion.BATREV)
|
|
{
|
|
getFieldsfromPKM = populateFieldsBK4;
|
|
getPKMfromFields = prepareBK4;
|
|
}
|
|
else
|
|
{
|
|
getFieldsfromPKM = populateFieldsPK4;
|
|
getPKMfromFields = preparePK4;
|
|
}
|
|
extraBytes = PK4.ExtraBytes;
|
|
break;
|
|
case 5:
|
|
getFieldsfromPKM = populateFieldsPK5;
|
|
getPKMfromFields = preparePK5;
|
|
extraBytes = PK5.ExtraBytes;
|
|
break;
|
|
case 6:
|
|
getFieldsfromPKM = populateFieldsPK6;
|
|
getPKMfromFields = preparePK6;
|
|
extraBytes = PK6.ExtraBytes;
|
|
break;
|
|
case 7:
|
|
getFieldsfromPKM = populateFieldsPK7;
|
|
getPKMfromFields = preparePK7;
|
|
extraBytes = PK7.ExtraBytes;
|
|
break;
|
|
}
|
|
|
|
// Load Extra Byte List
|
|
GB_ExtraBytes.Visible = GB_ExtraBytes.Enabled = extraBytes.Length != 0;
|
|
if (GB_ExtraBytes.Enabled)
|
|
{
|
|
CB_ExtraBytes.Items.Clear();
|
|
foreach (byte b in extraBytes)
|
|
CB_ExtraBytes.Items.Add("0x" + b.ToString("X2"));
|
|
CB_ExtraBytes.SelectedIndex = 0;
|
|
}
|
|
}
|
|
public void populateFields(PKM pk, bool focus = true)
|
|
{
|
|
if (pk == null) { WinFormsUtil.Error("Attempted to load a null file."); return; }
|
|
|
|
if ((pk.Format >= 3 && pk.Format > SAV.Generation) // pk3-7, can't go backwards
|
|
|| (pk.Format <= 2 && SAV.Generation > 2 && SAV.Generation < 7)) // pk1-2, can't go 3-6
|
|
{ WinFormsUtil.Alert($"Can't load Gen{pk.Format} to Gen{SAV.Generation} games."); return; }
|
|
|
|
bool oldInit = fieldsInitialized;
|
|
fieldsInitialized = fieldsLoaded = false;
|
|
if (focus)
|
|
Tab_Main.Focus();
|
|
|
|
pkm = pk.Clone();
|
|
|
|
if (fieldsInitialized & !pkm.ChecksumValid)
|
|
WinFormsUtil.Alert("PKM File has an invalid checksum.");
|
|
|
|
if (pkm.Format != SAV.Generation) // past gen format
|
|
{
|
|
string c;
|
|
pkm = PKMConverter.convertToFormat(pkm, SAV.PKMType, out c);
|
|
if (pk.Format != pkm.Format && focus) // converted
|
|
WinFormsUtil.Alert("Converted File.");
|
|
}
|
|
|
|
try { getFieldsfromPKM(); }
|
|
catch { fieldsInitialized = oldInit; throw; }
|
|
|
|
CB_EncounterType.Visible = Label_EncounterType.Visible = pkm.Gen4 && SAV.Generation < 7;
|
|
fieldsInitialized = oldInit;
|
|
updateIVs(null, null);
|
|
updatePKRSInfected(null, null);
|
|
updatePKRSCured(null, null);
|
|
|
|
if (HaX) // Load original values from pk not pkm
|
|
{
|
|
MT_Level.Text = (pk.Stat_HPMax != 0 ? pk.Stat_Level : PKX.getLevel(pk.Species, pk.EXP)).ToString();
|
|
TB_EXP.Text = pk.EXP.ToString();
|
|
MT_Form.Text = pk.AltForm.ToString();
|
|
if (pk.Stat_HPMax != 0) // stats present
|
|
{
|
|
Stat_HP.Text = pk.Stat_HPCurrent.ToString();
|
|
Stat_ATK.Text = pk.Stat_ATK.ToString();
|
|
Stat_DEF.Text = pk.Stat_DEF.ToString();
|
|
Stat_SPA.Text = pk.Stat_SPA.ToString();
|
|
Stat_SPD.Text = pk.Stat_SPD.ToString();
|
|
Stat_SPE.Text = pk.Stat_SPE.ToString();
|
|
}
|
|
}
|
|
fieldsLoaded = true;
|
|
|
|
Label_HatchCounter.Visible = CHK_IsEgg.Checked && SAV.Generation > 1;
|
|
Label_Friendship.Visible = !CHK_IsEgg.Checked && SAV.Generation > 1;
|
|
|
|
// Set the Preview Box
|
|
dragout.Image = pk.Sprite();
|
|
setMarkings();
|
|
updateLegality();
|
|
lastData = preparePKM()?.Data;
|
|
}
|
|
|
|
// General Use Functions shared by other Forms //
|
|
internal static void setCountrySubRegion(ComboBox CB, string type)
|
|
{
|
|
int index = CB.SelectedIndex;
|
|
// fix for Korean / Chinese being swapped
|
|
string cl = curlanguage + "";
|
|
cl = cl == "zh" ? "ko" : cl == "ko" ? "zh" : cl;
|
|
|
|
CB.DataSource = Util.getCBList(type, cl);
|
|
|
|
if (index > 0 && index < CB.Items.Count && fieldsInitialized)
|
|
CB.SelectedIndex = index;
|
|
}
|
|
private void setForms()
|
|
{
|
|
int species = WinFormsUtil.getIndex(CB_Species);
|
|
if (SAV.Generation < 4 && species != 201)
|
|
{
|
|
Label_Form.Visible = CB_Form.Visible = CB_Form.Enabled = false;
|
|
return;
|
|
}
|
|
|
|
bool hasForms = SAV.Personal[species].HasFormes || new[] { 201, 664, 665, 414 }.Contains(species);
|
|
CB_Form.Enabled = CB_Form.Visible = Label_Form.Visible = hasForms;
|
|
|
|
if (HaX && SAV.Generation >= 4)
|
|
Label_Form.Visible = true;
|
|
|
|
if (!hasForms)
|
|
return;
|
|
|
|
var ds = PKX.getFormList(species, GameInfo.Strings.types, GameInfo.Strings.forms, gendersymbols, SAV.Generation).ToList();
|
|
if (ds.Count == 1 && string.IsNullOrEmpty(ds[0])) // empty (Alolan Totems)
|
|
CB_Form.Enabled = CB_Form.Visible = Label_Form.Visible = false;
|
|
else CB_Form.DataSource = ds;
|
|
}
|
|
private void setAbilityList()
|
|
{
|
|
if (SAV.Generation < 3) // no abilities
|
|
return;
|
|
|
|
int formnum = 0;
|
|
int species = WinFormsUtil.getIndex(CB_Species);
|
|
if (SAV.Generation > 3) // has forms
|
|
formnum = CB_Form.SelectedIndex;
|
|
|
|
int[] abils = SAV.Personal.getAbilities(species, formnum);
|
|
if (abils[1] == 0 && SAV.Generation != 3)
|
|
abils[1] = abils[0];
|
|
string[] abilIdentifier = {" (1)", " (2)", " (H)"};
|
|
List<string> ability_list = abils.Where(a => a != 0).Select((t, i) => GameInfo.Strings.abilitylist[t] + abilIdentifier[i]).ToList();
|
|
if (!ability_list.Any())
|
|
ability_list.Add(GameInfo.Strings.abilitylist[0] + abilIdentifier[0]);
|
|
|
|
bool tmp = fieldsLoaded;
|
|
fieldsLoaded = false;
|
|
int abil = CB_Ability.SelectedIndex;
|
|
CB_Ability.DataSource = ability_list;
|
|
CB_Ability.SelectedIndex = abil < 0 || abil >= CB_Ability.Items.Count ? 0 : abil;
|
|
fieldsLoaded = tmp;
|
|
}
|
|
// PKX Data Calculation Functions //
|
|
private void setIsShiny(object sender)
|
|
{
|
|
if (sender == TB_PID)
|
|
pkm.PID = Util.getHEXval(TB_PID.Text);
|
|
else if (sender == TB_TID)
|
|
pkm.TID = (int)Util.ToUInt32(TB_TID.Text);
|
|
else if (sender == TB_SID)
|
|
pkm.SID = (int)Util.ToUInt32(TB_SID.Text);
|
|
|
|
bool isShiny = pkm.IsShiny;
|
|
|
|
// Set the Controls
|
|
BTN_Shinytize.Visible = BTN_Shinytize.Enabled = !isShiny;
|
|
Label_IsShiny.Visible = isShiny;
|
|
|
|
// Refresh Markings (for Shiny Star if applicable)
|
|
setMarkings();
|
|
}
|
|
private void setMarkings()
|
|
{
|
|
Func<bool, double> getOpacity = b => b ? 1 : 0.175;
|
|
PictureBox[] pba = { PB_Mark1, PB_Mark2, PB_Mark3, PB_Mark4, PB_Mark5, PB_Mark6 };
|
|
for (int i = 0; i < pba.Length; i++)
|
|
pba[i].Image = ImageUtil.ChangeOpacity(pba[i].InitialImage, getOpacity(pkm.Markings[i] != 0));
|
|
|
|
PB_MarkShiny.Image = ImageUtil.ChangeOpacity(PB_MarkShiny.InitialImage, getOpacity(!BTN_Shinytize.Enabled));
|
|
PB_MarkCured.Image = ImageUtil.ChangeOpacity(PB_MarkCured.InitialImage, getOpacity(CHK_Cured.Checked));
|
|
|
|
PB_MarkPentagon.Image = ImageUtil.ChangeOpacity(PB_MarkPentagon.InitialImage, getOpacity(pkm.Gen6));
|
|
|
|
// Gen7 Markings
|
|
if (pkm.Format != 7)
|
|
return;
|
|
|
|
PB_MarkAlola.Image = ImageUtil.ChangeOpacity(PB_MarkAlola.InitialImage, getOpacity(pkm.Gen7));
|
|
PB_MarkVC.Image = ImageUtil.ChangeOpacity(PB_MarkVC.InitialImage, getOpacity(pkm.VC));
|
|
PB_MarkHorohoro.Image = ImageUtil.ChangeOpacity(PB_MarkHorohoro.InitialImage, getOpacity(pkm.Horohoro));
|
|
|
|
for (int i = 0; i < pba.Length; i++)
|
|
{
|
|
switch (pkm.Markings[i])
|
|
{
|
|
case 1:
|
|
pba[i].Image = ImageUtil.ChangeAllColorTo(pba[i].Image, Color.FromArgb(000, 191, 255));
|
|
break;
|
|
case 2:
|
|
pba[i].Image = ImageUtil.ChangeAllColorTo(pba[i].Image, Color.FromArgb(255, 117, 179));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// Clicked Label Shortcuts //
|
|
private bool QR6Notified;
|
|
private void clickQR(object sender, EventArgs e)
|
|
{
|
|
if (ModifierKeys == Keys.Alt)
|
|
{
|
|
// Fetch data from QR code...
|
|
byte[] ekx = QR.getQRData();
|
|
|
|
if (ekx == null) return;
|
|
|
|
PKM pk = PKMConverter.getPKMfromBytes(ekx, prefer: SAV.Generation);
|
|
if (pk == null) { WinFormsUtil.Alert("Decoded data not a valid PKM.", $"QR Data Size: {ekx.Length}"); }
|
|
else
|
|
{
|
|
if (!pk.Valid || pk.Species <= 0)
|
|
{ WinFormsUtil.Alert("Invalid data detected."); return; }
|
|
|
|
string c; PKM pkz = PKMConverter.convertToFormat(pk, SAV.PKMType, out c);
|
|
if (pkz == null)
|
|
{ WinFormsUtil.Alert(c); return; }
|
|
|
|
populateFields(pkz);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!verifiedPKM()) return;
|
|
PKM pkx = preparePKM();
|
|
|
|
Image qr;
|
|
switch (pkx.Format)
|
|
{
|
|
case 7:
|
|
qr = QR.GenerateQRCode7((PK7) pkx);
|
|
break;
|
|
default:
|
|
if (pkx.Format == 6 && !QR6Notified) // hint that the user should not be using QR6 injection
|
|
{
|
|
WinFormsUtil.Alert("QR codes are deprecated in favor of other methods.",
|
|
"Consider utilizing homebrew or on-the-fly RAM editing custom firmware (PKMN-NTR).");
|
|
QR6Notified = true;
|
|
}
|
|
qr = QR.getQRImage(pkx.EncryptedBoxData, QR.getQRServer(pkx.Format));
|
|
break;
|
|
}
|
|
|
|
if (qr == null) return;
|
|
|
|
var sprite = dragout.Image;
|
|
var la = new LegalityAnalysis(pkx);
|
|
if (la.Parsed)
|
|
{
|
|
var img = la.Valid ? Resources.valid : Resources.warn;
|
|
sprite = ImageUtil.LayerImage(sprite, img, 24, 0, 1);
|
|
}
|
|
|
|
string[] r = pkx.QRText;
|
|
string refer = $"PKHeX ({Resources.ProgramVersion})";
|
|
new QR(qr, sprite, r[0], r[1], r[2], $"{refer} ({pkx.GetType().Name})", pkx).ShowDialog();
|
|
}
|
|
}
|
|
private void clickFriendship(object sender, EventArgs e)
|
|
{
|
|
if (ModifierKeys == Keys.Control) // prompt to reset
|
|
TB_Friendship.Text = pkm.CurrentFriendship.ToString();
|
|
else
|
|
TB_Friendship.Text = TB_Friendship.Text == "255" ? SAV.Personal[pkm.Species].BaseFriendship.ToString() : "255";
|
|
}
|
|
private void clickLevel(object sender, EventArgs e)
|
|
{
|
|
if (ModifierKeys == Keys.Control)
|
|
{
|
|
((MaskedTextBox)sender).Text = "100";
|
|
}
|
|
}
|
|
private void clickGender(object sender, EventArgs e)
|
|
{
|
|
// Get Gender Threshold
|
|
int gt = SAV.Personal.getFormeEntry(WinFormsUtil.getIndex(CB_Species), CB_Form.SelectedIndex).Gender;
|
|
|
|
if (gt == 255 || gt == 0 || gt == 254) // Single gender/genderless
|
|
return;
|
|
|
|
if (gt >= 255) return;
|
|
// If not a single gender(less) species: (should be <254 but whatever, 255 never happens)
|
|
|
|
int newGender = PKX.getGender(Label_Gender.Text) ^ 1;
|
|
if (SAV.Generation == 2)
|
|
do { TB_ATKIV.Text = (Util.rnd32() & SAV.MaxIV).ToString(); } while (PKX.getGender(Label_Gender.Text) != newGender);
|
|
else if (SAV.Generation <= 4)
|
|
{
|
|
pkm.Species = WinFormsUtil.getIndex(CB_Species);
|
|
pkm.Version = WinFormsUtil.getIndex(CB_GameOrigin);
|
|
pkm.Nature = WinFormsUtil.getIndex(CB_Nature);
|
|
pkm.AltForm = CB_Form.SelectedIndex;
|
|
|
|
pkm.setPIDGender(newGender);
|
|
TB_PID.Text = pkm.PID.ToString("X8");
|
|
}
|
|
pkm.Gender = newGender;
|
|
Label_Gender.Text = gendersymbols[pkm.Gender];
|
|
Label_Gender.ForeColor = pkm.Gender == 2 ? Label_Species.ForeColor : (pkm.Gender == 1 ? Color.Red : Color.Blue);
|
|
|
|
if (PKX.getGender(CB_Form.Text) < 2) // Gendered Forms
|
|
CB_Form.SelectedIndex = PKX.getGender(Label_Gender.Text);
|
|
|
|
getQuickFiller(dragout);
|
|
}
|
|
private void clickPPUps(object sender, EventArgs e)
|
|
{
|
|
CB_PPu1.SelectedIndex = ModifierKeys != Keys.Control && WinFormsUtil.getIndex(CB_Move1) > 0 ? 3 : 0;
|
|
CB_PPu2.SelectedIndex = ModifierKeys != Keys.Control && WinFormsUtil.getIndex(CB_Move2) > 0 ? 3 : 0;
|
|
CB_PPu3.SelectedIndex = ModifierKeys != Keys.Control && WinFormsUtil.getIndex(CB_Move3) > 0 ? 3 : 0;
|
|
CB_PPu4.SelectedIndex = ModifierKeys != Keys.Control && WinFormsUtil.getIndex(CB_Move4) > 0 ? 3 : 0;
|
|
}
|
|
private void clickMarking(object sender, EventArgs e)
|
|
{
|
|
PictureBox[] pba = { PB_Mark1, PB_Mark2, PB_Mark3, PB_Mark4, PB_Mark5, PB_Mark6 };
|
|
int index = Array.IndexOf(pba, sender);
|
|
|
|
// Handling Gens 3-6
|
|
int[] markings = pkm.Markings;
|
|
switch (pkm.Format)
|
|
{
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
case 6: // on/off
|
|
markings[index] ^= 1; // toggle
|
|
pkm.Markings = markings;
|
|
break;
|
|
case 7: // 0 (none) | 1 (blue) | 2 (pink)
|
|
markings[index] = (markings[index]+1)%3; // cycle
|
|
pkm.Markings = markings;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
setMarkings();
|
|
}
|
|
private void clickStatLabel(object sender, MouseEventArgs e)
|
|
{
|
|
if (!(ModifierKeys == Keys.Control || ModifierKeys == Keys.Alt))
|
|
return;
|
|
|
|
if (sender == Label_SPC)
|
|
sender = Label_SPA;
|
|
int index = Array.IndexOf(new[] { Label_HP, Label_ATK, Label_DEF, Label_SPA, Label_SPD, Label_SPE }, sender);
|
|
|
|
if (ModifierKeys == Keys.Alt) // EV
|
|
{
|
|
var mt = new[] {TB_HPEV, TB_ATKEV, TB_DEFEV, TB_SPAEV, TB_SPDEV, TB_SPEEV}[index];
|
|
if (e.Button == MouseButtons.Left) // max
|
|
mt.Text = SAV.Generation >= 3
|
|
? Math.Min(Math.Max(510 - Util.ToInt32(TB_EVTotal.Text) + Util.ToInt32(mt.Text), 0), 252).ToString()
|
|
: ushort.MaxValue.ToString();
|
|
else // min
|
|
mt.Text = 0.ToString();
|
|
}
|
|
else
|
|
new[] {TB_HPIV, TB_ATKIV, TB_DEFIV, TB_SPAIV, TB_SPDIV, TB_SPEIV}[index].Text =
|
|
(e.Button == MouseButtons.Left ? SAV.MaxIV : 0).ToString();
|
|
}
|
|
private void clickIV(object sender, EventArgs e)
|
|
{
|
|
if (ModifierKeys == Keys.Control)
|
|
if (SAV.Generation < 7)
|
|
((MaskedTextBox) sender).Text = SAV.MaxIV.ToString();
|
|
else
|
|
{
|
|
var index = Array.IndexOf(new[] {TB_HPIV, TB_ATKIV, TB_DEFIV, TB_SPAIV, TB_SPDIV, TB_SPEIV}, sender);
|
|
pkm.HyperTrainInvert(index);
|
|
updateIVs(sender, e);
|
|
}
|
|
else if (ModifierKeys == Keys.Alt)
|
|
((MaskedTextBox) sender).Text = 0.ToString();
|
|
}
|
|
private void clickEV(object sender, EventArgs e)
|
|
{
|
|
MaskedTextBox mt = (MaskedTextBox)sender;
|
|
if (ModifierKeys == Keys.Control) // EV
|
|
mt.Text = SAV.Generation >= 3
|
|
? Math.Min(Math.Max(510 - Util.ToInt32(TB_EVTotal.Text) + Util.ToInt32(mt.Text), 0), 252).ToString()
|
|
: ushort.MaxValue.ToString();
|
|
else if (ModifierKeys == Keys.Alt)
|
|
mt.Text = 0.ToString();
|
|
}
|
|
private void clickOT(object sender, EventArgs e)
|
|
{
|
|
if (!SAV.Exportable)
|
|
return;
|
|
|
|
// Get Save Information
|
|
TB_OT.Text = SAV.OT;
|
|
Label_OTGender.Text = gendersymbols[SAV.Gender % 2];
|
|
Label_OTGender.ForeColor = SAV.Gender == 1 ? Color.Red : Color.Blue;
|
|
TB_TID.Text = SAV.TID.ToString("00000");
|
|
TB_SID.Text = SAV.SID.ToString("00000");
|
|
|
|
if (SAV.Game >= 0)
|
|
CB_GameOrigin.SelectedValue = SAV.Game;
|
|
if (SAV.Language >= 0)
|
|
CB_Language.SelectedValue = SAV.Language;
|
|
if (SAV.HasGeolocation)
|
|
{
|
|
CB_3DSReg.SelectedValue = SAV.ConsoleRegion;
|
|
CB_Country.SelectedValue = SAV.Country;
|
|
CB_SubRegion.SelectedValue = SAV.SubRegion;
|
|
}
|
|
updateNickname(null, null);
|
|
}
|
|
private void clickCT(object sender, EventArgs e)
|
|
{
|
|
if (TB_OTt2.Text.Length > 0)
|
|
Label_CTGender.Text = gendersymbols[SAV.Gender % 2];
|
|
}
|
|
private void clickGT(object sender, EventArgs e)
|
|
{
|
|
if (!GB_nOT.Visible)
|
|
return;
|
|
if (sender == GB_OT)
|
|
{
|
|
pkm.CurrentHandler = 0;
|
|
GB_OT.BackgroundImage = mixedHighlight;
|
|
GB_nOT.BackgroundImage = null;
|
|
}
|
|
else if (TB_OTt2.Text.Length > 0)
|
|
{
|
|
pkm.CurrentHandler = 1;
|
|
GB_OT.BackgroundImage = null;
|
|
GB_nOT.BackgroundImage = mixedHighlight;
|
|
}
|
|
TB_Friendship.Text = pkm.CurrentFriendship.ToString();
|
|
}
|
|
private void clickTRGender(object sender, EventArgs e)
|
|
{
|
|
Label lbl = sender as Label;
|
|
if (!string.IsNullOrWhiteSpace(lbl?.Text)) // set gender label (toggle M/F)
|
|
{
|
|
int gender = PKX.getGender(lbl.Text) ^ 1;
|
|
lbl.Text = gendersymbols[gender];
|
|
lbl.ForeColor = gender == 1 ? Color.Red : Color.Blue;
|
|
}
|
|
}
|
|
private void clickMoves(object sender, EventArgs e)
|
|
{
|
|
updateLegality(skipMoveRepop:true);
|
|
if (sender == GB_CurrentMoves)
|
|
{
|
|
bool random = ModifierKeys == Keys.Control;
|
|
int[] m = Legality.getSuggestedMoves(tm: random, tutor: random, reminder: random);
|
|
if (m == null)
|
|
{ WinFormsUtil.Alert("Suggestions are not enabled for this PKM format."); return; }
|
|
|
|
if (random)
|
|
Util.Shuffle(m);
|
|
if (m.Length > 4)
|
|
m = m.Skip(m.Length - 4).ToArray();
|
|
Array.Resize(ref m, 4);
|
|
|
|
if (pkm.Moves.SequenceEqual(m))
|
|
return;
|
|
|
|
string r = string.Join(Environment.NewLine, m.Select(v => v >= GameInfo.Strings.movelist.Length ? "ERROR" : GameInfo.Strings.movelist[v]));
|
|
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Apply suggested current moves?", r))
|
|
return;
|
|
|
|
CB_Move1.SelectedValue = m[0];
|
|
CB_Move2.SelectedValue = m[1];
|
|
CB_Move3.SelectedValue = m[2];
|
|
CB_Move4.SelectedValue = m[3];
|
|
}
|
|
else if (sender == GB_RelearnMoves)
|
|
{
|
|
int[] m = Legality.getSuggestedRelearn();
|
|
if (!pkm.WasEgg && !pkm.WasEvent && !pkm.WasEventEgg && !pkm.WasLink)
|
|
{
|
|
var encounter = Legality.getSuggestedMetInfo();
|
|
if (encounter != null)
|
|
m = encounter.Relearn;
|
|
}
|
|
|
|
if (pkm.RelearnMoves.SequenceEqual(m))
|
|
return;
|
|
|
|
string r = string.Join(Environment.NewLine, m.Select(v => v >= GameInfo.Strings.movelist.Length ? "ERROR" : GameInfo.Strings.movelist[v]));
|
|
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Apply suggested relearn moves?", r))
|
|
return;
|
|
|
|
CB_RelearnMove1.SelectedValue = m[0];
|
|
CB_RelearnMove2.SelectedValue = m[1];
|
|
CB_RelearnMove3.SelectedValue = m[2];
|
|
CB_RelearnMove4.SelectedValue = m[3];
|
|
}
|
|
|
|
updateLegality();
|
|
}
|
|
private void clickMetLocation(object sender, EventArgs e)
|
|
{
|
|
if (HaX)
|
|
return;
|
|
|
|
pkm = preparePKM();
|
|
updateLegality(skipMoveRepop:true);
|
|
if (Legality.Valid)
|
|
return;
|
|
|
|
var encounter = Legality.getSuggestedMetInfo();
|
|
if (encounter == null || (pkm.Format >= 3 && encounter.Location < 0))
|
|
{
|
|
WinFormsUtil.Alert("Unable to provide a suggestion.");
|
|
return;
|
|
}
|
|
|
|
int level = encounter.Level;
|
|
int location = encounter.Location;
|
|
int minlvl = Legal.getLowestLevel(pkm, encounter.Species);
|
|
if (minlvl == 0)
|
|
minlvl = level;
|
|
|
|
if (pkm.CurrentLevel >= minlvl && pkm.Met_Level == level && pkm.Met_Location == location)
|
|
return;
|
|
if (minlvl < level)
|
|
minlvl = level;
|
|
|
|
var suggestion = new List<string> {"Suggested:"};
|
|
if (pkm.Format >= 3)
|
|
{
|
|
var met_list = GameInfo.getLocationList((GameVersion)pkm.Version, SAV.Generation, egg: false);
|
|
var locstr = met_list.FirstOrDefault(loc => loc.Value == location)?.Text;
|
|
suggestion.Add($"Met Location: {locstr}");
|
|
suggestion.Add($"Met Level: {level}");
|
|
}
|
|
if (pkm.CurrentLevel < minlvl)
|
|
suggestion.Add($"Current Level: {minlvl}");
|
|
|
|
if (suggestion.Count == 1) // no suggestion
|
|
return;
|
|
|
|
string suggest = string.Join(Environment.NewLine, suggestion);
|
|
if (WinFormsUtil.Prompt(MessageBoxButtons.YesNo, suggest) != DialogResult.Yes)
|
|
return;
|
|
|
|
if (pkm.Format >= 3)
|
|
{
|
|
TB_MetLevel.Text = level.ToString();
|
|
CB_MetLocation.SelectedValue = location;
|
|
}
|
|
|
|
if (pkm.CurrentLevel < minlvl)
|
|
TB_Level.Text = minlvl.ToString();
|
|
|
|
pkm = preparePKM();
|
|
updateLegality();
|
|
}
|
|
// Prompted Updates of PKX Functions //
|
|
private bool changingFields;
|
|
private void updateBall(object sender, EventArgs e)
|
|
{
|
|
PB_Ball.Image = PKMUtil.getBallSprite(WinFormsUtil.getIndex(CB_Ball));
|
|
}
|
|
private void updateEXPLevel(object sender, EventArgs e)
|
|
{
|
|
if (changingFields || !fieldsInitialized) return;
|
|
|
|
changingFields = true;
|
|
if (sender == TB_EXP)
|
|
{
|
|
// Change the Level
|
|
uint EXP = Util.ToUInt32(TB_EXP.Text);
|
|
int Species = WinFormsUtil.getIndex(CB_Species);
|
|
int Level = PKX.getLevel(Species, EXP);
|
|
if (Level == 100)
|
|
EXP = PKX.getEXP(100, Species);
|
|
|
|
TB_Level.Text = Level.ToString();
|
|
if (!HaX)
|
|
TB_EXP.Text = EXP.ToString();
|
|
else if (Level <= 100 && Util.ToInt32(MT_Level.Text) <= 100)
|
|
MT_Level.Text = Level.ToString();
|
|
}
|
|
else
|
|
{
|
|
// Change the XP
|
|
int Level = Util.ToInt32((HaX ? MT_Level : TB_Level).Text);
|
|
if (Level > 100) TB_Level.Text = "100";
|
|
if (Level > byte.MaxValue) MT_Level.Text = "255";
|
|
|
|
if (Level <= 100)
|
|
TB_EXP.Text = PKX.getEXP(Level, WinFormsUtil.getIndex(CB_Species)).ToString();
|
|
}
|
|
changingFields = false;
|
|
if (fieldsLoaded) // store values back
|
|
{
|
|
pkm.EXP = Util.ToUInt32(TB_EXP.Text);
|
|
pkm.Stat_Level = Util.ToInt32((HaX ? MT_Level : TB_Level).Text);
|
|
}
|
|
updateStats();
|
|
updateLegality();
|
|
}
|
|
private void updateHPType(object sender, EventArgs e)
|
|
{
|
|
if (changingFields || !fieldsInitialized) return;
|
|
changingFields = true;
|
|
int[] ivs =
|
|
{
|
|
Util.ToInt32(TB_HPIV.Text), Util.ToInt32(TB_ATKIV.Text), Util.ToInt32(TB_DEFIV.Text),
|
|
Util.ToInt32(TB_SPAIV.Text), Util.ToInt32(TB_SPDIV.Text), Util.ToInt32(TB_SPEIV.Text)
|
|
};
|
|
|
|
// Change IVs to match the new Hidden Power
|
|
int[] newIVs = PKX.setHPIVs(WinFormsUtil.getIndex(CB_HPType), ivs);
|
|
TB_HPIV.Text = newIVs[0].ToString();
|
|
TB_ATKIV.Text = newIVs[1].ToString();
|
|
TB_DEFIV.Text = newIVs[2].ToString();
|
|
TB_SPAIV.Text = newIVs[3].ToString();
|
|
TB_SPDIV.Text = newIVs[4].ToString();
|
|
TB_SPEIV.Text = newIVs[5].ToString();
|
|
|
|
// Refresh View
|
|
changingFields = false;
|
|
updateIVs(null, null);
|
|
}
|
|
private void updateIVs(object sender, EventArgs e)
|
|
{
|
|
if (changingFields || !fieldsInitialized) return;
|
|
if (sender != null && Util.ToInt32(((MaskedTextBox) sender).Text) > SAV.MaxIV)
|
|
((MaskedTextBox) sender).Text = SAV.MaxIV.ToString("00");
|
|
|
|
changingFields = true;
|
|
|
|
// Update IVs
|
|
pkm.IV_HP = Util.ToInt32(TB_HPIV.Text);
|
|
pkm.IV_ATK = Util.ToInt32(TB_ATKIV.Text);
|
|
pkm.IV_DEF = Util.ToInt32(TB_DEFIV.Text);
|
|
pkm.IV_SPE = Util.ToInt32(TB_SPEIV.Text);
|
|
pkm.IV_SPA = Util.ToInt32(TB_SPAIV.Text);
|
|
pkm.IV_SPD = Util.ToInt32(TB_SPDIV.Text);
|
|
|
|
var IV_Boxes = new[] {TB_HPIV, TB_ATKIV, TB_DEFIV, TB_SPAIV, TB_SPDIV, TB_SPEIV};
|
|
var HT_Vals = new[] {pkm.HT_HP, pkm.HT_ATK, pkm.HT_DEF, pkm.HT_SPA, pkm.HT_SPD, pkm.HT_SPE};
|
|
for (int i = 0; i < IV_Boxes.Length; i++)
|
|
if (HT_Vals[i])
|
|
IV_Boxes[i].BackColor = Color.LightGreen;
|
|
else
|
|
IV_Boxes[i].ResetBackColor();
|
|
|
|
if (SAV.Generation < 3)
|
|
{
|
|
TB_HPIV.Text = pkm.IV_HP.ToString();
|
|
TB_SPDIV.Text = TB_SPAIV.Text;
|
|
if (SAV.Generation == 2)
|
|
{
|
|
Label_Gender.Text = gendersymbols[pkm.Gender];
|
|
Label_Gender.ForeColor = pkm.Gender == 2
|
|
? Label_Species.ForeColor
|
|
: (pkm.Gender == 1 ? Color.Red : Color.Blue);
|
|
if (pkm.Species == 201 && e != null) // Unown
|
|
CB_Form.SelectedIndex = pkm.AltForm;
|
|
}
|
|
setIsShiny(null);
|
|
getQuickFiller(dragout);
|
|
}
|
|
|
|
CB_HPType.SelectedValue = pkm.HPType;
|
|
changingFields = false;
|
|
|
|
// Potential Reading
|
|
L_Potential.Text = (unicode
|
|
? new[] {"★☆☆☆", "★★☆☆", "★★★☆", "★★★★"}
|
|
: new[] {"+", "++", "+++", "++++"}
|
|
)[pkm.PotentialRating];
|
|
|
|
TB_IVTotal.Text = pkm.IVs.Sum().ToString();
|
|
|
|
int characteristic = pkm.Characteristic;
|
|
L_Characteristic.Visible = Label_CharacteristicPrefix.Visible = characteristic > -1;
|
|
if (characteristic > -1)
|
|
L_Characteristic.Text = GameInfo.Strings.characteristics[pkm.Characteristic];
|
|
updateStats();
|
|
}
|
|
private void updateEVs(object sender, EventArgs e)
|
|
{
|
|
if (sender is MaskedTextBox)
|
|
{
|
|
MaskedTextBox m = (MaskedTextBox)sender;
|
|
if (Util.ToInt32(m.Text) > SAV.MaxEV)
|
|
{ m.Text = SAV.MaxEV.ToString(); return; } // recursive on text set
|
|
}
|
|
|
|
changingFields = true;
|
|
if (sender == TB_HPEV) pkm.EV_HP = Util.ToInt32(TB_HPEV.Text);
|
|
else if (sender == TB_ATKEV) pkm.EV_ATK = Util.ToInt32(TB_ATKEV.Text);
|
|
else if (sender == TB_DEFEV) pkm.EV_DEF = Util.ToInt32(TB_DEFEV.Text);
|
|
else if (sender == TB_SPEEV) pkm.EV_SPE = Util.ToInt32(TB_SPEEV.Text);
|
|
else if (sender == TB_SPAEV) pkm.EV_SPA = Util.ToInt32(TB_SPAEV.Text);
|
|
else if (sender == TB_SPDEV) pkm.EV_SPD = Util.ToInt32(TB_SPDEV.Text);
|
|
|
|
if (SAV.Generation < 3)
|
|
TB_SPDEV.Text = TB_SPAEV.Text;
|
|
|
|
int evtotal = pkm.EVs.Sum();
|
|
|
|
if (evtotal > 510) // Background turns Red
|
|
TB_EVTotal.BackColor = Color.Red;
|
|
else if (evtotal == 510) // Maximum EVs
|
|
TB_EVTotal.BackColor = Color.Honeydew;
|
|
else if (evtotal == 508) // Fishy EVs
|
|
TB_EVTotal.BackColor = Color.LightYellow;
|
|
else TB_EVTotal.BackColor = TB_IVTotal.BackColor;
|
|
|
|
TB_EVTotal.Text = evtotal.ToString();
|
|
EVTip.SetToolTip(TB_EVTotal, $"Remaining: {510 - evtotal}");
|
|
changingFields = false;
|
|
updateStats();
|
|
}
|
|
private void updateRandomIVs(object sender, EventArgs e)
|
|
{
|
|
changingFields = true;
|
|
if (ModifierKeys == Keys.Control || ModifierKeys == Keys.Shift)
|
|
{
|
|
// Max IVs
|
|
TB_HPIV.Text = SAV.MaxIV.ToString();
|
|
TB_ATKIV.Text = SAV.MaxIV.ToString();
|
|
TB_DEFIV.Text = SAV.MaxIV.ToString();
|
|
TB_SPAIV.Text = SAV.MaxIV.ToString();
|
|
TB_SPDIV.Text = SAV.MaxIV.ToString();
|
|
TB_SPEIV.Text = SAV.MaxIV.ToString();
|
|
}
|
|
else
|
|
{
|
|
bool IV3 = Legal.Legends.Contains(pkm.Species) || Legal.SubLegends.Contains(pkm.Species);
|
|
|
|
int[] IVs = new int[6];
|
|
for (int i = 0; i < 6; i++)
|
|
IVs[i] = (int)(Util.rnd32() & SAV.MaxIV);
|
|
if (IV3)
|
|
for (int i = 0; i < 3; i++)
|
|
IVs[i] = SAV.MaxIV;
|
|
Util.Shuffle(IVs); // Randomize IV order
|
|
|
|
var IVBoxes = new[] {TB_HPIV, TB_ATKIV, TB_DEFIV, TB_SPAIV, TB_SPDIV, TB_SPEIV};
|
|
for (int i = 0; i < 6; i++)
|
|
IVBoxes[i].Text = IVs[i].ToString();
|
|
}
|
|
changingFields = false;
|
|
updateIVs(null, e);
|
|
}
|
|
private void updateRandomEVs(object sender, EventArgs e)
|
|
{
|
|
changingFields = true;
|
|
|
|
var tb = new[] {TB_HPEV, TB_ATKEV, TB_DEFEV, TB_SPAEV, TB_SPDEV, TB_SPEEV};
|
|
bool zero = ModifierKeys == Keys.Control || ModifierKeys == Keys.Shift;
|
|
var evs = zero ? new uint[6] : PKX.getRandomEVs(SAV.Generation);
|
|
for (int i = 0; i < 6; i++)
|
|
tb[i].Text = evs[i].ToString();
|
|
|
|
changingFields = false;
|
|
updateEVs(null, null);
|
|
}
|
|
private void updateRandomPID(object sender, EventArgs e)
|
|
{
|
|
if (pkm.Format < 3)
|
|
return;
|
|
if (fieldsLoaded)
|
|
pkm.PID = Util.getHEXval(TB_PID.Text);
|
|
|
|
if (sender == Label_Gender)
|
|
pkm.setPIDGender(pkm.Gender);
|
|
else if (sender == CB_Nature && pkm.Nature != WinFormsUtil.getIndex(CB_Nature))
|
|
pkm.setPIDNature(WinFormsUtil.getIndex(CB_Nature));
|
|
else if (sender == BTN_RerollPID)
|
|
pkm.setPIDGender(pkm.Gender);
|
|
else if (sender == CB_Ability && CB_Ability.SelectedIndex != pkm.PIDAbility && pkm.PIDAbility > -1)
|
|
pkm.PID = PKX.getRandomPID(pkm.Species, pkm.Gender, pkm.Version, pkm.Nature, pkm.Format, (uint)(CB_Ability.SelectedIndex * 0x10001));
|
|
|
|
TB_PID.Text = pkm.PID.ToString("X8");
|
|
getQuickFiller(dragout);
|
|
if (pkm.GenNumber < 6 && SAV.Generation >= 6)
|
|
TB_EC.Text = TB_PID.Text;
|
|
}
|
|
private void updateRandomEC(object sender, EventArgs e)
|
|
{
|
|
if (pkm.Format < 6)
|
|
return;
|
|
|
|
int wIndex = Array.IndexOf(Legal.WurmpleEvolutions, WinFormsUtil.getIndex(CB_Species));
|
|
if (wIndex < 0)
|
|
{
|
|
TB_EC.Text = Util.rnd32().ToString("X8");
|
|
}
|
|
else
|
|
{
|
|
uint EC;
|
|
bool valid;
|
|
do
|
|
{
|
|
EC = Util.rnd32();
|
|
uint evoVal;
|
|
switch (pkm.GenNumber)
|
|
{
|
|
case 3: evoVal = pkm.PID & 0xFFFF; break;
|
|
case 4:
|
|
case 5: evoVal = pkm.PID >> 16; break;
|
|
default: evoVal = pkm.EncryptionConstant >> 16; break;
|
|
}
|
|
evoVal = evoVal%10/5;
|
|
valid = evoVal == wIndex/2;
|
|
} while (!valid);
|
|
TB_EC.Text = EC.ToString("X8");
|
|
}
|
|
updateLegality();
|
|
}
|
|
private void updateHackedStats(object sender, EventArgs e)
|
|
{
|
|
Stat_HP.Enabled =
|
|
Stat_ATK.Enabled =
|
|
Stat_DEF.Enabled =
|
|
Stat_SPA.Enabled =
|
|
Stat_SPD.Enabled =
|
|
Stat_SPE.Enabled = CHK_HackedStats.Checked;
|
|
}
|
|
private void updateHackedStatText(object sender, EventArgs e)
|
|
{
|
|
if (!CHK_HackedStats.Checked || !(sender is TextBox))
|
|
return;
|
|
|
|
string text = ((TextBox)sender).Text;
|
|
if (string.IsNullOrWhiteSpace(text))
|
|
((TextBox)sender).Text = "0";
|
|
|
|
if (Convert.ToUInt32(text) > ushort.MaxValue)
|
|
((TextBox)sender).Text = "65535";
|
|
}
|
|
private void update255_MTB(object sender, EventArgs e)
|
|
{
|
|
if (Util.ToInt32(((MaskedTextBox) sender).Text) > byte.MaxValue)
|
|
((MaskedTextBox) sender).Text = "255";
|
|
}
|
|
private void updateForm(object sender, EventArgs e)
|
|
{
|
|
if (CB_Form == sender && fieldsLoaded)
|
|
pkm.AltForm = CB_Form.SelectedIndex;
|
|
|
|
updateGender();
|
|
updateStats();
|
|
// Repopulate Abilities if Species Form has different abilities
|
|
setAbilityList();
|
|
|
|
// Gender Forms
|
|
if (WinFormsUtil.getIndex(CB_Species) == 201 && fieldsLoaded)
|
|
{
|
|
if (SAV.Generation == 3)
|
|
{
|
|
pkm.setPIDUnown3(CB_Form.SelectedIndex);
|
|
TB_PID.Text = pkm.PID.ToString("X8");
|
|
}
|
|
else if (SAV.Generation == 2)
|
|
{
|
|
int desiredForm = CB_Form.SelectedIndex;
|
|
while (pkm.AltForm != desiredForm)
|
|
updateRandomIVs(null, null);
|
|
}
|
|
}
|
|
else if (PKX.getGender(CB_Form.Text) < 2)
|
|
{
|
|
if (CB_Form.Items.Count == 2) // actually M/F; Pumpkaboo formes in German are S,M,L,XL
|
|
Label_Gender.Text = gendersymbols[PKX.getGender(CB_Form.Text)];
|
|
}
|
|
|
|
if (changingFields)
|
|
return;
|
|
changingFields = true;
|
|
MT_Form.Text = CB_Form.SelectedIndex.ToString();
|
|
changingFields = false;
|
|
|
|
if (fieldsLoaded)
|
|
getQuickFiller(dragout);
|
|
}
|
|
private void updateHaXForm(object sender, EventArgs e)
|
|
{
|
|
if (changingFields)
|
|
return;
|
|
changingFields = true;
|
|
int form = pkm.AltForm = Util.ToInt32(MT_Form.Text);
|
|
CB_Form.SelectedIndex = CB_Form.Items.Count > form ? form : -1;
|
|
changingFields = false;
|
|
|
|
if (fieldsLoaded)
|
|
getQuickFiller(dragout);
|
|
}
|
|
private void updatePP(object sender, EventArgs e)
|
|
{
|
|
ComboBox[] cbs = {CB_Move1, CB_Move2, CB_Move3, CB_Move4};
|
|
ComboBox[] pps = {CB_PPu1, CB_PPu2, CB_PPu3, CB_PPu4};
|
|
MaskedTextBox[] tbs = {TB_PP1, TB_PP2, TB_PP3, TB_PP4};
|
|
int index = Array.IndexOf(cbs, sender);
|
|
if (index < 0)
|
|
index = Array.IndexOf(pps, sender);
|
|
if (index < 0)
|
|
return;
|
|
|
|
int move = WinFormsUtil.getIndex(cbs[index]);
|
|
int pp = pps[index].SelectedIndex;
|
|
if (move == 0 && pp != 0)
|
|
{
|
|
pps[index].SelectedIndex = 0;
|
|
return; // recursively triggers
|
|
}
|
|
tbs[index].Text = pkm.getMovePP(move, pp).ToString();
|
|
}
|
|
private void updatePKRSstrain(object sender, EventArgs e)
|
|
{
|
|
// Change the PKRS Days to the legal bounds.
|
|
int currentDuration = CB_PKRSDays.SelectedIndex;
|
|
CB_PKRSDays.Items.Clear();
|
|
foreach (int day in Enumerable.Range(0, CB_PKRSStrain.SelectedIndex % 4 + 2)) CB_PKRSDays.Items.Add(day);
|
|
|
|
// Set the days back if they're legal, else set it to 1. (0 always passes).
|
|
CB_PKRSDays.SelectedIndex = currentDuration < CB_PKRSDays.Items.Count ? currentDuration : 1;
|
|
|
|
if (CB_PKRSStrain.SelectedIndex != 0) return;
|
|
|
|
// Never Infected
|
|
CB_PKRSDays.SelectedIndex = 0;
|
|
CHK_Cured.Checked = false;
|
|
CHK_Infected.Checked = false;
|
|
}
|
|
private void updatePKRSdays(object sender, EventArgs e)
|
|
{
|
|
if (CB_PKRSDays.SelectedIndex != 0) return;
|
|
|
|
// If no days are selected
|
|
if (CB_PKRSStrain.SelectedIndex == 0)
|
|
CHK_Cured.Checked = CHK_Infected.Checked = false; // No Strain = Never Cured / Infected, triggers Strain update
|
|
else CHK_Cured.Checked = true; // Any Strain = Cured
|
|
}
|
|
private void updatePKRSCured(object sender, EventArgs e)
|
|
{
|
|
if (!fieldsInitialized) return;
|
|
// Cured PokeRus is toggled
|
|
if (CHK_Cured.Checked)
|
|
{
|
|
// Has Had PokeRus
|
|
Label_PKRSdays.Visible = CB_PKRSDays.Visible = false;
|
|
CB_PKRSDays.SelectedIndex = 0;
|
|
|
|
Label_PKRS.Visible = CB_PKRSStrain.Visible = true;
|
|
CHK_Infected.Checked = true;
|
|
|
|
// If we're cured we have to have a strain infection.
|
|
if (CB_PKRSStrain.SelectedIndex == 0)
|
|
CB_PKRSStrain.SelectedIndex = 1;
|
|
}
|
|
else if (!CHK_Infected.Checked)
|
|
{
|
|
// Not Infected, Disable the other
|
|
Label_PKRS.Visible = CB_PKRSStrain.Visible = false;
|
|
CB_PKRSStrain.SelectedIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
// Still Infected for a duration
|
|
Label_PKRSdays.Visible = CB_PKRSDays.Visible = true;
|
|
CB_PKRSDays.SelectedValue = 1;
|
|
}
|
|
// if not cured yet, days > 0
|
|
if (!CHK_Cured.Checked && CHK_Infected.Checked && CB_PKRSDays.SelectedIndex == 0)
|
|
CB_PKRSDays.SelectedIndex++;
|
|
|
|
setMarkings();
|
|
}
|
|
private void updatePKRSInfected(object sender, EventArgs e)
|
|
{
|
|
if (!fieldsInitialized) return;
|
|
if (CHK_Cured.Checked && !CHK_Infected.Checked) { CHK_Cured.Checked = false; return; }
|
|
if (CHK_Cured.Checked) return;
|
|
Label_PKRS.Visible = CB_PKRSStrain.Visible = CHK_Infected.Checked;
|
|
if (!CHK_Infected.Checked) { CB_PKRSStrain.SelectedIndex = 0; CB_PKRSDays.SelectedIndex = 0; Label_PKRSdays.Visible = CB_PKRSDays.Visible = false; }
|
|
else if (CB_PKRSStrain.SelectedIndex == 0) { CB_PKRSStrain.SelectedIndex = 1; Label_PKRSdays.Visible = CB_PKRSDays.Visible = true; updatePKRSCured(sender, e);}
|
|
|
|
// if not cured yet, days > 0
|
|
if (CHK_Infected.Checked && CB_PKRSDays.SelectedIndex == 0) CB_PKRSDays.SelectedIndex++;
|
|
}
|
|
private void updateCountry(object sender, EventArgs e)
|
|
{
|
|
if (WinFormsUtil.getIndex(sender as ComboBox) > 0)
|
|
setCountrySubRegion(CB_SubRegion, "sr_" + WinFormsUtil.getIndex(sender as ComboBox).ToString("000"));
|
|
}
|
|
private void updateSpecies(object sender, EventArgs e)
|
|
{
|
|
// Get Species dependent information
|
|
setAbilityList();
|
|
setForms();
|
|
updateForm(null, null);
|
|
|
|
if (!fieldsLoaded)
|
|
return;
|
|
|
|
pkm.Species = WinFormsUtil.getIndex(CB_Species);
|
|
// Recalculate EXP for Given Level
|
|
uint EXP = PKX.getEXP(pkm.CurrentLevel, pkm.Species);
|
|
TB_EXP.Text = EXP.ToString();
|
|
|
|
// Check for Gender Changes
|
|
updateGender();
|
|
|
|
// If species changes and no nickname, set the new name == speciesName.
|
|
if (!CHK_Nicknamed.Checked)
|
|
updateNickname(sender, e);
|
|
|
|
updateLegality();
|
|
}
|
|
private void updateOriginGame(object sender, EventArgs e)
|
|
{
|
|
GameVersion Version = (GameVersion)WinFormsUtil.getIndex(CB_GameOrigin);
|
|
|
|
// check if differs
|
|
GameVersion newTrack = GameUtil.getMetLocationVersionGroup(Version);
|
|
if (newTrack != origintrack)
|
|
{
|
|
var met_list = GameInfo.getLocationList(Version, SAV.Generation, egg:false);
|
|
CB_MetLocation.DisplayMember = "Text";
|
|
CB_MetLocation.ValueMember = "Value";
|
|
CB_MetLocation.DataSource = new BindingSource(met_list, null);
|
|
|
|
int metLoc = 0; // transporter or pal park for past gen pkm
|
|
switch (newTrack)
|
|
{
|
|
case GameVersion.GO: metLoc = 30012; break;
|
|
case GameVersion.RBY: metLoc = 30013; break;
|
|
}
|
|
if (metLoc != 0)
|
|
CB_MetLocation.SelectedValue = metLoc;
|
|
else
|
|
CB_MetLocation.SelectedIndex = metLoc;
|
|
|
|
var egg_list = GameInfo.getLocationList(Version, SAV.Generation, egg:true);
|
|
CB_EggLocation.DisplayMember = "Text";
|
|
CB_EggLocation.ValueMember = "Value";
|
|
CB_EggLocation.DataSource = new BindingSource(egg_list, null);
|
|
CB_EggLocation.SelectedIndex = CHK_AsEgg.Checked ? 1 : 0; // daycare : none
|
|
|
|
origintrack = newTrack;
|
|
|
|
// Stretch C/XD met location dropdowns
|
|
int width = CB_EggLocation.DropDownWidth;
|
|
if (Version == GameVersion.CXD && SAV.Generation == 3)
|
|
width = 2*width;
|
|
CB_MetLocation.DropDownWidth = width;
|
|
}
|
|
|
|
// Visibility logic for Gen 4 encounter type; only show for Gen 4 Pokemon.
|
|
if (SAV.Generation >= 4)
|
|
{
|
|
bool g4 = Version >= GameVersion.HG && Version <= GameVersion.Pt;
|
|
if ((int) Version == 9) // invalid
|
|
g4 = false;
|
|
CB_EncounterType.Visible = Label_EncounterType.Visible = g4 && SAV.Generation < 7;
|
|
if (!g4)
|
|
CB_EncounterType.SelectedValue = 0;
|
|
}
|
|
|
|
if (!fieldsLoaded)
|
|
return;
|
|
pkm.Version = (int)Version;
|
|
setMarkings(); // Set/Remove KB marking
|
|
updateLegality();
|
|
}
|
|
private void updateExtraByteValue(object sender, EventArgs e)
|
|
{
|
|
if (CB_ExtraBytes.Items.Count == 0)
|
|
return;
|
|
// Changed Extra Byte's Value
|
|
if (Util.ToInt32(((MaskedTextBox) sender).Text) > byte.MaxValue)
|
|
((MaskedTextBox) sender).Text = "255";
|
|
|
|
int value = Util.ToInt32(TB_ExtraByte.Text);
|
|
int offset = Convert.ToInt32(CB_ExtraBytes.Text, 16);
|
|
pkm.Data[offset] = (byte)value;
|
|
}
|
|
private void updateExtraByteIndex(object sender, EventArgs e)
|
|
{
|
|
if (CB_ExtraBytes.Items.Count == 0)
|
|
return;
|
|
// Byte changed, need to refresh the Text box for the byte's value.
|
|
TB_ExtraByte.Text = pkm.Data[Convert.ToInt32(CB_ExtraBytes.Text, 16)].ToString();
|
|
}
|
|
private void updateNatureModification(object sender, EventArgs e)
|
|
{
|
|
if (sender != CB_Nature) return;
|
|
int nature = WinFormsUtil.getIndex(CB_Nature);
|
|
int incr = nature / 5;
|
|
int decr = nature % 5;
|
|
|
|
Label[] labarray = { Label_ATK, Label_DEF, Label_SPE, Label_SPA, Label_SPD };
|
|
// Reset Label Colors
|
|
foreach (Label label in labarray)
|
|
label.ResetForeColor();
|
|
|
|
// Set Colored StatLabels only if Nature isn't Neutral
|
|
NatureTip.SetToolTip(CB_Nature,
|
|
incr != decr
|
|
? $"+{labarray[incr].Text} / -{labarray[decr].Text}".Replace(":", "")
|
|
: "-/-");
|
|
}
|
|
private void updateNickname(object sender, EventArgs e)
|
|
{
|
|
if (fieldsInitialized && ModifierKeys == Keys.Control && sender != null) // Import Showdown
|
|
{ clickShowdownImportPKM(sender, e); return; }
|
|
if (fieldsInitialized && ModifierKeys == Keys.Alt && sender != null) // Export Showdown
|
|
{ clickShowdownExportPKM(sender, e); return; }
|
|
|
|
int lang = WinFormsUtil.getIndex(CB_Language);
|
|
|
|
if (!fieldsInitialized || CHK_Nicknamed.Checked)
|
|
return;
|
|
|
|
// Fetch Current Species and set it as Nickname Text
|
|
int species = WinFormsUtil.getIndex(CB_Species);
|
|
if (species < 1 || species > SAV.MaxSpeciesID)
|
|
{ TB_Nickname.Text = ""; return; }
|
|
|
|
if (CHK_IsEgg.Checked)
|
|
species = 0; // get the egg name.
|
|
|
|
// If name is that of another language, don't replace the nickname
|
|
if (sender != CB_Language && species != 0 && !PKX.getIsNicknamedAnyLanguage(species, TB_Nickname.Text, SAV.Generation))
|
|
return;
|
|
|
|
TB_Nickname.Text = PKX.getSpeciesNameGeneration(species, lang, SAV.Generation);
|
|
if (SAV.Generation == 1)
|
|
((PK1) pkm).setNotNicknamed();
|
|
if (SAV.Generation == 2)
|
|
((PK2) pkm).setNotNicknamed();
|
|
}
|
|
private void updateNicknameClick(object sender, MouseEventArgs e)
|
|
{
|
|
TextBox tb = !(sender is TextBox) ? TB_Nickname : (TextBox) sender;
|
|
// Special Character Form
|
|
if (ModifierKeys != Keys.Control)
|
|
return;
|
|
|
|
if (tb == TB_Nickname)
|
|
{
|
|
pkm.Nickname = tb.Text;
|
|
var d = new f2_Text(tb, pkm.Nickname_Trash);
|
|
d.ShowDialog();
|
|
tb.Text = d.FinalString;
|
|
pkm.Nickname_Trash = d.FinalBytes;
|
|
}
|
|
else if (tb == TB_OT)
|
|
{
|
|
pkm.OT_Name = tb.Text;
|
|
var d = new f2_Text(tb, pkm.OT_Trash);
|
|
d.ShowDialog();
|
|
tb.Text = d.FinalString;
|
|
pkm.OT_Trash = d.FinalBytes;
|
|
}
|
|
else if (tb == TB_OTt2)
|
|
{
|
|
pkm.HT_Name = tb.Text;
|
|
var d = new f2_Text(tb, pkm.HT_Trash);
|
|
d.ShowDialog();
|
|
tb.Text = d.FinalString;
|
|
pkm.HT_Trash = d.FinalBytes;
|
|
}
|
|
}
|
|
private void updateNotOT(object sender, EventArgs e)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(TB_OTt2.Text))
|
|
{
|
|
clickGT(GB_OT, null); // Switch CT over to OT.
|
|
Label_CTGender.Text = "";
|
|
TB_Friendship.Text = pkm.CurrentFriendship.ToString();
|
|
}
|
|
else if (string.IsNullOrWhiteSpace(Label_CTGender.Text))
|
|
Label_CTGender.Text = gendersymbols[0];
|
|
}
|
|
private void updateIsEgg(object sender, EventArgs e)
|
|
{
|
|
// Display hatch counter if it is an egg, Display Friendship if it is not.
|
|
Label_HatchCounter.Visible = CHK_IsEgg.Checked && SAV.Generation > 1;
|
|
Label_Friendship.Visible = !CHK_IsEgg.Checked && SAV.Generation > 1;
|
|
|
|
if (!fieldsLoaded)
|
|
return;
|
|
|
|
pkm.IsEgg = CHK_IsEgg.Checked;
|
|
if (CHK_IsEgg.Checked)
|
|
{
|
|
TB_Friendship.Text = "1";
|
|
|
|
// If we are an egg, it won't have a met location.
|
|
CHK_AsEgg.Checked = true;
|
|
GB_EggConditions.Enabled = true;
|
|
|
|
CAL_MetDate.Value = new DateTime(2000, 01, 01);
|
|
|
|
// if egg wasn't originally obtained by OT => Link Trade, else => None
|
|
bool isTraded = SAV.OT != TB_OT.Text || SAV.TID != Util.ToInt32(TB_TID.Text) || SAV.SID != Util.ToInt32(TB_SID.Text);
|
|
CB_MetLocation.SelectedIndex = isTraded ? 2 : 0;
|
|
|
|
if (!CHK_Nicknamed.Checked)
|
|
{
|
|
TB_Nickname.Text = PKX.getSpeciesNameGeneration(0, WinFormsUtil.getIndex(CB_Language), pkm.Format);
|
|
CHK_Nicknamed.Checked = true;
|
|
}
|
|
}
|
|
else // Not Egg
|
|
{
|
|
if (!CHK_Nicknamed.Checked)
|
|
updateNickname(null, null);
|
|
|
|
TB_Friendship.Text = SAV.Personal[WinFormsUtil.getIndex(CB_Species)].BaseFriendship.ToString();
|
|
|
|
if (CB_EggLocation.SelectedIndex == 0)
|
|
{
|
|
CAL_EggDate.Value = new DateTime(2000, 01, 01);
|
|
CHK_AsEgg.Checked = false;
|
|
GB_EggConditions.Enabled = false;
|
|
}
|
|
|
|
if (TB_Nickname.Text == PKX.getSpeciesNameGeneration(0, WinFormsUtil.getIndex(CB_Language), pkm.Format))
|
|
CHK_Nicknamed.Checked = false;
|
|
}
|
|
|
|
updateNickname(null, null);
|
|
getQuickFiller(dragout);
|
|
}
|
|
private void updateMetAsEgg(object sender, EventArgs e)
|
|
{
|
|
GB_EggConditions.Enabled = CHK_AsEgg.Checked;
|
|
if (CHK_AsEgg.Checked)
|
|
{
|
|
if (!fieldsLoaded)
|
|
return;
|
|
|
|
CAL_EggDate.Value = DateTime.Now;
|
|
CB_EggLocation.SelectedIndex = 1;
|
|
return;
|
|
}
|
|
// Remove egg met data
|
|
CHK_IsEgg.Checked = false;
|
|
CAL_EggDate.Value = new DateTime(2000, 01, 01);
|
|
CB_EggLocation.SelectedValue = 0;
|
|
|
|
updateLegality();
|
|
}
|
|
private void updateShinyPID(object sender, EventArgs e)
|
|
{
|
|
pkm.TID = Util.ToInt32(TB_TID.Text);
|
|
pkm.SID = Util.ToInt32(TB_SID.Text);
|
|
pkm.PID = Util.getHEXval(TB_PID.Text);
|
|
pkm.Nature = WinFormsUtil.getIndex(CB_Nature);
|
|
pkm.Gender = PKX.getGender(Label_Gender.Text);
|
|
pkm.AltForm = CB_Form.SelectedIndex;
|
|
pkm.Version = WinFormsUtil.getIndex(CB_GameOrigin);
|
|
|
|
if (pkm.Format > 2)
|
|
pkm.setShinyPID();
|
|
else
|
|
{
|
|
// IVs determine shininess
|
|
// All 10IV except for one where (IV & 2 == 2) [gen specific]
|
|
int[] and2 = {2, 3, 6, 7, 10, 11, 14, 15};
|
|
int randIV = and2[Util.rnd32()%and2.Length];
|
|
if (pkm.Format == 1)
|
|
{
|
|
TB_ATKIV.Text = "10"; // an attempt was made
|
|
TB_DEFIV.Text = randIV.ToString();
|
|
}
|
|
else // pkm.Format == 2
|
|
{
|
|
TB_ATKIV.Text = randIV.ToString();
|
|
TB_DEFIV.Text = "10";
|
|
}
|
|
TB_SPEIV.Text = "10";
|
|
TB_SPAIV.Text = "10";
|
|
updateIVs(null, null);
|
|
}
|
|
TB_PID.Text = pkm.PID.ToString("X8");
|
|
|
|
if (pkm.GenNumber < 6 && TB_EC.Visible)
|
|
TB_EC.Text = TB_PID.Text;
|
|
|
|
getQuickFiller(dragout);
|
|
updateLegality();
|
|
}
|
|
private void updateTSV(object sender, EventArgs e)
|
|
{
|
|
if (SAV.Generation < 6)
|
|
return;
|
|
|
|
var TSV = pkm.TSV.ToString("0000");
|
|
string IDstr = "TSV: " + TSV;
|
|
if (SAV.Generation > 6)
|
|
IDstr += Environment.NewLine + "G7TID: " + pkm.TrainerID7.ToString("000000");
|
|
|
|
Tip1.SetToolTip(TB_TID, IDstr);
|
|
Tip2.SetToolTip(TB_SID, IDstr);
|
|
|
|
pkm.PID = Util.getHEXval(TB_PID.Text);
|
|
var PSV = pkm.PSV;
|
|
Tip3.SetToolTip(TB_PID, "PSV: " + PSV.ToString("0000"));
|
|
}
|
|
private void update_ID(object sender, EventArgs e)
|
|
{
|
|
// Trim out nonhex characters
|
|
TB_PID.Text = Util.getHEXval(TB_PID.Text).ToString("X8");
|
|
TB_EC.Text = Util.getHEXval(TB_EC.Text).ToString("X8");
|
|
|
|
// Max TID/SID is 65535
|
|
if (Util.ToUInt32(TB_TID.Text) > ushort.MaxValue) TB_TID.Text = "65535";
|
|
if (Util.ToUInt32(TB_SID.Text) > ushort.MaxValue) TB_SID.Text = "65535";
|
|
|
|
setIsShiny(sender);
|
|
getQuickFiller(dragout);
|
|
updateIVs(null, null); // If the EC is changed, EC%6 (Characteristic) might be changed.
|
|
TB_PID.Select(60, 0); // position cursor at end of field
|
|
if (SAV.Generation <= 4 && fieldsLoaded)
|
|
{
|
|
fieldsLoaded = false;
|
|
pkm.PID = Util.getHEXval(TB_PID.Text);
|
|
CB_Nature.SelectedValue = pkm.Nature;
|
|
Label_Gender.Text = gendersymbols[pkm.Gender];
|
|
Label_Gender.ForeColor = pkm.Gender == 2 ? Label_Species.ForeColor : (pkm.Gender == 1 ? Color.Red : Color.Blue);
|
|
fieldsLoaded = true;
|
|
}
|
|
}
|
|
private void updateShadowID(object sender, EventArgs e)
|
|
{
|
|
if (!fieldsLoaded)
|
|
return;
|
|
FLP_Purification.Visible = NUD_ShadowID.Value > 0;
|
|
}
|
|
private void updatePurification(object sender, EventArgs e)
|
|
{
|
|
if (!fieldsLoaded)
|
|
return;
|
|
fieldsLoaded = false;
|
|
CHK_Shadow.Checked = NUD_Purification.Value > 0;
|
|
fieldsLoaded = true;
|
|
}
|
|
private void updateShadowCHK(object sender, EventArgs e)
|
|
{
|
|
if (!fieldsLoaded)
|
|
return;
|
|
fieldsLoaded = false;
|
|
NUD_Purification.Value = CHK_Shadow.Checked ? NUD_Purification.Maximum : 0;
|
|
fieldsLoaded = true;
|
|
}
|
|
private void validateComboBox(object sender)
|
|
{
|
|
if (!formInitialized)
|
|
return;
|
|
ComboBox cb = sender as ComboBox;
|
|
if (cb == null)
|
|
return;
|
|
|
|
if (cb.Text == "" && cb.Items.Count > 0)
|
|
{ cb.SelectedIndex = 0; return; }
|
|
if (cb.SelectedValue == null)
|
|
cb.BackColor = Color.DarkSalmon;
|
|
else
|
|
cb.ResetBackColor();
|
|
}
|
|
private void validateComboBox(object sender, System.ComponentModel.CancelEventArgs e)
|
|
{
|
|
if (!(sender is ComboBox))
|
|
return;
|
|
|
|
validateComboBox(sender);
|
|
|
|
if (fieldsLoaded)
|
|
getQuickFiller(dragout);
|
|
}
|
|
private void validateComboBox2(object sender, EventArgs e)
|
|
{
|
|
if (!fieldsInitialized)
|
|
return;
|
|
validateComboBox(sender, null);
|
|
if (fieldsLoaded)
|
|
{
|
|
if (sender == CB_Ability && SAV.Generation >= 6)
|
|
TB_AbilityNumber.Text = (1 << CB_Ability.SelectedIndex).ToString();
|
|
if (sender == CB_Ability && SAV.Generation <= 5 && CB_Ability.SelectedIndex < 2) // not hidden
|
|
updateRandomPID(sender, e);
|
|
if (sender == CB_Nature && SAV.Generation <= 4)
|
|
{
|
|
pkm.Nature = CB_Nature.SelectedIndex;
|
|
updateRandomPID(sender, e);
|
|
}
|
|
if (sender == CB_HeldItem || sender == CB_Ability)
|
|
updateLegality();
|
|
}
|
|
updateNatureModification(sender, null);
|
|
updateIVs(null, null); // updating Nature will trigger stats to update as well
|
|
}
|
|
private void validateMove(object sender, EventArgs e)
|
|
{
|
|
if (!fieldsInitialized)
|
|
return;
|
|
validateComboBox(sender);
|
|
if (!fieldsLoaded)
|
|
return;
|
|
|
|
if (new[] { CB_Move1, CB_Move2, CB_Move3, CB_Move4 }.Contains(sender)) // Move
|
|
updatePP(sender, e);
|
|
|
|
// Legality
|
|
pkm.Moves = new[] {CB_Move1, CB_Move2, CB_Move3, CB_Move4}.Select(WinFormsUtil.getIndex).ToArray();
|
|
pkm.RelearnMoves = new[] {CB_RelearnMove1, CB_RelearnMove2, CB_RelearnMove3, CB_RelearnMove4}.Select(WinFormsUtil.getIndex).ToArray();
|
|
updateLegality(skipMoveRepop:true);
|
|
}
|
|
private void validateMovePaint(object sender, DrawItemEventArgs e)
|
|
{
|
|
if (e.Index < 0) return;
|
|
|
|
var i = (ComboItem)(sender as ComboBox).Items[e.Index];
|
|
var moves = Legality.AllSuggestedMovesAndRelearn;
|
|
bool vm = moves != null && moves.Contains(i.Value) && !HaX;
|
|
|
|
bool current = (e.State & DrawItemState.Selected) == DrawItemState.Selected;
|
|
Brush tBrush = current ? SystemBrushes.HighlightText : new SolidBrush(e.ForeColor);
|
|
Brush brush = current ? SystemBrushes.Highlight : vm ? Brushes.PaleGreen : new SolidBrush(e.BackColor);
|
|
|
|
e.Graphics.FillRectangle(brush, e.Bounds);
|
|
e.Graphics.DrawString(i.Text, e.Font, tBrush, e.Bounds, StringFormat.GenericDefault);
|
|
if (current) return;
|
|
tBrush.Dispose();
|
|
if (!vm)
|
|
brush.Dispose();
|
|
}
|
|
private void validateLocation(object sender, EventArgs e)
|
|
{
|
|
validateComboBox(sender);
|
|
if (!fieldsLoaded)
|
|
return;
|
|
|
|
pkm.Met_Location = WinFormsUtil.getIndex(CB_MetLocation);
|
|
pkm.Egg_Location = WinFormsUtil.getIndex(CB_EggLocation);
|
|
updateLegality();
|
|
}
|
|
private void removedropCB(object sender, KeyEventArgs e)
|
|
{
|
|
((ComboBox)sender).DroppedDown = false;
|
|
}
|
|
private void showLegality(PKM pk, bool tabs, bool verbose, bool skipMoveRepop = false)
|
|
{
|
|
LegalityAnalysis la = new LegalityAnalysis(pk);
|
|
if (!la.Parsed)
|
|
{
|
|
WinFormsUtil.Alert(pk.Format < 3
|
|
? $"Checking legality of PK{pk.Format} files is not supported."
|
|
: $"Checking legality of PK{pk.Format} files that originated from Gen{pk.GenNumber} is not supported.");
|
|
return;
|
|
}
|
|
if (tabs)
|
|
updateLegality(la, skipMoveRepop);
|
|
WinFormsUtil.Alert(la.Report(verbose));
|
|
}
|
|
private void updateLegality(LegalityAnalysis la = null, bool skipMoveRepop = false)
|
|
{
|
|
if (!fieldsLoaded)
|
|
return;
|
|
|
|
Legality = la ?? new LegalityAnalysis(pkm);
|
|
if (!Legality.Parsed || HaX)
|
|
{
|
|
PB_Legal.Visible =
|
|
PB_WarnMove1.Visible = PB_WarnMove2.Visible = PB_WarnMove3.Visible = PB_WarnMove4.Visible =
|
|
PB_WarnRelearn1.Visible = PB_WarnRelearn2.Visible = PB_WarnRelearn3.Visible = PB_WarnRelearn4.Visible = false;
|
|
return;
|
|
}
|
|
|
|
PB_Legal.Visible = true;
|
|
PB_Legal.Image = Legality.Valid ? Resources.valid : Resources.warn;
|
|
|
|
// Refresh Move Legality
|
|
for (int i = 0; i < 4; i++)
|
|
movePB[i].Visible = !Legality.vMoves[i].Valid;
|
|
|
|
if (pkm.Format >= 6)
|
|
for (int i = 0; i < 4; i++)
|
|
relearnPB[i].Visible = !Legality.vRelearn[i].Valid;
|
|
|
|
if (skipMoveRepop)
|
|
return;
|
|
// Resort moves
|
|
bool tmp = fieldsLoaded;
|
|
fieldsLoaded = false;
|
|
var cb = new[] {CB_Move1, CB_Move2, CB_Move3, CB_Move4};
|
|
var moves = Legality.AllSuggestedMovesAndRelearn;
|
|
var moveList = GameInfo.MoveDataSource.OrderByDescending(m => moves.Contains(m.Value)).ToArray();
|
|
foreach (ComboBox c in cb)
|
|
{
|
|
var index = WinFormsUtil.getIndex(c);
|
|
c.DataSource = new BindingSource(moveList, null);
|
|
c.SelectedValue = index;
|
|
if (c.Visible)
|
|
c.SelectionLength = 0; // flicker hack
|
|
}
|
|
fieldsLoaded |= tmp;
|
|
}
|
|
|
|
private void updateGender()
|
|
{
|
|
int cg = PKX.getGender(Label_Gender.Text);
|
|
int gt = SAV.Personal.getFormeEntry(WinFormsUtil.getIndex(CB_Species), CB_Form.SelectedIndex).Gender;
|
|
|
|
int Gender;
|
|
if (gt == 255) // Genderless
|
|
Gender = 2;
|
|
else if (gt == 254) // Female Only
|
|
Gender = 1;
|
|
else if (gt == 0) // Male Only
|
|
Gender = 0;
|
|
else if (cg == 2 || WinFormsUtil.getIndex(CB_GameOrigin) < 24)
|
|
Gender = (Util.getHEXval(TB_PID.Text) & 0xFF) <= gt ? 1 : 0;
|
|
else
|
|
Gender = cg;
|
|
|
|
Label_Gender.Text = gendersymbols[Gender];
|
|
Label_Gender.ForeColor = Gender == 2 ? Label_Species.ForeColor : (Gender == 1 ? Color.Red : Color.Blue);
|
|
}
|
|
private void updateStats()
|
|
{
|
|
// Generate the stats.
|
|
pkm.setStats(pkm.getStats(SAV.Personal.getFormeEntry(pkm.Species, pkm.AltForm)));
|
|
|
|
Stat_HP.Text = pkm.Stat_HPCurrent.ToString();
|
|
Stat_ATK.Text = pkm.Stat_ATK.ToString();
|
|
Stat_DEF.Text = pkm.Stat_DEF.ToString();
|
|
Stat_SPA.Text = pkm.Stat_SPA.ToString();
|
|
Stat_SPD.Text = pkm.Stat_SPD.ToString();
|
|
Stat_SPE.Text = pkm.Stat_SPE.ToString();
|
|
|
|
// Recolor the Stat Labels based on boosted stats.
|
|
{
|
|
int incr = pkm.Nature / 5;
|
|
int decr = pkm.Nature % 5;
|
|
|
|
Label[] labarray = { Label_ATK, Label_DEF, Label_SPE, Label_SPA, Label_SPD };
|
|
// Reset Label Colors
|
|
foreach (Label label in labarray)
|
|
label.ResetForeColor();
|
|
|
|
// Set Colored StatLabels only if Nature isn't Neutral
|
|
if (incr == decr) return;
|
|
labarray[incr].ForeColor = Color.Red;
|
|
labarray[decr].ForeColor = Color.Blue;
|
|
}
|
|
}
|
|
private void updateUnicode()
|
|
{
|
|
if (!unicode)
|
|
{
|
|
gendersymbols = new[] { "M", "F", "-" };
|
|
BTN_Shinytize.Text = "*";
|
|
TB_Nickname.Font = TB_OT.Font = TB_OTt2.Font = Label_TID.Font;
|
|
}
|
|
else
|
|
{
|
|
gendersymbols = new[] { "♂", "♀", "-" };
|
|
BTN_Shinytize.Text = "☆";
|
|
TB_Nickname.Font = TB_OT.Font = TB_OTt2.Font = FontUtil.getPKXFont(11);
|
|
}
|
|
// Switch active gender labels to new if they are active.
|
|
if (PKX.getGender(Label_Gender.Text) < 2)
|
|
Label_Gender.Text = gendersymbols[PKX.getGender(Label_Gender.Text)];
|
|
if (PKX.getGender(Label_OTGender.Text) < 2)
|
|
Label_OTGender.Text = gendersymbols[PKX.getGender(Label_OTGender.Text)];
|
|
if (PKX.getGender(Label_CTGender.Text) < 2)
|
|
Label_CTGender.Text = gendersymbols[PKX.getGender(Label_CTGender.Text)];
|
|
}
|
|
// Secondary Windows for Ribbons/Amie/Memories
|
|
private void openRibbons(object sender, EventArgs e)
|
|
{
|
|
new RibbonEditor().ShowDialog();
|
|
}
|
|
private void openMedals(object sender, EventArgs e)
|
|
{
|
|
new SuperTrainingEditor().ShowDialog();
|
|
}
|
|
private void openHistory(object sender, EventArgs e)
|
|
{
|
|
// Write back current values
|
|
pkm.HT_Name = TB_OTt2.Text;
|
|
pkm.OT_Name = TB_OT.Text;
|
|
pkm.IsEgg = CHK_IsEgg.Checked;
|
|
pkm.CurrentFriendship = Util.ToInt32(TB_Friendship.Text);
|
|
new MemoryAmie().ShowDialog();
|
|
TB_Friendship.Text = pkm.CurrentFriendship.ToString();
|
|
}
|
|
// Open/Save Array Manipulation //
|
|
public bool verifiedPKM()
|
|
{
|
|
if (ModifierKeys == (Keys.Control | Keys.Shift | Keys.Alt))
|
|
return true; // Override
|
|
// Make sure the PKX Fields are filled out properly (color check)
|
|
ComboBox[] cba = {
|
|
CB_Species, CB_Nature, CB_HeldItem, CB_Ability, // Main Tab
|
|
CB_MetLocation, CB_EggLocation, CB_Ball, // Met Tab
|
|
CB_Move1, CB_Move2, CB_Move3, CB_Move4, // Moves
|
|
CB_RelearnMove1, CB_RelearnMove2, CB_RelearnMove3, CB_RelearnMove4 // Moves
|
|
};
|
|
|
|
ComboBox cb = cba.FirstOrDefault(c => c.BackColor == Color.DarkSalmon && c.Items.Count != 0);
|
|
if (cb != null)
|
|
{
|
|
Control c = cb.Parent;
|
|
while (!(c is TabPage))
|
|
c = c.Parent;
|
|
tabMain.SelectedTab = c as TabPage;
|
|
}
|
|
else if (SAV.Generation >= 3 && Convert.ToUInt32(TB_EVTotal.Text) > 510 && !CHK_HackedStats.Checked)
|
|
tabMain.SelectedTab = Tab_Stats;
|
|
else if (WinFormsUtil.getIndex(CB_Species) == 0)
|
|
tabMain.SelectedTab = Tab_Main;
|
|
else
|
|
return true;
|
|
|
|
SystemSounds.Exclamation.Play();
|
|
return false;
|
|
}
|
|
public PKM preparePKM(bool click = true)
|
|
{
|
|
if (click)
|
|
ValidateChildren();
|
|
PKM pk = getPKMfromFields();
|
|
return pk?.Clone();
|
|
}
|
|
// Drag & Drop Events
|
|
private void tabMain_DragEnter(object sender, DragEventArgs e)
|
|
{
|
|
if (e.AllowedEffect == (DragDropEffects.Copy | DragDropEffects.Link)) // external file
|
|
e.Effect = DragDropEffects.Copy;
|
|
else if (e.Data != null) // within
|
|
e.Effect = DragDropEffects.Move;
|
|
}
|
|
private void tabMain_DragDrop(object sender, DragEventArgs e)
|
|
{
|
|
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
|
openQuick(files[0]);
|
|
e.Effect = DragDropEffects.Copy;
|
|
|
|
Cursor = DefaultCursor;
|
|
}
|
|
// Decrypted Export
|
|
private void dragout_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left && (ModifierKeys == Keys.Alt || ModifierKeys == Keys.Shift))
|
|
clickQR(sender, e);
|
|
if (e.Button == MouseButtons.Right)
|
|
return;
|
|
if (!verifiedPKM())
|
|
return;
|
|
|
|
// Create Temp File to Drag
|
|
PKM pkx = preparePKM();
|
|
bool encrypt = ModifierKeys == Keys.Control;
|
|
string fn = pkx.FileName; fn = fn.Substring(0, fn.LastIndexOf('.'));
|
|
string filename = $"{fn}{(encrypt ? ".ek" + pkx.Format : "." + pkx.Extension)}";
|
|
byte[] dragdata = encrypt ? pkx.EncryptedBoxData : pkx.DecryptedBoxData;
|
|
// Make file
|
|
string newfile = Path.Combine(Path.GetTempPath(), Util.CleanFileName(filename));
|
|
try
|
|
{
|
|
File.WriteAllBytes(newfile, dragdata);
|
|
PictureBox pb = (PictureBox)sender;
|
|
DragInfo.Cursor = Cursor = new Cursor(((Bitmap)pb.Image).GetHicon());
|
|
DoDragDrop(new DataObject(DataFormats.FileDrop, new[] { newfile }), DragDropEffects.Move);
|
|
}
|
|
catch (Exception x)
|
|
{ WinFormsUtil.Error("Drag & Drop Error", x); }
|
|
DragInfo.Cursor = Cursor = DefaultCursor;
|
|
File.Delete(newfile);
|
|
}
|
|
private void dragout_DragOver(object sender, DragEventArgs e)
|
|
{
|
|
e.Effect = DragDropEffects.Move;
|
|
}
|
|
// Dragout Display
|
|
private void dragoutEnter(object sender, EventArgs e)
|
|
{
|
|
dragout.BackgroundImage = WinFormsUtil.getIndex(CB_Species) > 0 ? Resources.slotSet : Resources.slotDel;
|
|
Cursor = Cursors.Hand;
|
|
}
|
|
private void dragoutLeave(object sender, EventArgs e)
|
|
{
|
|
dragout.BackgroundImage = Resources.slotTrans;
|
|
if (Cursor == Cursors.Hand)
|
|
Cursor = Cursors.Default;
|
|
}
|
|
private void dragoutDrop(object sender, DragEventArgs e)
|
|
{
|
|
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
|
openQuick(files[0]);
|
|
e.Effect = DragDropEffects.Copy;
|
|
|
|
Cursor = DefaultCursor;
|
|
}
|
|
|
|
private void Main_FormClosing(object sender, FormClosingEventArgs e)
|
|
{
|
|
if ((SAV.Edited || PKMIsUnsaved) && DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Any unsaved changes will be lost.", "Are you sure you want to close PKHeX?"))
|
|
{
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
|
|
try { Properties.Settings.Default.Save(); }
|
|
catch (Exception x) { File.WriteAllLines("config error.txt", new[] { x.ToString() }); }
|
|
}
|
|
#endregion
|
|
|
|
#region //// SAVE FILE FUNCTIONS ////
|
|
private void clickVerifyCHK(object sender, EventArgs e)
|
|
{
|
|
if (SAV.Edited) { WinFormsUtil.Alert("Save has been edited. Cannot integrity check."); return; }
|
|
|
|
if (SAV.ChecksumsValid) { WinFormsUtil.Alert("Checksums are valid."); return; }
|
|
if (DialogResult.Yes == WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Export Checksum Info to Clipboard?"))
|
|
Clipboard.SetText(SAV.ChecksumInfo);
|
|
}
|
|
private void clickExportSAVBAK(object sender, EventArgs e)
|
|
{
|
|
if (!SAV.Exportable)
|
|
return;
|
|
SaveFileDialog sfd = new SaveFileDialog
|
|
{ FileName = Util.CleanFileName(SAV.BAKName) };
|
|
if (sfd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
|
|
string path = sfd.FileName;
|
|
File.WriteAllBytes(path, SAV.BAK);
|
|
WinFormsUtil.Alert("Saved Backup of current SAV to:", path);
|
|
|
|
if (!Directory.Exists(BackupPath))
|
|
promptBackup();
|
|
}
|
|
private static void promptBackup()
|
|
{
|
|
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo,
|
|
$"PKHeX can perform automatic backups if you create a folder with the name \"{BackupPath}\" in the same folder as PKHeX's executable.",
|
|
"Would you like to create the backup folder now?")) return;
|
|
|
|
try { Directory.CreateDirectory(BackupPath); WinFormsUtil.Alert("Backup folder created!",
|
|
$"If you wish to no longer automatically back up save files, delete the \"{BackupPath}\" folder."); }
|
|
catch(Exception ex) { WinFormsUtil.Error($"Unable to create backup folder @ {BackupPath}", ex); }
|
|
}
|
|
private void clickExportSAV(object sender, EventArgs e)
|
|
{
|
|
if (!Menu_ExportSAV.Enabled)
|
|
return;
|
|
ValidateChildren();
|
|
|
|
// Chunk Error Checking
|
|
string err = SAV.MiscSaveChecks();
|
|
if (err.Length > 0 && WinFormsUtil.Prompt(MessageBoxButtons.YesNo, err, "Continue saving?") != DialogResult.Yes)
|
|
return;
|
|
|
|
SaveFileDialog main = new SaveFileDialog
|
|
{
|
|
Filter = SAV.Filter,
|
|
FileName = SAV.FileName,
|
|
RestoreDirectory = true
|
|
};
|
|
if (Directory.Exists(SAV.FilePath))
|
|
main.InitialDirectory = SAV.FilePath;
|
|
|
|
// Export
|
|
if (main.ShowDialog() != DialogResult.OK) return;
|
|
|
|
if (SAV.HasBox)
|
|
SAV.CurrentBox = CB_BoxSelect.SelectedIndex;
|
|
|
|
bool dsv = Path.GetExtension(main.FileName)?.ToLower() == ".dsv";
|
|
bool gci = Path.GetExtension(main.FileName)?.ToLower() == ".gci";
|
|
try
|
|
{
|
|
File.WriteAllBytes(main.FileName, SAV.Write(dsv, gci));
|
|
SAV.Edited = false;
|
|
WinFormsUtil.Alert("SAV exported to:", main.FileName);
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
if (x is UnauthorizedAccessException || x is FileNotFoundException)
|
|
WinFormsUtil.Error("Unable to save." + Environment.NewLine + x.Message,
|
|
"If destination is a removable disk (SD card), please ensure the write protection switch is not set.");
|
|
else throw;
|
|
}
|
|
}
|
|
|
|
// Box/SAV Functions //
|
|
private void clickBoxRight(object sender, EventArgs e)
|
|
{
|
|
CB_BoxSelect.SelectedIndex = (CB_BoxSelect.SelectedIndex + 1) % SAV.BoxCount;
|
|
}
|
|
private void clickBoxLeft(object sender, EventArgs e)
|
|
{
|
|
CB_BoxSelect.SelectedIndex = (CB_BoxSelect.SelectedIndex + SAV.BoxCount-1) % SAV.BoxCount;
|
|
}
|
|
private void clickBoxSort(object sender, EventArgs e)
|
|
{
|
|
if (tabBoxMulti.SelectedTab != Tab_Box)
|
|
return;
|
|
if (!SAV.HasBox)
|
|
return;
|
|
|
|
string modified;
|
|
bool all = false;
|
|
if (ModifierKeys == (Keys.Alt | Keys.Shift) && DialogResult.Yes == WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Clear ALL Boxes?!"))
|
|
{
|
|
if (SAV.getBoxHasLockedSlot(0, SAV.BoxCount - 1))
|
|
{ WinFormsUtil.Alert("Battle Box slots prevent the clearing of all boxes."); return; }
|
|
SAV.resetBoxes();
|
|
modified = "Boxes cleared!";
|
|
all = true;
|
|
}
|
|
else if (ModifierKeys == Keys.Alt && DialogResult.Yes == WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Clear Current Box?"))
|
|
{
|
|
if (SAV.getBoxHasLockedSlot(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex))
|
|
{ WinFormsUtil.Alert("Battle Box slots prevent the clearing of box."); return; }
|
|
SAV.resetBoxes(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex + 1);
|
|
modified = "Current Box cleared!";
|
|
}
|
|
else if (ModifierKeys == (Keys.Control | Keys.Shift) && DialogResult.Yes == WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Sort ALL Boxes?!"))
|
|
{
|
|
if (SAV.getBoxHasLockedSlot(0, SAV.BoxCount - 1))
|
|
{ WinFormsUtil.Alert("Battle Box slots prevent the sorting of all boxes."); return; }
|
|
SAV.sortBoxes();
|
|
modified = "Boxes sorted!";
|
|
all = true;
|
|
}
|
|
else if (ModifierKeys == Keys.Control && DialogResult.Yes == WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Sort Current Box?"))
|
|
{
|
|
if (SAV.getBoxHasLockedSlot(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex))
|
|
{ WinFormsUtil.Alert("Battle Box slots prevent the sorting of box."); return; }
|
|
SAV.sortBoxes(CB_BoxSelect.SelectedIndex, CB_BoxSelect.SelectedIndex + 1);
|
|
modified = "Current Box sorted!";
|
|
}
|
|
else
|
|
return;
|
|
|
|
setPKXBoxes();
|
|
updateBoxViewers(all);
|
|
WinFormsUtil.Alert(modified);
|
|
}
|
|
private void clickBoxDouble(object sender, MouseEventArgs e)
|
|
{
|
|
if (tabBoxMulti.SelectedTab == Tab_SAV)
|
|
{
|
|
clickSaveFileName(sender, e);
|
|
return;
|
|
}
|
|
if (tabBoxMulti.SelectedTab != Tab_Box)
|
|
return;
|
|
if (!SAV.HasBox)
|
|
return;
|
|
if (ModifierKeys != Keys.Shift)
|
|
{
|
|
var z = Application.OpenForms.Cast<Form>().FirstOrDefault(form => form.GetType() == typeof(SAV_BoxViewer)) as SAV_BoxViewer;
|
|
if (z != null)
|
|
{ WinFormsUtil.CenterToForm(z, this); z.BringToFront(); return; }
|
|
}
|
|
new SAV_BoxViewer(this).Show();
|
|
}
|
|
public int swapBoxesViewer(int viewBox)
|
|
{
|
|
int mainBox = CB_BoxSelect.SelectedIndex;
|
|
CB_BoxSelect.SelectedIndex = viewBox;
|
|
return mainBox;
|
|
}
|
|
public void notifyBoxViewerRefresh()
|
|
{
|
|
var views = Application.OpenForms.OfType<SAV_BoxViewer>();
|
|
foreach (var v in views.Where(v => DragInfo.WasDragParticipant(v, v.CurrentBox) == false))
|
|
v.setPKXBoxes();
|
|
if (DragInfo.WasDragParticipant(this, CB_BoxSelect.SelectedIndex) == false)
|
|
setPKXBoxes();
|
|
}
|
|
private void updateBoxViewers(bool all = false)
|
|
{
|
|
var views = Application.OpenForms.OfType<SAV_BoxViewer>();
|
|
foreach (var v in views.Where(v => v.CurrentBox == CB_BoxSelect.SelectedIndex || all))
|
|
v.setPKXBoxes();
|
|
}
|
|
|
|
private void clickSlot(object sender, EventArgs e)
|
|
{
|
|
switch (ModifierKeys)
|
|
{
|
|
case Keys.Control | Keys.Alt: clickClone(sender, e); break;
|
|
case Keys.Control: clickView(sender, e); break;
|
|
case Keys.Shift: clickSet(sender, e); break;
|
|
case Keys.Alt: clickDelete(sender, e); break;
|
|
}
|
|
}
|
|
private void clickView(object sender, EventArgs e)
|
|
{
|
|
int slot = getSlot(sender);
|
|
|
|
if (SlotPictureBoxes[slot].Image == null)
|
|
{ SystemSounds.Exclamation.Play(); return; }
|
|
if (PKMIsUnsaved && DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "PKM has been modified but has not been Set.", "Continue?"))
|
|
return;
|
|
int offset = getPKXOffset(slot);
|
|
if (offset < 0)
|
|
{
|
|
WinFormsUtil.Error($"Slot read error @ slot {slot}.");
|
|
return;
|
|
}
|
|
// Load the PKX file
|
|
PKM pk = 30 <= slot && slot < 36 ? SAV.getPartySlot(offset) : SAV.getStoredSlot(offset);
|
|
if (pk.Valid && pk.Species != 0)
|
|
{
|
|
try { populateFields(pk); }
|
|
catch { }
|
|
// Visual to display what slot is currently loaded.
|
|
getSlotColor(slot, Resources.slotView);
|
|
}
|
|
else
|
|
SystemSounds.Exclamation.Play();
|
|
}
|
|
private void clickSet(object sender, EventArgs e)
|
|
{
|
|
if (!verifiedPKM()) return;
|
|
int slot = getSlot(sender);
|
|
if (slot == 30 && (CB_Species.SelectedIndex == 0 || CHK_IsEgg.Checked))
|
|
{ WinFormsUtil.Alert("Can't have empty/egg first slot."); return; }
|
|
if (SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, slot))
|
|
{ WinFormsUtil.Alert("Can't set to locked slot."); return; }
|
|
|
|
int offset = getPKXOffset(slot);
|
|
if (offset < 0)
|
|
{
|
|
WinFormsUtil.Error($"Slot read error @ slot {slot}.");
|
|
return;
|
|
}
|
|
PKM pk = preparePKM();
|
|
|
|
string[] errata = SAV.IsPKMCompatible(pk);
|
|
if (errata.Length > 0 && DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, string.Join(Environment.NewLine, errata), "Continue?"))
|
|
return;
|
|
|
|
if (slot >= 30 && slot < 36) // Party
|
|
{
|
|
// If slot isn't overwriting existing PKM, make it write to the lowest empty PKM slot
|
|
if (SAV.PartyCount < slot + 1 - 30)
|
|
{ slot = SAV.PartyCount + 30; offset = getPKXOffset(slot); }
|
|
SAV.setPartySlot(pk, offset);
|
|
setParty();
|
|
getSlotColor(slot, Resources.slotSet);
|
|
}
|
|
else if (slot < 30 || HaX)
|
|
{
|
|
if (slot < 30)
|
|
{
|
|
UndoStack.Push(new SlotChange
|
|
{
|
|
Box = CB_BoxSelect.SelectedIndex,
|
|
Slot = slot,
|
|
Offset = offset,
|
|
OriginalData = SAV.getStoredSlot(offset)
|
|
});
|
|
Menu_Undo.Enabled = true;
|
|
}
|
|
|
|
SAV.setStoredSlot(pk, offset);
|
|
getQuickFiller(SlotPictureBoxes[slot], pk);
|
|
getSlotColor(slot, Resources.slotSet);
|
|
}
|
|
|
|
lastData = pk.Data;
|
|
updateBoxViewers();
|
|
|
|
RedoStack.Clear(); Menu_Redo.Enabled = false;
|
|
}
|
|
private void clickDelete(object sender, EventArgs e)
|
|
{
|
|
int slot = getSlot(sender);
|
|
if (slot == 30 && SAV.PartyCount == 1 && !HaX)
|
|
{ WinFormsUtil.Alert("Can't delete first slot."); return; }
|
|
if (SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, slot))
|
|
{ WinFormsUtil.Alert("Can't delete locked slot."); return; }
|
|
|
|
int offset = getPKXOffset(slot);
|
|
if (offset < 0)
|
|
{
|
|
WinFormsUtil.Error($"Slot read error @ slot {slot}.");
|
|
return;
|
|
}
|
|
if (slot >= 30 && slot < 36) // Party
|
|
{
|
|
SAV.deletePartySlot(slot-30);
|
|
setParty();
|
|
getSlotColor(slot, Resources.slotDel);
|
|
return;
|
|
}
|
|
if (slot < 30 || HaX)
|
|
{
|
|
if (slot < 30)
|
|
{
|
|
UndoStack.Push(new SlotChange
|
|
{
|
|
Box = CB_BoxSelect.SelectedIndex,
|
|
Slot = slot,
|
|
Offset = offset,
|
|
OriginalData = SAV.getStoredSlot(offset)
|
|
});
|
|
Menu_Undo.Enabled = true;
|
|
}
|
|
SAV.setStoredSlot(SAV.BlankPKM, getPKXOffset(slot));
|
|
}
|
|
else return;
|
|
|
|
getQuickFiller(SlotPictureBoxes[slot], SAV.BlankPKM);
|
|
getSlotColor(slot, Resources.slotDel);
|
|
updateBoxViewers();
|
|
|
|
RedoStack.Clear(); Menu_Redo.Enabled = false;
|
|
}
|
|
private readonly Stack<SlotChange> UndoStack = new Stack<SlotChange>();
|
|
private readonly Stack<SlotChange> RedoStack = new Stack<SlotChange>();
|
|
private void clickUndo(object sender, EventArgs e)
|
|
{
|
|
if (!UndoStack.Any())
|
|
return;
|
|
|
|
SlotChange change = UndoStack.Pop();
|
|
if (change.Slot >= 30)
|
|
return;
|
|
|
|
RedoStack.Push(new SlotChange
|
|
{
|
|
Slot = change.Slot,
|
|
Box = change.Box,
|
|
Offset = change.Offset,
|
|
OriginalData = SAV.getStoredSlot(change.Offset)
|
|
});
|
|
undoSlotChange(change);
|
|
}
|
|
private void clickRedo(object sender, EventArgs e)
|
|
{
|
|
if (!RedoStack.Any())
|
|
return;
|
|
|
|
SlotChange change = RedoStack.Pop();
|
|
if (change.Slot >= 30)
|
|
return;
|
|
|
|
UndoStack.Push(new SlotChange
|
|
{
|
|
Slot = change.Slot,
|
|
Box = change.Box,
|
|
Offset = change.Offset,
|
|
OriginalData = SAV.getStoredSlot(change.Offset)
|
|
});
|
|
undoSlotChange(change);
|
|
}
|
|
private void undoSlotChange(SlotChange change)
|
|
{
|
|
int slot = change.Slot;
|
|
int offset = change.Offset;
|
|
PKM pk = (PKM)change.OriginalData;
|
|
|
|
if (CB_BoxSelect.SelectedIndex != change.Box)
|
|
CB_BoxSelect.SelectedIndex = change.Box;
|
|
SAV.setStoredSlot(pk, offset);
|
|
getQuickFiller(SlotPictureBoxes[slot], pk);
|
|
getSlotColor(slot, Resources.slotSet);
|
|
|
|
Menu_Undo.Enabled = UndoStack.Any();
|
|
Menu_Redo.Enabled = RedoStack.Any();
|
|
|
|
SystemSounds.Asterisk.Play();
|
|
}
|
|
private void clickClone(object sender, EventArgs e)
|
|
{
|
|
if (getSlot(sender) > 30) return; // only perform action if cloning to boxes
|
|
if (!verifiedPKM()) return; // don't copy garbage to the box
|
|
|
|
if (WinFormsUtil.Prompt(MessageBoxButtons.YesNo, $"Clone Pokemon from Editing Tabs to all slots in {CB_BoxSelect.Text}?") != DialogResult.Yes)
|
|
return;
|
|
|
|
PKM pk = preparePKM();
|
|
|
|
int slotSkipped = 0;
|
|
for (int i = 0; i < SAV.BoxSlotCount; i++) // set to every slot in box
|
|
{
|
|
if (SAV.getIsSlotLocked(CB_BoxSelect.SelectedIndex, i))
|
|
{ slotSkipped++; continue; }
|
|
SAV.setStoredSlot(pk, getPKXOffset(i));
|
|
getQuickFiller(SlotPictureBoxes[i], pk);
|
|
}
|
|
|
|
if (slotSkipped > 0)
|
|
WinFormsUtil.Alert($"Skipped {slotSkipped} locked slot{(slotSkipped > 1 ? "s" : "")}.");
|
|
|
|
updateBoxViewers();
|
|
}
|
|
private void clickLegality(object sender, EventArgs e)
|
|
{
|
|
int slot = getSlot(sender);
|
|
PKM pk;
|
|
if (slot >= 0)
|
|
{
|
|
pk = SAV.getStoredSlot(getPKXOffset(slot));
|
|
if (slot < 30 || slot >= 36) // not party
|
|
pk.Box = CB_BoxSelect.SelectedIndex; // mark as in a box
|
|
}
|
|
else if (verifiedPKM())
|
|
pk = preparePKM();
|
|
else
|
|
return;
|
|
|
|
if (pk.Species == 0 || !pk.ChecksumValid)
|
|
{ SystemSounds.Asterisk.Play(); return; }
|
|
showLegality(pk, slot < 0, ModifierKeys == Keys.Control);
|
|
}
|
|
private void updateSaveSlot(object sender, EventArgs e)
|
|
{
|
|
if (SAV.Version != GameVersion.BATREV)
|
|
return;
|
|
((SAV4BR)SAV).CurrentSlot = WinFormsUtil.getIndex(CB_SaveSlot);
|
|
setPKXBoxes();
|
|
}
|
|
private void updateStringSeed(object sender, EventArgs e)
|
|
{
|
|
if (!fieldsLoaded)
|
|
return;
|
|
|
|
TextBox tb = sender as TextBox;
|
|
if (tb == null)
|
|
return;
|
|
|
|
if (tb.Text.Length == 0)
|
|
{
|
|
tb.Undo();
|
|
return;
|
|
}
|
|
|
|
string filterText = Util.getOnlyHex(tb.Text);
|
|
if (filterText.Length != tb.Text.Length)
|
|
{
|
|
WinFormsUtil.Alert("Expected HEX (0-9, A-F).", "Received: " + Environment.NewLine + tb.Text);
|
|
tb.Undo();
|
|
return;
|
|
}
|
|
|
|
// Write final value back to the save
|
|
if (tb == TB_RNGSeed)
|
|
{
|
|
var value = filterText.PadLeft(SAV.DaycareSeedSize, '0');
|
|
SAV.setDaycareRNGSeed(SAV.DaycareIndex, value);
|
|
SAV.Edited = true;
|
|
}
|
|
else if (tb == TB_GameSync)
|
|
{
|
|
var value = filterText.PadLeft(SAV.GameSyncIDSize, '0');
|
|
SAV.GameSyncID = value;
|
|
SAV.Edited = true;
|
|
}
|
|
else if (SAV.Generation >= 6)
|
|
{
|
|
var value = Convert.ToUInt64(filterText, 16);
|
|
if (tb == TB_Secure1)
|
|
SAV.Secure1 = value;
|
|
else if (tb == TB_Secure2)
|
|
SAV.Secure2 = value;
|
|
SAV.Edited = true;
|
|
}
|
|
}
|
|
private void updateIsNicknamed(object sender, EventArgs e)
|
|
{
|
|
if (!fieldsLoaded)
|
|
return;
|
|
|
|
pkm.Nickname = TB_Nickname.Text;
|
|
if (CHK_Nicknamed.Checked)
|
|
return;
|
|
|
|
int species = WinFormsUtil.getIndex(CB_Species);
|
|
if (species < 1 || species > SAV.MaxSpeciesID)
|
|
return;
|
|
|
|
if (CHK_IsEgg.Checked)
|
|
species = 0; // get the egg name.
|
|
|
|
if (PKX.getIsNicknamedAnyLanguage(species, TB_Nickname.Text, SAV.Generation))
|
|
CHK_Nicknamed.Checked = true;
|
|
}
|
|
|
|
// Generic Subfunctions //
|
|
public void setParty()
|
|
{
|
|
PKM[] party = SAV.PartyData;
|
|
PKM[] battle = SAV.BattleBoxData;
|
|
// Refresh slots
|
|
if (SAV.HasParty)
|
|
{
|
|
for (int i = 0; i < party.Length; i++)
|
|
getQuickFiller(SlotPictureBoxes[i + 30], party[i]);
|
|
for (int i = party.Length; i < 6; i++)
|
|
SlotPictureBoxes[i + 30].Image = null;
|
|
}
|
|
if (SAV.HasBattleBox)
|
|
{
|
|
for (int i = 0; i < battle.Length; i++)
|
|
getQuickFiller(SlotPictureBoxes[i + 36], battle[i]);
|
|
for (int i = battle.Length; i < 6; i++)
|
|
SlotPictureBoxes[i + 36].Image = null;
|
|
}
|
|
}
|
|
private int getPKXOffset(int slot)
|
|
{
|
|
if (slot < 30) // Box Slot
|
|
return SAV.getBoxOffset(CB_BoxSelect.SelectedIndex) + slot * SAV.SIZE_STORED;
|
|
slot -= 30;
|
|
if (slot < 6) // Party Slot
|
|
return SAV.getPartyOffset(slot);
|
|
slot -= 6;
|
|
if (slot < 6) // Battle Box Slot
|
|
return SAV.BattleBox + slot * SAV.SIZE_STORED;
|
|
slot -= 6;
|
|
if (slot < 2) // Daycare
|
|
return SAV.getDaycareSlotOffset(SAV.DaycareIndex, slot);
|
|
slot -= 2;
|
|
if (slot == 0) // GTS
|
|
return SAV.GTS;
|
|
slot -= 1;
|
|
if (slot == 0) // Fused
|
|
return SAV.Fused;
|
|
slot -= 1;
|
|
if (slot < 3) // SUBE
|
|
return SAV.SUBE + slot * (SAV.SIZE_STORED + 4);
|
|
return -1;
|
|
}
|
|
private int getSlot(object sender)
|
|
{
|
|
sender = ((sender as ToolStripItem)?.Owner as ContextMenuStrip)?.SourceControl ?? sender as PictureBox;
|
|
return Array.IndexOf(SlotPictureBoxes, sender);
|
|
}
|
|
public void setPKXBoxes()
|
|
{
|
|
if (SAV.HasBox)
|
|
{
|
|
int boxoffset = SAV.getBoxOffset(CB_BoxSelect.SelectedIndex);
|
|
int boxbgval = SAV.getBoxWallpaper(CB_BoxSelect.SelectedIndex);
|
|
PAN_Box.BackgroundImage = SAV.WallpaperImage(boxbgval);
|
|
for (int i = 0; i < 30; i++)
|
|
{
|
|
if (i < SAV.BoxSlotCount)
|
|
{
|
|
getSlotFiller(boxoffset + SAV.SIZE_STORED * i, SlotPictureBoxes[i]);
|
|
}
|
|
else
|
|
{
|
|
SlotPictureBoxes[i].Image = null;
|
|
SlotPictureBoxes[i].Visible = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reload Party
|
|
if (SAV.HasParty)
|
|
{
|
|
for (int i = 0; i < 6; i++)
|
|
getSlotFiller(SAV.getPartyOffset(i), SlotPictureBoxes[i + 30]);
|
|
}
|
|
|
|
// Reload Battle Box
|
|
if (SAV.HasBattleBox)
|
|
{
|
|
for (int i = 0; i < 6; i++)
|
|
getSlotFiller(SAV.BattleBox + SAV.SIZE_STORED * i, SlotPictureBoxes[i + 36]);
|
|
}
|
|
|
|
// Reload Daycare
|
|
if (SAV.HasDaycare)
|
|
{
|
|
Label[] L_SlotOccupied = { L_DC1, L_DC2 };
|
|
TextBox[] TB_SlotEXP = { TB_Daycare1XP, TB_Daycare2XP };
|
|
Label[] L_SlotEXP = { L_XP1, L_XP2 };
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
getSlotFiller(SAV.getDaycareSlotOffset(SAV.DaycareIndex, i), SlotPictureBoxes[i + 42]);
|
|
uint? exp = SAV.getDaycareEXP(SAV.DaycareIndex, i);
|
|
TB_SlotEXP[i].Visible = L_SlotEXP[i].Visible = exp != null;
|
|
TB_SlotEXP[i].Text = exp.ToString();
|
|
bool? occ = SAV.getDaycareOccupied(SAV.DaycareIndex, i);
|
|
L_SlotOccupied[i].Visible = occ != null;
|
|
if (occ == true) // If Occupied
|
|
L_SlotOccupied[i].Text = $"{i + 1}: ✓";
|
|
else
|
|
{
|
|
L_SlotOccupied[i].Text = $"{i + 1}: ✘";
|
|
SlotPictureBoxes[i + 42].Image = ImageUtil.ChangeOpacity(SlotPictureBoxes[i + 42].Image, 0.6);
|
|
}
|
|
}
|
|
bool? egg = SAV.getDaycareHasEgg(SAV.DaycareIndex);
|
|
DayCare_HasEgg.Visible = egg != null;
|
|
DayCare_HasEgg.Checked = egg == true;
|
|
|
|
var seed = SAV.getDaycareRNGSeed(SAV.DaycareIndex);
|
|
L_DaycareSeed.Visible = TB_RNGSeed.Visible = seed != null;
|
|
if (seed != null)
|
|
{
|
|
TB_RNGSeed.MaxLength = SAV.DaycareSeedSize;
|
|
TB_RNGSeed.Text = seed;
|
|
}
|
|
}
|
|
|
|
// GTS
|
|
if (SAV.HasGTS)
|
|
getSlotFiller(SAV.GTS, SlotPictureBoxes[44]);
|
|
|
|
// Fused
|
|
if (SAV.HasFused)
|
|
getSlotFiller(SAV.Fused, SlotPictureBoxes[45]);
|
|
|
|
// SUBE
|
|
if (SAV.HasSUBE)
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
int offset = SAV.SUBE + i * (SAV.SIZE_STORED + 4);
|
|
if (BitConverter.ToUInt64(SAV.Data, offset) != 0)
|
|
getSlotFiller(offset, SlotPictureBoxes[46 + i]);
|
|
else SlotPictureBoxes[46 + i].Image = null;
|
|
}
|
|
|
|
// Recoloring of a storage box slot (to not show for other storage boxes)
|
|
if (colorizedslot <= SAV.BoxCount)
|
|
SlotPictureBoxes[colorizedslot].BackgroundImage = colorizedbox == CB_BoxSelect.SelectedIndex ? colorizedcolor : null;
|
|
}
|
|
private void setBoxNames()
|
|
{
|
|
if (!SAV.HasBox)
|
|
return;
|
|
// Build ComboBox Dropdown Items
|
|
try
|
|
{
|
|
CB_BoxSelect.Items.Clear();
|
|
for (int i = 0; i < SAV.BoxCount; i++)
|
|
CB_BoxSelect.Items.Add(SAV.getBoxName(i));
|
|
}
|
|
catch
|
|
{
|
|
CB_BoxSelect.Items.Clear();
|
|
for (int i = 1; i <= SAV.BoxCount; i++)
|
|
CB_BoxSelect.Items.Add($"BOX {i}");
|
|
}
|
|
if (SAV.CurrentBox < CB_BoxSelect.Items.Count)
|
|
CB_BoxSelect.SelectedIndex = SAV.CurrentBox; // restore selected box
|
|
}
|
|
private void getQuickFiller(PictureBox pb, PKM pk = null)
|
|
{
|
|
if (!fieldsInitialized) return;
|
|
pk = pk ?? preparePKM(false); // don't perform control loss click
|
|
|
|
if (pb == dragout) mnuLQR.Enabled = pk.Species != 0; // Species
|
|
|
|
int slot = getSlot(pb);
|
|
pb.Image = pk.Sprite(SAV, CB_BoxSelect.SelectedIndex, slot, Menu_FlagIllegal.Checked);
|
|
if (pb.BackColor == Color.Red)
|
|
pb.BackColor = Color.Transparent;
|
|
}
|
|
private void getSlotFiller(int offset, PictureBox pb)
|
|
{
|
|
if (SAV.getData(offset, SAV.SIZE_STORED).SequenceEqual(new byte[SAV.SIZE_STORED]))
|
|
{
|
|
// 00s present in slot.
|
|
pb.Image = null;
|
|
pb.BackColor = Color.Transparent;
|
|
pb.Visible = true;
|
|
return;
|
|
}
|
|
PKM p = SAV.getStoredSlot(offset);
|
|
if (!p.Valid) // Invalid
|
|
{
|
|
// Bad Egg present in slot.
|
|
pb.Image = null;
|
|
pb.BackColor = Color.Red;
|
|
pb.Visible = true;
|
|
return;
|
|
}
|
|
|
|
int slot = getSlot(pb);
|
|
pb.Image = p.Sprite(SAV, CB_BoxSelect.SelectedIndex, slot, Menu_FlagIllegal.Checked);
|
|
pb.BackColor = Color.Transparent;
|
|
pb.Visible = true;
|
|
}
|
|
private void getSlotColor(int slot, Image color)
|
|
{
|
|
foreach (PictureBox t in SlotPictureBoxes)
|
|
t.BackgroundImage = null;
|
|
|
|
if (slot < 30)
|
|
colorizedbox = CB_BoxSelect.SelectedIndex;
|
|
|
|
SlotPictureBoxes[slot].BackgroundImage = color;
|
|
colorizedcolor = color;
|
|
colorizedslot = slot;
|
|
}
|
|
private void getBox(object sender, EventArgs e)
|
|
{
|
|
if (SAV.CurrentBox != CB_BoxSelect.SelectedIndex)
|
|
{
|
|
SAV.CurrentBox = CB_BoxSelect.SelectedIndex;
|
|
SAV.Edited = true; // Dumb
|
|
}
|
|
setPKXBoxes();
|
|
}
|
|
private void switchDaycare(object sender, EventArgs e)
|
|
{
|
|
if (!SAV.HasTwoDaycares) return;
|
|
if (DialogResult.Yes == WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Would you like to switch the view to the other Daycare?",
|
|
$"Currently viewing daycare {SAV.DaycareIndex + 1}."))
|
|
// If ORAS, alter the daycare offset via toggle.
|
|
SAV.DaycareIndex ^= 1;
|
|
|
|
// Refresh Boxes
|
|
setPKXBoxes();
|
|
}
|
|
private void loadBoxesFromDB(string path)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(path)) return;
|
|
if (!SAV.HasBox) return;
|
|
|
|
DialogResult dr = WinFormsUtil.Prompt(MessageBoxButtons.YesNoCancel, "Clear subsequent boxes when importing data?", "If you only want to overwrite for new data, press no.");
|
|
if (dr == DialogResult.Cancel)
|
|
return;
|
|
|
|
string result;
|
|
bool clearAll = dr == DialogResult.Yes;
|
|
bool? noSetb = getPKMSetOverride();
|
|
|
|
SAV.loadBoxes(path, out result, CB_BoxSelect.SelectedIndex, clearAll, noSetb);
|
|
setPKXBoxes();
|
|
WinFormsUtil.Alert(result);
|
|
}
|
|
private void B_SaveBoxBin_Click(object sender, EventArgs e)
|
|
{
|
|
if (!SAV.HasBox)
|
|
{ WinFormsUtil.Alert("Save file does not have boxes to dump!"); return; }
|
|
|
|
DialogResult dr = WinFormsUtil.Prompt(MessageBoxButtons.YesNoCancel,
|
|
"Yes: Export All Boxes" + Environment.NewLine +
|
|
$"No: Export {CB_BoxSelect.Text} (Box {CB_BoxSelect.SelectedIndex + 1})" + Environment.NewLine +
|
|
"Cancel: Abort");
|
|
|
|
if (dr == DialogResult.Yes)
|
|
{
|
|
SaveFileDialog sfd = new SaveFileDialog {Filter = "Box Data|*.bin", FileName = "pcdata.bin"};
|
|
if (sfd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
File.WriteAllBytes(sfd.FileName, SAV.getPCBin());
|
|
}
|
|
else if (dr == DialogResult.No)
|
|
{
|
|
SaveFileDialog sfd = new SaveFileDialog {Filter = "Box Data|*.bin", FileName = $"boxdata {CB_BoxSelect.Text}.bin"};
|
|
if (sfd.ShowDialog() != DialogResult.OK)
|
|
return;
|
|
File.WriteAllBytes(sfd.FileName, SAV.getBoxBin(CB_BoxSelect.SelectedIndex));
|
|
}
|
|
}
|
|
private bool? getPKMSetOverride()
|
|
{
|
|
var yn = Menu_ModifyPKM.Checked ? "Yes" : "No";
|
|
DialogResult noSet = WinFormsUtil.Prompt(MessageBoxButtons.YesNoCancel,
|
|
"Loading overrides:",
|
|
"Yes - Modify .pk* when set to SAV" + Environment.NewLine +
|
|
"No - Don't modify .pk*" + Environment.NewLine +
|
|
$"Cancel - Use current settings ({yn})");
|
|
return noSet == DialogResult.Yes ? true : (noSet == DialogResult.No ? (bool?)false : null);
|
|
}
|
|
|
|
// Subfunction Save Buttons //
|
|
private void B_OpenWondercards_Click(object sender, EventArgs e) => new SAV_Wondercard(sender as MysteryGift).ShowDialog();
|
|
private void B_OpenPokepuffs_Click(object sender, EventArgs e) => new SAV_Pokepuff().ShowDialog();
|
|
private void B_OpenPokeBeans_Click(object sender, EventArgs e) => new SAV_Pokebean().ShowDialog();
|
|
private void B_OpenItemPouch_Click(object sender, EventArgs e) => new SAV_Inventory().ShowDialog();
|
|
private void B_OpenBerryField_Click(object sender, EventArgs e) => new SAV_BerryFieldXY().ShowDialog();
|
|
private void B_OpenPokeblocks_Click(object sender, EventArgs e) => new SAV_PokeBlockORAS().ShowDialog();
|
|
private void B_OpenEventFlags_Click(object sender, EventArgs e) => new SAV_EventFlags().ShowDialog();
|
|
private void B_OpenSuperTraining_Click(object sender, EventArgs e) => new SAV_SuperTrain().ShowDialog();
|
|
private void B_OpenSecretBase_Click(object sender, EventArgs e) => new SAV_SecretBase().ShowDialog();
|
|
private void B_OpenZygardeCells_Click(object sender, EventArgs e) => new SAV_ZygardeCell().ShowDialog();
|
|
private void B_LinkInfo_Click(object sender, EventArgs e) => new SAV_Link6().ShowDialog();
|
|
private void B_OpenBoxLayout_Click(object sender, EventArgs e)
|
|
{
|
|
new SAV_BoxLayout(CB_BoxSelect.SelectedIndex).ShowDialog();
|
|
setBoxNames(); // fix box names
|
|
setPKXBoxes(); // refresh box background
|
|
updateBoxViewers(all:true); // update subviewers
|
|
}
|
|
private void B_OpenTrainerInfo_Click(object sender, EventArgs e)
|
|
{
|
|
if (SAV.Generation < 6)
|
|
new SAV_SimpleTrainer().ShowDialog();
|
|
else if (SAV.Generation == 6)
|
|
new SAV_Trainer().ShowDialog();
|
|
else if (SAV.Generation == 7)
|
|
new SAV_Trainer7().ShowDialog();
|
|
// Refresh conversion info
|
|
PKMConverter.updateConfig(SAV.SubRegion, SAV.Country, SAV.ConsoleRegion, SAV.OT, SAV.Gender, SAV.Language);
|
|
}
|
|
private void B_OpenOPowers_Click(object sender, EventArgs e)
|
|
{
|
|
if (SAV.Generation != 6)
|
|
return;
|
|
if (SAV.ORAS)
|
|
{
|
|
DialogResult dr = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "No editing support for ORAS :(", "Max O-Powers with a working code?");
|
|
if (dr != DialogResult.Yes) return;
|
|
new byte[]
|
|
{
|
|
0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00,
|
|
0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01,
|
|
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
|
0x01, 0x00, 0x00, 0x00,
|
|
}.CopyTo(SAV.Data, ((SAV6) SAV).OPower);
|
|
}
|
|
else if (SAV.XY)
|
|
new SAV_OPower().ShowDialog();
|
|
}
|
|
private void B_OpenFriendSafari_Click(object sender, EventArgs e)
|
|
{
|
|
if (!SAV.XY)
|
|
return;
|
|
|
|
DialogResult dr = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "No editing support for Friend Safari :(", "Unlock all 3 slots for each friend?");
|
|
if (dr != DialogResult.Yes) return;
|
|
|
|
// Unlock + reveal all safari slots if friend data is present
|
|
for (int i = 1; i < 101; i++)
|
|
if (SAV.Data[0x1E7FF + 0x15*i] != 0x00) // no friend data == 0x00
|
|
SAV.Data[0x1E7FF + 0x15*i] = 0x3D;
|
|
}
|
|
private void B_OpenPokedex_Click(object sender, EventArgs e)
|
|
{
|
|
switch (SAV.Generation)
|
|
{
|
|
case 1:
|
|
case 2:
|
|
new SAV_SimplePokedex().ShowDialog(); break;
|
|
case 3:
|
|
if (SAV.GameCube)
|
|
return;
|
|
new SAV_SimplePokedex().ShowDialog(); break;
|
|
case 4:
|
|
if (SAV is SAV4BR)
|
|
return;
|
|
new SAV_Pokedex4().ShowDialog(); break;
|
|
case 5:
|
|
new SAV_Pokedex5().ShowDialog(); break;
|
|
case 6:
|
|
if (SAV.ORAS)
|
|
new SAV_PokedexORAS().ShowDialog();
|
|
else if (SAV.XY)
|
|
new SAV_PokedexXY().ShowDialog();
|
|
break;
|
|
case 7:
|
|
if (SAV.SM)
|
|
new SAV_PokedexSM().ShowDialog();
|
|
break;
|
|
}
|
|
}
|
|
private void B_OpenMiscEditor_Click(object sender, EventArgs e)
|
|
{
|
|
switch (SAV.Generation)
|
|
{
|
|
case 3:
|
|
new SAV_Misc3().ShowDialog(); break;
|
|
case 4:
|
|
new SAV_Misc4().ShowDialog(); break;
|
|
}
|
|
}
|
|
private void B_OpenRTCEditor_Click(object sender, EventArgs e)
|
|
{
|
|
switch (SAV.Generation)
|
|
{
|
|
case 3:
|
|
new SAV_RTC3().ShowDialog(); break;
|
|
}
|
|
}
|
|
private void B_OpenHoneyTreeEditor_Click(object sender, EventArgs e)
|
|
{
|
|
switch (SAV.Version)
|
|
{
|
|
case GameVersion.DP:
|
|
case GameVersion.Pt:
|
|
new SAV_HoneyTree().ShowDialog(); break;
|
|
}
|
|
}
|
|
private void B_OUTPasserby_Click(object sender, EventArgs e)
|
|
{
|
|
if (SAV.Generation != 6)
|
|
return;
|
|
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Export Passerby Info to Clipboard?"))
|
|
return;
|
|
string result = "PSS List" + Environment.NewLine;
|
|
string[] headers = { "PSS Data - Friends", "PSS Data - Acquaintances", "PSS Data - Passerby", };
|
|
int offset = ((SAV6) SAV).PSS;
|
|
for (int g = 0; g < 3; g++)
|
|
{
|
|
result += Environment.NewLine
|
|
+ "----" + Environment.NewLine
|
|
+ headers[g] + Environment.NewLine
|
|
+ "----" + Environment.NewLine;
|
|
// uint count = BitConverter.ToUInt32(savefile, offset + 0x4E20);
|
|
int r_offset = offset;
|
|
|
|
for (int i = 0; i < 100; i++)
|
|
{
|
|
ulong unkn = BitConverter.ToUInt64(SAV.Data, r_offset);
|
|
if (unkn == 0) break; // No data present here
|
|
if (i > 0) result += Environment.NewLine + Environment.NewLine;
|
|
|
|
string otname = Util.TrimFromZero(Encoding.Unicode.GetString(SAV.Data, r_offset + 8, 0x1A));
|
|
string message = Util.TrimFromZero(Encoding.Unicode.GetString(SAV.Data, r_offset + 0x22, 0x22));
|
|
|
|
// Trim terminated
|
|
|
|
// uint unk1 = BitConverter.ToUInt32(savefile, r_offset + 0x44);
|
|
// ulong unk2 = BitConverter.ToUInt64(savefile, r_offset + 0x48);
|
|
// uint unk3 = BitConverter.ToUInt32(savefile, r_offset + 0x50);
|
|
// uint unk4 = BitConverter.ToUInt16(savefile, r_offset + 0x54);
|
|
byte region = SAV.Data[r_offset + 0x56];
|
|
byte country = SAV.Data[r_offset + 0x57];
|
|
byte game = SAV.Data[r_offset + 0x5A];
|
|
// ulong outfit = BitConverter.ToUInt64(savefile, r_offset + 0x5C);
|
|
int favpkm = BitConverter.ToUInt16(SAV.Data, r_offset + 0x9C) & 0x7FF;
|
|
string gamename;
|
|
try { gamename = GameInfo.Strings.gamelist[game]; }
|
|
catch { gamename = "UNKNOWN GAME"; }
|
|
|
|
var cr = GameInfo.getCountryRegionText(country, region, curlanguage);
|
|
result +=
|
|
"OT: " + otname + Environment.NewLine +
|
|
"Message: " + message + Environment.NewLine +
|
|
"Game: " + gamename + Environment.NewLine +
|
|
"Country: " + cr.Item1 + Environment.NewLine +
|
|
"Region: " + cr.Item2 + Environment.NewLine +
|
|
"Favorite: " + GameInfo.Strings.specieslist[favpkm];
|
|
|
|
r_offset += 0xC8; // Advance to next entry
|
|
}
|
|
offset += 0x5000; // Advance to next block
|
|
}
|
|
Clipboard.SetText(result);
|
|
}
|
|
private void B_OUTHallofFame_Click(object sender, EventArgs e)
|
|
{
|
|
if (SAV.Generation == 6)
|
|
new SAV_HallOfFame().ShowDialog();
|
|
else if (SAV.SM)
|
|
new SAV_HallOfFame7().ShowDialog();
|
|
}
|
|
private void B_CGearSkin_Click(object sender, EventArgs e)
|
|
{
|
|
if (SAV.Generation != 5)
|
|
return; // can never be too safe
|
|
new SAV_CGearSkin().ShowDialog();
|
|
}
|
|
private void B_JPEG_Click(object sender, EventArgs e)
|
|
{
|
|
byte[] jpeg = SAV.JPEGData;
|
|
if (SAV.JPEGData == null)
|
|
{ WinFormsUtil.Alert("No PGL picture data found in the save file!"); return; }
|
|
string filename = SAV.JPEGTitle + "'s picture";
|
|
SaveFileDialog sfd = new SaveFileDialog {FileName = filename, Filter = "JPEG|*.jpeg"};
|
|
if (sfd.ShowDialog() != DialogResult.OK) return;
|
|
File.WriteAllBytes(sfd.FileName, jpeg);
|
|
}
|
|
// Save Folder Related
|
|
private void clickSaveFileName(object sender, EventArgs e)
|
|
{
|
|
string path;
|
|
string cgse = "";
|
|
string pathCache = CyberGadgetUtil.GetCacheFolder();
|
|
if (Directory.Exists(pathCache))
|
|
cgse = Path.Combine(pathCache);
|
|
if (!SaveUtil.detectSaveFile(out path, cgse))
|
|
WinFormsUtil.Error(path);
|
|
if (path == null || !File.Exists(path)) return;
|
|
if (WinFormsUtil.Prompt(MessageBoxButtons.YesNo, "Open save file from the following location?", path) == DialogResult.Yes)
|
|
openQuick(path); // load save
|
|
}
|
|
|
|
// Drag and drop related functions
|
|
private static Image OriginalBackground;
|
|
private static Image CurrentBackground;
|
|
private void pbBoxSlot_MouseEnter(object sender, EventArgs e)
|
|
{
|
|
var pb = (PictureBox) sender;
|
|
if (pb.Image == null)
|
|
return;
|
|
OriginalBackground = pb.BackgroundImage;
|
|
pb.BackgroundImage = CurrentBackground = Resources.slotHover;
|
|
Cursor = Cursors.Hand;
|
|
}
|
|
private void pbBoxSlot_MouseLeave(object sender, EventArgs e)
|
|
{
|
|
var pb = (PictureBox)sender;
|
|
if (pb.BackgroundImage != CurrentBackground)
|
|
return;
|
|
pb.BackgroundImage = OriginalBackground;
|
|
Cursor = Cursors.Default;
|
|
}
|
|
private void pbBoxSlot_MouseClick(object sender, MouseEventArgs e)
|
|
{
|
|
if (!DragInfo.slotDragDropInProgress)
|
|
clickSlot(sender, e);
|
|
}
|
|
private void pbBoxSlot_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
DragInfo.slotLeftMouseIsDown = false;
|
|
if (e.Button == MouseButtons.Right)
|
|
DragInfo.slotRightMouseIsDown = false;
|
|
}
|
|
private void pbBoxSlot_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
if (e.Button == MouseButtons.Left)
|
|
DragInfo.slotLeftMouseIsDown = true;
|
|
if (e.Button == MouseButtons.Right)
|
|
DragInfo.slotRightMouseIsDown = true;
|
|
}
|
|
private void pbBoxSlot_MouseMove(object sender, MouseEventArgs e)
|
|
{
|
|
if (DragInfo.slotDragDropInProgress)
|
|
return;
|
|
|
|
if (!DragInfo.slotLeftMouseIsDown)
|
|
return;
|
|
|
|
// The goal is to create a temporary PKX file for the underlying Pokemon
|
|
// and use that file to perform a drag drop operation.
|
|
|
|
// Abort if there is no Pokemon in the given slot.
|
|
PictureBox pb = (PictureBox)sender;
|
|
if (pb.Image == null)
|
|
return;
|
|
|
|
int slot = getSlot(pb);
|
|
int box = slot >= 30 ? -1 : CB_BoxSelect.SelectedIndex;
|
|
if (SAV.getIsSlotLocked(box, slot))
|
|
return;
|
|
|
|
// Set flag to prevent re-entering.
|
|
DragInfo.slotDragDropInProgress = true;
|
|
|
|
DragInfo.slotSource = this;
|
|
DragInfo.slotSourceSlotNumber = slot;
|
|
DragInfo.slotSourceBoxNumber = box;
|
|
DragInfo.slotSourceOffset = getPKXOffset(DragInfo.slotSourceSlotNumber);
|
|
|
|
// Prepare Data
|
|
DragInfo.slotPkmSource = SAV.getData(DragInfo.slotSourceOffset, SAV.SIZE_STORED);
|
|
|
|
// Make a new file name based off the PID
|
|
bool encrypt = ModifierKeys == Keys.Control;
|
|
byte[] dragdata = SAV.decryptPKM(DragInfo.slotPkmSource);
|
|
Array.Resize(ref dragdata, SAV.SIZE_STORED);
|
|
PKM pkx = SAV.getPKM(dragdata);
|
|
string fn = pkx.FileName; fn = fn.Substring(0, fn.LastIndexOf('.'));
|
|
string filename = $"{fn}{(encrypt ? ".ek" + pkx.Format : "." + pkx.Extension)}";
|
|
|
|
// Make File
|
|
string newfile = Path.Combine(Path.GetTempPath(), Util.CleanFileName(filename));
|
|
try
|
|
{
|
|
File.WriteAllBytes(newfile, encrypt ? pkx.EncryptedBoxData : pkx.DecryptedBoxData);
|
|
var img = (Bitmap)pb.Image;
|
|
DragInfo.Cursor = Cursor.Current = new Cursor(img.GetHicon());
|
|
pb.Image = null;
|
|
pb.BackgroundImage = Resources.slotDrag;
|
|
// Thread Blocks on DoDragDrop
|
|
DragInfo.CurrentPath = newfile;
|
|
DragDropEffects result = pb.DoDragDrop(new DataObject(DataFormats.FileDrop, new[] { newfile }), DragDropEffects.Move);
|
|
if (!DragInfo.SourceValid || result != DragDropEffects.Link) // not dropped to another box slot, restore img
|
|
pb.Image = img;
|
|
else // refresh image
|
|
getQuickFiller(pb, SAV.getStoredSlot(DragInfo.slotSourceOffset));
|
|
pb.BackgroundImage = null;
|
|
|
|
if (DragInfo.SameBox && DragInfo.DestinationValid)
|
|
{
|
|
if (SAV.getIsTeamSet(box, DragInfo.slotDestinationSlotNumber) ^ SAV.getIsTeamSet(box, DragInfo.slotSourceSlotNumber))
|
|
getQuickFiller(SlotPictureBoxes[DragInfo.slotDestinationSlotNumber], SAV.getStoredSlot(DragInfo.slotDestinationOffset));
|
|
else
|
|
SlotPictureBoxes[DragInfo.slotDestinationSlotNumber].Image = img;
|
|
}
|
|
|
|
if (result == DragDropEffects.Copy) // viewed in tabs, apply 'view' highlight
|
|
getSlotColor(DragInfo.slotSourceSlotNumber, Resources.slotView);
|
|
}
|
|
catch (Exception x)
|
|
{
|
|
WinFormsUtil.Error("Drag & Drop Error", x);
|
|
}
|
|
notifyBoxViewerRefresh();
|
|
DragInfo.Reset();
|
|
Cursor = DefaultCursor;
|
|
|
|
// Browser apps need time to load data since the file isn't moved to a location on the user's local storage.
|
|
// Tested 10ms -> too quick, 100ms was fine. 500ms should be safe?
|
|
new Thread(() =>
|
|
{
|
|
Thread.Sleep(500);
|
|
if (File.Exists(newfile) && DragInfo.CurrentPath == null)
|
|
File.Delete(newfile);
|
|
}).Start();
|
|
if (DragInfo.SourceParty || DragInfo.DestinationParty)
|
|
setParty();
|
|
}
|
|
private void pbBoxSlot_DragDrop(object sender, DragEventArgs e)
|
|
{
|
|
DragInfo.slotDestination = this;
|
|
DragInfo.slotDestinationSlotNumber = getSlot(sender);
|
|
DragInfo.slotDestinationOffset = getPKXOffset(DragInfo.slotDestinationSlotNumber);
|
|
DragInfo.slotDestinationBoxNumber = DragInfo.DestinationParty ? -1 : CB_BoxSelect.SelectedIndex;
|
|
|
|
// Check for In-Dropped files (PKX,SAV,ETC)
|
|
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
|
if (Directory.Exists(files[0])) { loadBoxesFromDB(files[0]); return; }
|
|
if (DragInfo.SameSlot)
|
|
return;
|
|
if (SAV.getIsSlotLocked(DragInfo.slotDestinationBoxNumber, DragInfo.slotDestinationSlotNumber))
|
|
{
|
|
DragInfo.slotDestinationSlotNumber = -1; // Invalidate
|
|
WinFormsUtil.Alert("Unable to set to locked slot.");
|
|
return;
|
|
}
|
|
if (DragInfo.slotSourceOffset < 0) // file
|
|
{
|
|
if (files.Length <= 0)
|
|
return;
|
|
string file = files[0];
|
|
FileInfo fi = new FileInfo(file);
|
|
if (!PKX.getIsPKM(fi.Length) && !MysteryGift.getIsMysteryGift(fi.Length))
|
|
{ openQuick(file); return; }
|
|
|
|
byte[] data = File.ReadAllBytes(file);
|
|
MysteryGift mg = MysteryGift.getMysteryGift(data, fi.Extension);
|
|
PKM temp = mg?.convertToPKM(SAV) ?? PKMConverter.getPKMfromBytes(data, prefer: fi.Extension.Length > 0 ? (fi.Extension.Last() - 0x30)&7 : SAV.Generation);
|
|
string c;
|
|
|
|
PKM pk = PKMConverter.convertToFormat(temp, SAV.PKMType, out c);
|
|
if (pk == null)
|
|
{ WinFormsUtil.Error(c); Console.WriteLine(c); return; }
|
|
|
|
string[] errata = SAV.IsPKMCompatible(pk);
|
|
if (errata.Length > 0)
|
|
{
|
|
string concat = string.Join(Environment.NewLine, errata);
|
|
if (DialogResult.Yes != WinFormsUtil.Prompt(MessageBoxButtons.YesNo, concat, "Continue?"))
|
|
{ Console.WriteLine(c); Console.WriteLine(concat); return; }
|
|
}
|
|
|
|
DragInfo.setPKMtoDestination(SAV, pk);
|
|
getQuickFiller(SlotPictureBoxes[DragInfo.slotDestinationSlotNumber], pk);
|
|
getSlotColor(DragInfo.slotDestinationSlotNumber, Resources.slotSet);
|
|
Console.WriteLine(c);
|
|
}
|
|
else
|
|
{
|
|
PKM pkz = DragInfo.getPKMfromSource(SAV);
|
|
if (!DragInfo.SourceValid) { } // not overwritable, do nothing
|
|
else if (ModifierKeys == Keys.Alt && DragInfo.DestinationValid) // overwrite delete old slot
|
|
{
|
|
// Clear from slot
|
|
if (DragInfo.SameBox)
|
|
getQuickFiller(SlotPictureBoxes[DragInfo.slotSourceSlotNumber], SAV.BlankPKM); // picturebox
|
|
|
|
DragInfo.setPKMtoSource(SAV, SAV.BlankPKM);
|
|
}
|
|
else if (ModifierKeys != Keys.Control && DragInfo.DestinationValid)
|
|
{
|
|
// Load data from destination
|
|
PKM pk = ((PictureBox) sender).Image != null
|
|
? DragInfo.getPKMfromDestination(SAV)
|
|
: SAV.BlankPKM;
|
|
|
|
// Set destination pokemon image to source picture box
|
|
if (DragInfo.SameBox)
|
|
getQuickFiller(SlotPictureBoxes[DragInfo.slotSourceSlotNumber], pk);
|
|
|
|
// Set destination pokemon data to source slot
|
|
DragInfo.setPKMtoSource(SAV, pk);
|
|
}
|
|
else if (DragInfo.SameBox)
|
|
getQuickFiller(SlotPictureBoxes[DragInfo.slotSourceSlotNumber], pkz);
|
|
|
|
// Copy from temp to destination slot.
|
|
DragInfo.setPKMtoDestination(SAV, pkz);
|
|
getQuickFiller(SlotPictureBoxes[DragInfo.slotDestinationSlotNumber], pkz);
|
|
|
|
e.Effect = DragDropEffects.Link;
|
|
Cursor = DefaultCursor;
|
|
}
|
|
if (DragInfo.SourceParty || DragInfo.DestinationParty)
|
|
setParty();
|
|
if (DragInfo.slotSource == null) // another instance or file
|
|
{
|
|
notifyBoxViewerRefresh();
|
|
DragInfo.Reset();
|
|
}
|
|
}
|
|
private void pbBoxSlot_DragEnter(object sender, DragEventArgs e)
|
|
{
|
|
if (e.AllowedEffect == (DragDropEffects.Copy | DragDropEffects.Link)) // external file
|
|
e.Effect = DragDropEffects.Copy;
|
|
else if (e.Data != null) // within
|
|
e.Effect = DragDropEffects.Move;
|
|
|
|
if (DragInfo.slotDragDropInProgress)
|
|
Cursor = (Cursor)DragInfo.Cursor;
|
|
}
|
|
private void pbBoxSlot_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
|
|
{
|
|
if (e.Action == DragAction.Cancel || e.Action == DragAction.Drop)
|
|
{
|
|
DragInfo.slotLeftMouseIsDown = false;
|
|
DragInfo.slotRightMouseIsDown = false;
|
|
DragInfo.slotDragDropInProgress = false;
|
|
}
|
|
}
|
|
|
|
public static class DragInfo
|
|
{
|
|
public static bool slotLeftMouseIsDown;
|
|
public static bool slotRightMouseIsDown;
|
|
public static bool slotDragDropInProgress;
|
|
|
|
public static byte[] slotPkmSource;
|
|
public static byte[] slotPkmDestination;
|
|
|
|
public static object slotSource;
|
|
public static int slotSourceOffset = -1;
|
|
public static int slotSourceSlotNumber = -1;
|
|
public static int slotSourceBoxNumber = -1;
|
|
|
|
public static object slotDestination;
|
|
public static int slotDestinationOffset = -1;
|
|
public static int slotDestinationSlotNumber = -1;
|
|
public static int slotDestinationBoxNumber = -1;
|
|
|
|
public static object Cursor;
|
|
public static string CurrentPath;
|
|
|
|
public static bool SameBox => slotSourceBoxNumber > -1 && slotSourceBoxNumber == slotDestinationBoxNumber;
|
|
public static bool SameSlot => slotSourceSlotNumber == slotDestinationSlotNumber && slotSourceBoxNumber == slotDestinationBoxNumber;
|
|
public static bool SourceValid => slotSourceSlotNumber > -1 && (slotSourceBoxNumber > -1 || SourceParty);
|
|
public static bool DestinationValid => slotDestinationSlotNumber > -1 && (slotDestinationBoxNumber > -1 || DestinationParty);
|
|
public static bool SourceParty => 30 <= slotSourceSlotNumber && slotSourceSlotNumber < 36;
|
|
public static bool DestinationParty => 30 <= slotDestinationSlotNumber && slotDestinationSlotNumber < 36;
|
|
|
|
// PKM Get Set
|
|
public static PKM getPKMfromSource(SaveFile SAV)
|
|
{
|
|
int o = slotSourceOffset;
|
|
return SourceParty ? SAV.getPartySlot(o) : SAV.getStoredSlot(o);
|
|
}
|
|
public static PKM getPKMfromDestination(SaveFile SAV)
|
|
{
|
|
int o = slotDestinationOffset;
|
|
return DestinationParty ? SAV.getPartySlot(o) : SAV.getStoredSlot(o);
|
|
}
|
|
public static void setPKMtoSource(SaveFile SAV, PKM pk)
|
|
{
|
|
int o = slotSourceOffset;
|
|
if (!SourceParty)
|
|
{ SAV.setStoredSlot(pk, o); return; }
|
|
|
|
if (pk.Species == 0) // Empty Slot
|
|
{ SAV.deletePartySlot(slotSourceSlotNumber-30); return; }
|
|
|
|
if (pk.Stat_HPMax == 0) // Without Stats (Box)
|
|
{
|
|
pk.setStats(pk.getStats(SAV.Personal.getFormeEntry(pk.Species, pk.AltForm)));
|
|
pk.Stat_Level = pk.CurrentLevel;
|
|
}
|
|
SAV.setPartySlot(pk, o);
|
|
}
|
|
public static void setPKMtoDestination(SaveFile SAV, PKM pk)
|
|
{
|
|
int o = slotDestinationOffset;
|
|
if (!DestinationParty)
|
|
{ SAV.setStoredSlot(pk, o); return; }
|
|
|
|
if (30 + SAV.PartyCount < slotDestinationSlotNumber)
|
|
{
|
|
o = SAV.getPartyOffset(SAV.PartyCount);
|
|
slotDestinationSlotNumber = 30 + SAV.PartyCount;
|
|
}
|
|
if (pk.Stat_HPMax == 0) // Without Stats (Box/File)
|
|
{
|
|
pk.setStats(pk.getStats(SAV.Personal.getFormeEntry(pk.Species, pk.AltForm)));
|
|
pk.Stat_Level = pk.CurrentLevel;
|
|
}
|
|
SAV.setPartySlot(pk, o);
|
|
}
|
|
|
|
public static void Reset()
|
|
{
|
|
slotLeftMouseIsDown = false;
|
|
slotRightMouseIsDown = false;
|
|
slotDragDropInProgress = false;
|
|
|
|
slotPkmSource = null;
|
|
slotSourceOffset = slotSourceSlotNumber = slotSourceBoxNumber = -1;
|
|
slotPkmDestination = null;
|
|
slotDestinationOffset = slotSourceBoxNumber = slotDestinationBoxNumber = -1;
|
|
|
|
Cursor = null;
|
|
CurrentPath = null;
|
|
|
|
slotSource = null;
|
|
slotDestination = null;
|
|
}
|
|
|
|
public static bool? WasDragParticipant(object form, int index)
|
|
{
|
|
if (slotDestinationBoxNumber != index && slotSourceBoxNumber != index)
|
|
return null; // form was not watching box
|
|
return slotSource == form || slotDestination == form; // form already updated?
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|