mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-24 04:53:08 +00:00
4613 lines
195 KiB
C#
4613 lines
195 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.WinForms.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 (!PathUtilWindows.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 static string TemplatePath => Path.Combine(WorkingDirectory, "template");
|
|
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 (!PathUtilWindows.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)
|
|
{
|
|
Settings.Default.Unicode = unicode = Menu_Unicode.Checked;
|
|
updateUnicode();
|
|
}
|
|
private void mainMenuModifyDex(object sender, EventArgs e)
|
|
{
|
|
Settings.Default.SetUpdateDex = SaveFile.SetUpdateDex = Menu_ModifyDex.Checked;
|
|
}
|
|
private void mainMenuModifyUnset(object sender, EventArgs e)
|
|
{
|
|
Settings.Default.ModifyUnset = Menu_ModifyUnset.Checked;
|
|
}
|
|
private void mainMenuModifyPKM(object sender, EventArgs e)
|
|
{
|
|
Settings.Default.SetUpdatePKM = SaveFile.SetUpdatePKM = Menu_ModifyPKM.Checked;
|
|
}
|
|
private void mainMenuFlagIllegal(object sender, EventArgs e)
|
|
{
|
|
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(PathUtilWindows.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(PathUtilWindows.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()
|
|
{
|
|
Legal.RefreshMGDB(MGDatabasePath);
|
|
}
|
|
|
|
// 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)
|
|
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), Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName.Substring(0, 2)));
|
|
|
|
// 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 static PKM loadTemplate()
|
|
{
|
|
if (!Directory.Exists(TemplatePath))
|
|
return null;
|
|
|
|
var blank = SAV.BlankPKM;
|
|
string path = Path.Combine(TemplatePath, new DirectoryInfo(TemplatePath).Name + "." + blank.Extension);
|
|
|
|
if (!File.Exists(path) || !PKX.getIsPKM(new FileInfo(path).Length))
|
|
return null;
|
|
|
|
var pk = PKMConverter.getPKMfromBytes(File.ReadAllBytes(path), prefer: blank.Format);
|
|
return PKMConverter.convertToFormat(pk, SAV.BlankPKM.GetType(), out path); // no sneaky plz; reuse string
|
|
}
|
|
private void TemplateFields()
|
|
{
|
|
var template = loadTemplate();
|
|
if (template != null)
|
|
{ populateFields(template); return; }
|
|
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()
|
|
{
|
|
double getOpacity(bool 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 4:
|
|
case 3: evoVal = pkm.EncryptionConstant & 0xFFFF; 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 { 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 || x is IOException)
|
|
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 (!PathUtilWindows.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
|
|
}
|
|
}
|