PKHeX/Misc/CodeGenerator.cs
Kurt 661052bcf9 Refactoring of Save File Usage
Probably breaks a thing or two... time to get testing after this new
commit.

Wrapping the stored 'savefile' into an object which handles its use
allows a clearer separation of function and easier maintenance or future
updates.

May eventually move all get/sets for each form to allow property
fetching from any window, all logic handled within the class.
2015-10-23 20:13:32 -07:00

338 lines
13 KiB
C#

using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace PKHeX
{
public partial class CodeGenerator : Form
{
byte[] codedata = new byte[232];
byte[] newdata = new byte[232];
byte[] tabdata;
public CodeGenerator(byte[] formdata)
{
tabdata = formdata;
InitializeComponent();
CenterToParent();
RTB_Code.Clear();
TB_Write.Clear();
CB_Box.Items.Clear();
for (int i = 1; i <= 31; i++)
CB_Box.Items.Add(i.ToString());
CB_Source.SelectedIndex = 0;
CB_Slot.SelectedIndex = 0;
CB_Box.SelectedIndex = 0;
}
private bool loaddata()
{
if (CB_Source.SelectedIndex == 0)
{
if (tabdata != null)
{
byte[] pkx = tabdata;
newdata = new byte[232];
Array.Copy(PKX.encryptArray(pkx), newdata, 232);
}
else
return false;
}
else if (CB_Source.SelectedIndex == 1)
{
newdata = new byte[0xE8];
Array.Copy(Main.SAV.Data,
Main.SAV.Box // Box Offset
+ CB_Box.SelectedIndex * (232 * 30) // Box Shift
+ CB_Slot.SelectedIndex * 232, // Slot Shift
newdata, 0, 0xE8);
if (!newdata.SequenceEqual(new byte[0xE8])) return true;
System.Media.SystemSounds.Exclamation.Play();
return false;
}
else if (CB_Source.SelectedIndex == 2)
{
// Wondercard
newdata = new byte[0x108];
// Wondercard #
int index = CB_Slot.SelectedIndex;
// copy from save, the chosen wondercard offset, to new data
Array.Copy(Main.SAV.Data, Main.SAV.WondercardData + index * 0x108, newdata, 0, 0x108);
byte[] zerodata = new byte[0x108];
if (!newdata.SequenceEqual(zerodata)) return true;
System.Media.SystemSounds.Exclamation.Play();
return false;
}
return true;
}
private void B_Add_Click(object sender, EventArgs e)
{
// Add the new code to the textbox.
if (!loaddata()) return;
uint writeoffset = Util.getHEXval(TB_Write);
for (int i = 0; i < newdata.Length / 4; i++)
{
RTB_Code.AppendText((writeoffset + i * 4 + 0x20000000).ToString("X8") + " ");
RTB_Code.AppendText(BitConverter.ToUInt32(newdata,i*4).ToString("X8") + Environment.NewLine);
}
// Mat's Code - Unfinished
//for (int i = 0; i < newdata.Length / (4); i++)
//{
// // Add Operator
// RTB_Code.AppendText("00000001 "); // 01 00 00 00
// RTB_Code.AppendText((writeoffset + i * 4).ToString("X8") + " ");
// RTB_Code.AppendText(BitConverter.ToUInt32(newdata,i*4).ToString("X8") + Environment.NewLine);
//}
}
private void B_Clear_Click(object sender, EventArgs e)
{
RTB_Code.Clear();
}
private void B_Load_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog {Filter = "Code File|*.bin"};
if (ofd.ShowDialog() != DialogResult.OK) return;
string path = ofd.FileName;
byte[] ncf = File.ReadAllBytes(path);
uint length = BitConverter.ToUInt32(ncf, 0);
if (ncf.Length != length + 4)
{
Util.Error("Not a valid code file.");
return;
}
if (RTB_Code.Text.Length > 0)
{
DialogResult ld = Util.Prompt(MessageBoxButtons.YesNo, "Replace current code?");
if (ld == DialogResult.Yes)
RTB_Code.Clear();
else if (ld != DialogResult.No)
return;
}
for (int i = 4; i <= ncf.Length-12; i+=12)
{
RTB_Code.AppendText(BitConverter.ToUInt32(ncf, i + 0 * 4).ToString("X8") + " ");
RTB_Code.AppendText(BitConverter.ToUInt32(ncf, i + 1 * 4).ToString("X8") + " ");
RTB_Code.AppendText(BitConverter.ToUInt32(ncf, i + 2 * 4).ToString("X8") + Environment.NewLine);
}
}
private void B_Save_Click(object sender, EventArgs e)
{
// Gotta read in the textbox.
if (RTB_Code.Text.Length < 1) return;
byte[] ncf = new byte[4 + (RTB_Code.Lines.Count()-1) * (3 * 4)];
Array.Copy(BitConverter.GetBytes(ncf.Length - 4), ncf, 4);
for (int i = 0; i < RTB_Code.Lines.Count()-1; i++)
{
string line = RTB_Code.Lines[i];
string[] rip = line.Split(new[] {" "}, StringSplitOptions.None);
// Write the 3 u32's to an array.
Array.Copy(BitConverter.GetBytes(UInt32.Parse(rip[0], NumberStyles.HexNumber)),0,ncf,4+i*12+0,4);
Array.Copy(BitConverter.GetBytes(UInt32.Parse(rip[1], NumberStyles.HexNumber)),0,ncf,4+i*12+4,4);
Array.Copy(BitConverter.GetBytes(UInt32.Parse(rip[2], NumberStyles.HexNumber)),0,ncf,4+i*12+8,4);
}
SaveFileDialog sfd = new SaveFileDialog {FileName = "code.bin", Filter = "Code File|*.bin"};
if (sfd.ShowDialog() != DialogResult.OK) return;
string path = sfd.FileName;
if (File.Exists(path))
{
// File already exists, save a .bak
byte[] backupfile = File.ReadAllBytes(path);
File.WriteAllBytes(path + ".bak", backupfile);
}
File.WriteAllBytes(path, ncf);
}
private void B_Copy_Click(object sender, EventArgs e)
{
if (RTB_Code.Text.Length > 0)
Clipboard.SetText(RTB_Code.Text);
else
{
B_Diff.PerformClick();
try
{
Clipboard.SetText(RTB_Code.Text);
Util.Alert(
"Code generated and copied to clipboard!",
"Next time click [Create Diff] first.");
}
catch
{
Util.Alert(
"No code created!",
"Click [Create Diff], then make sure that data appears in the Text Box below. If no code appears, then you didn't save your changes.",
"Be sure to Set the Pokemon you edited back into a Box/Party slot!");
}
}
}
private void B_Diff_Click(object sender, EventArgs e)
{
string result = "";
RTB_Code.Clear();
byte[] cybersav = Main.originalSAV;
byte[] newcyber = Main.SAV.Data;
int boxoffset = Main.SAV.Box;
int lines = 0; // 65400
for (int i = 0; i < newcyber.Length - 0x200; i += 4)
{
// Skip Party and Boxes
if (i == 0x14200) i += (260 * 6 + 4); // +4 to skip over party count
if (i == boxoffset) i += (232 * 30 * 31);
if (BitConverter.ToUInt32(cybersav, i) == BitConverter.ToUInt32(newcyber, i)) continue;
result += ((0x20000000 + i).ToString("X8") + " ");
result += (BitConverter.ToUInt32(newcyber, i).ToString("X8") + Environment.NewLine);
lines++;
if ((lines % 128 == 0) && CHK_Break.Checked)
{
result +=
(Environment.NewLine +
"--- Segment " + (lines / 128 + 1) + " ---" +
Environment.NewLine + Environment.NewLine);
}
if (lines > 10000) goto toomany;
}
// Loop Through Party
for (int i = 0x14200; i < 0x14200 + 260 * 6; i+= 260)
{
byte[] newdata = new byte[260]; Array.Copy(newcyber, i, newdata, 0, 260);
byte[] olddata = new byte[260]; Array.Copy(cybersav, i, olddata, 0, 260);
if (newdata.SequenceEqual(olddata)) continue;
for (int z = 0; z < newdata.Length; z += 4)
{
result += ((0x20000000 + i + z).ToString("X8") + " ");
result += (BitConverter.ToUInt32(newdata, z).ToString("X8") + Environment.NewLine);
lines++;
if ((lines % 128 == 0) && CHK_Break.Checked)
{
result +=
(Environment.NewLine +
"--- Segment " + (lines / 128 + 1) + " ---" +
Environment.NewLine + Environment.NewLine);
}
if (lines > 10000) goto toomany;
}
}
// Fix Party Count if Necessary
if (cybersav[0x14818] != newcyber[0x14818])
{
result += ((0x00000000 + 0x14818).ToString("X8") + " ");
result += (newcyber[0x14818].ToString("X8") + Environment.NewLine);
lines++;
if ((lines % 128 == 0) && CHK_Break.Checked)
{
result +=
(Environment.NewLine +
"--- Segment " + (lines / 128 + 1) + " ---" +
Environment.NewLine + Environment.NewLine);
}
if (lines > 10000) goto toomany;
}
// Loop Through Boxes
for (int i = boxoffset; i < boxoffset + (232 * 30 * 31); i += 232)
{
byte[] newdata = new byte[232]; Array.Copy(newcyber, i, newdata, 0, 232);
byte[] olddata = new byte[232]; Array.Copy(cybersav, i, olddata, 0, 232);
if (newdata.SequenceEqual(olddata)) continue;
for (int z = 0; z < newdata.Length; z += 4)
{
result += ((0x20000000 + i + z).ToString("X8") + " ");
result += (BitConverter.ToUInt32(newdata, z).ToString("X8") + Environment.NewLine);
lines++;
if ((lines % 128 == 0) && CHK_Break.Checked)
{
result +=
(Environment.NewLine +
"--- Segment " + (lines / 128 + 1) + " ---" +
Environment.NewLine + Environment.NewLine);
}
if (lines > 10000) goto toomany;
}
}
if ((lines / 128 > 0) && CHK_Break.Checked)
{
Util.Alert(String.Format("{0} Code Segments.",
(1 + (lines / 128))),
String.Format("{0} Lines.", lines));
}
RTB_Code.Text = result;
return;
toomany:
{
Util.Alert("Too many differences detected.",
"Export your save instead.");
}
}
// Import
public byte[] returnArray { get; set; }
private void B_Paste_Click(object sender, EventArgs e)
{
RTB_Code.Text = Clipboard.GetText();
}
private void B_Import_Click(object sender, EventArgs e)
{
// Gotta read in the textbox.
if (RTB_Code.Text.Length < 1) return;
byte[] data = new byte[0];
// Get Actual Lines
for (int i = 0; i < RTB_Code.Lines.Count(); i++)
{
if (RTB_Code.Lines[i].Length <= 0) continue;
if (RTB_Code.Lines[i].Length <= 2 * 8 && RTB_Code.Lines[i].Length > 2 * 8 + 2)
{ Util.Error("Invalid code pasted (Type)"); return; }
try
{
// Grab Line Data
string line = RTB_Code.Lines[i];
string[] rip = line.Split(new[] { " " }, StringSplitOptions.None);
Array.Resize(ref data, data.Length + 4);
Array.Copy(BitConverter.GetBytes(UInt32.Parse(rip[1], NumberStyles.HexNumber)), 0, data, data.Length - 4, 4);
}
catch (Exception x)
{ Util.Error("Invalid code pasted (Content):", x.ToString()); return; }
}
// Go over the data
if ((data.Length == 232 - 4) || (data.Length == 260 - 4))
{
Array.Resize(ref data, data.Length + 4);
Array.Copy(data, 0, data, 4, data.Length);
data[0] = data[1] = data[2] = data[3] = 0;
}
if ((data.Length == 232) || (data.Length == 260))
{ returnArray = data; Close(); }
else { Util.Error("Invalid code pasted (Length)"); }
}
}
}