mirror of
https://github.com/AdAstra-LD/DS-Pokemon-Rom-Editor.git
synced 2026-05-09 21:50:57 -05:00
991 lines
52 KiB
C#
991 lines
52 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Resources;
|
|
using System.Windows.Forms;
|
|
using System.Linq;
|
|
using DSPRE.ROMFiles;
|
|
using System.Collections.Generic;
|
|
using DSPRE.Resources.ROMToolboxDB;
|
|
using DSPRE.Resources;
|
|
using static DSPRE.RomInfo;
|
|
using System.Threading.Tasks;
|
|
using static DSPRE.Resources.ROMToolboxDB.ToolboxDB;
|
|
using static NSMBe4.ROM;
|
|
|
|
namespace DSPRE {
|
|
public partial class PatchToolboxDialog : Form {
|
|
public static uint expandedARMfileID = ToolboxDB.syntheticOverlayFileNumbersDB[RomInfo.gameFamily];
|
|
|
|
public static bool flag_standardizedItems { get; private set; } = false;
|
|
public static bool flag_arm9Expanded { get; private set; } = false;
|
|
public static bool flag_BDHCamPatchApplied { get; private set; } = false;
|
|
public static bool flag_DynamicHeadersPatchApplied { get; private set; } = false;
|
|
public static bool flag_MatrixExpansionApplied { get; private set; } = false;
|
|
|
|
public static bool flag_MainComboTableRepointed { get; set; } = false;
|
|
public static bool flag_TrainerClassBattleTableRepointed { get; set; } = false;
|
|
public static bool flag_PokemonBattleTableRepointed { get; set; } = false;
|
|
public static bool flag_TrainerNamesExpanded { get; set; } = false;
|
|
|
|
public static bool overlay1MustBeRestoredFromBackup { get; private set; } = true;
|
|
|
|
public static readonly int expandedTrainerNameLength = 12;
|
|
|
|
#region Constructor
|
|
public PatchToolboxDialog() {
|
|
InitializeComponent();
|
|
|
|
CheckStandardizedItems();
|
|
|
|
if (RomInfo.gameLanguage == gLangEnum.English || RomInfo.gameLanguage == gLangEnum.Spanish) {
|
|
CheckARM9ExpansionApplied();
|
|
} else {
|
|
DisableARM9patch("Unsupported\nlanguage");
|
|
DisableBDHCamPatch("Unsupported\nlanguage");
|
|
DisableScrcmdRepointPatch("Unsupported\nlanguage");
|
|
}
|
|
|
|
CheckExpandedTrainerNamesPatchApplied();
|
|
|
|
|
|
switch (RomInfo.gameFamily) {
|
|
case gFamEnum.DP:
|
|
DisableOverlay1patch("Unsupported");
|
|
DisableDynamicHeadersPatch("Unsupported");
|
|
DisableMatrixExpansionPatch("Unsupported");
|
|
DisableScrcmdRepointPatch("Unsupported");
|
|
DisableKillTextureAnimationsPatch("Unsupported");
|
|
break;
|
|
case gFamEnum.Plat:
|
|
DisableOverlay1patch("Unsupported");
|
|
DisableMatrixExpansionPatch("Unsupported");
|
|
DisableScrcmdRepointPatch("Unsupported");
|
|
DisableKillTextureAnimationsPatch("Unsupported");
|
|
|
|
if (RomInfo.gameLanguage == gLangEnum.English || RomInfo.gameLanguage == gLangEnum.Spanish) {
|
|
CheckBDHCamPatchApplied();
|
|
}
|
|
CheckDynamicHeadersPatchApplied();
|
|
break;
|
|
case gFamEnum.HGSS:
|
|
if (!OverlayUtils.OverlayTable.IsDefaultCompressed(1)) {
|
|
DisableOverlay1patch("Already applied");
|
|
overlay1CB.Visible = true;
|
|
}
|
|
|
|
if (RomInfo.gameLanguage == gLangEnum.English || RomInfo.gameLanguage == gLangEnum.Spanish) {
|
|
CheckBDHCamPatchApplied();
|
|
CheckMatrixExpansionApplied();
|
|
CheckScrcmdRepointPatchApplied();
|
|
} else {
|
|
DisableMatrixExpansionPatch("Unsupported\nlanguage");
|
|
DisableScrcmdRepointPatch("Unsupported\nlanguage");
|
|
}
|
|
|
|
CheckDynamicHeadersPatchApplied();
|
|
break;
|
|
}
|
|
}
|
|
|
|
#region Patch Disable
|
|
private void DisableOverlay1patch(string reason) {
|
|
overlay1uncomprButton.Enabled = false;
|
|
overlay1uncompressedLBL.Enabled = false;
|
|
overlay1patchtextLBL.Enabled = false;
|
|
overlay1uncomprButton.Text = reason;
|
|
}
|
|
private void DisableBDHCamPatch(string reason) {
|
|
BDHCamPatchButton.Enabled = false;
|
|
BDHCamPatchLBL.Enabled = false;
|
|
BDHCamPatchTextLBL.Enabled = false;
|
|
BDHCamARM9requiredLBL.Enabled = false;
|
|
BDHCamPatchButton.Text = reason;
|
|
}
|
|
private void DisableARM9patch(string reason) {
|
|
applyARM9ExpansionButton.Enabled = false;
|
|
arm9expansionTextLBL.Enabled = false;
|
|
arm9expansionLBL.Enabled = false;
|
|
applyARM9ExpansionButton.Text = reason;
|
|
}
|
|
private void DisableDynamicHeadersPatch(string reason) {
|
|
applyDynamicHeadersButton.Enabled = false;
|
|
dynamicHeadersTextLBL.Enabled = false;
|
|
dynamicHeadersLBL.Enabled = false;
|
|
applyDynamicHeadersButton.Text = reason;
|
|
}
|
|
private void DisableMatrixExpansionPatch(string reason) {
|
|
expandMatrixButton.Enabled = false;
|
|
matrixExpansionLBL.Enabled = false;
|
|
matrixExpansionTextLBL.Enabled = false;
|
|
expandMatrixButton.Text = reason;
|
|
}
|
|
private void DisableStandardizeItemsPatch(string reason) {
|
|
applyItemStandardizeButton.Enabled = false;
|
|
standardizePatchLBL.Enabled = false;
|
|
standardizePatchTextLBL.Enabled = false;
|
|
applyItemStandardizeButton.Text = reason;
|
|
}
|
|
private void DisableScrcmdRepointPatch(string reason) {
|
|
repointScrcmdButton.Enabled = false;
|
|
repointScrcmdLBL.Enabled = false;
|
|
repointScrcmdTextLBL.Enabled = false;
|
|
scrcmdARM9requiredLBL.Enabled = false;
|
|
repointScrcmdButton.Text = reason;
|
|
}
|
|
private void DisableKillTextureAnimationsPatch(string reason) {
|
|
disableTextureAnimationsButton.Enabled = false;
|
|
disableTextureAnimationsLBL.Enabled = false;
|
|
disableTextureAnimationsTextLBL.Enabled = false;
|
|
disableTextureAnimationsButton.Text = reason;
|
|
}
|
|
private void DisableTrainerNameExpansionPatch(string reason) {
|
|
expandTrainerNamesButton.Enabled = false;
|
|
expandTrainerNamesLBL.Enabled = false;
|
|
expandTrainerNamesTextLBL.Enabled = false;
|
|
expandTrainerNamesButton.Text = reason;
|
|
}
|
|
#endregion
|
|
#endregion
|
|
|
|
#region Patch
|
|
private static bool CheckFilesArm9ExpansionApplied() {
|
|
ARM9PatchData data = new ARM9PatchData();
|
|
|
|
byte[] branchCode = DSUtils.HexStringToByteArray(data.branchString);
|
|
byte[] branchCodeRead = ARM9.ReadBytes(data.branchOffset, data.branchString.Length / 3 + 1); //Read branchCode
|
|
if (branchCodeRead.Length != branchCode.Length || !branchCodeRead.SequenceEqual(branchCode))
|
|
return false;
|
|
|
|
byte[] initCode = DSUtils.HexStringToByteArray(data.initString);
|
|
byte[] initCodeRead = ARM9.ReadBytes(data.initOffset, data.initString.Length / 3 + 1); //Read initCode
|
|
if (initCodeRead.Length != initCode.Length || !initCodeRead.SequenceEqual(initCode))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
public static bool CheckFilesBDHCamPatchApplied() {
|
|
BDHCAMPatchData data = new BDHCAMPatchData();
|
|
|
|
byte[] branchCode = DSUtils.HexStringToByteArray(data.branchString);
|
|
byte[] branchCodeRead = ARM9.ReadBytes(data.branchOffset, branchCode.Length);
|
|
|
|
if (branchCode.Length != branchCodeRead.Length || !branchCode.SequenceEqual(branchCodeRead)) {
|
|
return false;
|
|
}
|
|
|
|
string overlayFilePath = OverlayUtils.GetPath(data.overlayNumber);
|
|
OverlayUtils.Decompress(data.overlayNumber);
|
|
|
|
byte[] overlayCode1 = DSUtils.HexStringToByteArray(data.overlayString1);
|
|
byte[] overlayCode1Read = DSUtils.ReadFromFile(overlayFilePath, data.overlayOffset1, overlayCode1.Length);
|
|
if (overlayCode1.Length != overlayCode1Read.Length || !overlayCode1.SequenceEqual(overlayCode1Read))
|
|
return false;
|
|
|
|
|
|
byte[] overlayCode2 = DSUtils.HexStringToByteArray(data.overlayString2);
|
|
byte[] overlayCode2Read = DSUtils.ReadFromFile(overlayFilePath, data.overlayOffset2, overlayCode2.Length); //Write new overlayCode1
|
|
if (overlayCode2.Length != overlayCode2Read.Length || !overlayCode2.SequenceEqual(overlayCode2Read))
|
|
return false; //0 means BDHCAM patch has not been applied
|
|
|
|
String fullFilePath = RomInfo.gameDirs[DirNames.synthOverlay].unpackedDir + '\\' + PatchToolboxDialog.expandedARMfileID.ToString("D4");
|
|
byte[] subroutineRead = DSUtils.ReadFromFile(fullFilePath, BDHCAMPatchData.BDHCamSubroutineOffset, data.subroutine.Length); //Write new overlayCode1
|
|
if (data.subroutine.Length != subroutineRead.Length || !data.subroutine.SequenceEqual(subroutineRead))
|
|
return false; //0 means BDHCAM patch has not been applied
|
|
|
|
return true;
|
|
}
|
|
public static bool CheckFilesMatrixExpansionApplied() {
|
|
foreach (KeyValuePair<uint[], string> kv in ToolboxDB.matrixExpansionDB) {
|
|
foreach (uint offset in kv.Key) {
|
|
int languageOffset = 0;
|
|
if (RomInfo.romID == "IPKE" || RomInfo.romID == "IPGE" || RomInfo.romID == "IPGS") {
|
|
languageOffset = +8;
|
|
}
|
|
|
|
byte[] read = ARM9.ReadBytes((uint)(offset - ARM9.address + languageOffset), kv.Value.Length / 3 + 1);
|
|
byte[] code = DSUtils.HexStringToByteArray(kv.Value);
|
|
if (read.Length != code.Length || !read.SequenceEqual(code))
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
public static bool CheckScriptsStandardizedItemNumbers() {
|
|
ScriptFile itemScript = new ScriptFile(RomInfo.itemScriptFileNumber);
|
|
if (itemScript.allScripts.Count - 1 < new TextArchive(RomInfo.itemNamesTextNumber).messages.Count) {
|
|
return false;
|
|
}
|
|
|
|
for (ushort i = 0; i < itemScript.allScripts.Count - 1; i++) {
|
|
if (BitConverter.ToUInt16(itemScript.allScripts[i].commands[0].cmdParams[1], 0) != i || BitConverter.ToUInt16(itemScript.allScripts[i].commands[1].cmdParams[1], 0) != 1) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
public bool CheckStandardizedItems() {
|
|
DSUtils.TryUnpackNarcs(new List<RomInfo.DirNames> { RomInfo.DirNames.scripts });
|
|
|
|
if (!PatchToolboxDialog.flag_standardizedItems) {
|
|
if (!PatchToolboxDialog.CheckScriptsStandardizedItemNumbers()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
itemNumbersCB.Visible = true;
|
|
PatchToolboxDialog.flag_standardizedItems = true;
|
|
|
|
DisableStandardizeItemsPatch("Already applied");
|
|
return true;
|
|
}
|
|
public bool CheckMatrixExpansionApplied() {
|
|
if (!PatchToolboxDialog.flag_MatrixExpansionApplied) {
|
|
if (!PatchToolboxDialog.CheckFilesMatrixExpansionApplied()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
DisableMatrixExpansionPatch("Already applied");
|
|
PatchToolboxDialog.flag_MatrixExpansionApplied = true;
|
|
expandedMatrixCB.Visible = true;
|
|
return true;
|
|
}
|
|
public string backupSuffix = ".backup";
|
|
private bool CheckARM9ExpansionApplied() {
|
|
if (!PatchToolboxDialog.flag_arm9Expanded) {
|
|
if (!PatchToolboxDialog.CheckFilesArm9ExpansionApplied()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
PatchToolboxDialog.flag_arm9Expanded = true;
|
|
arm9patchCB.Visible = true;
|
|
DisableARM9patch("Already applied");
|
|
|
|
switch (RomInfo.gameFamily) {
|
|
case gFamEnum.Plat:
|
|
case gFamEnum.HGSS:
|
|
BDHCamARM9requiredLBL.Visible = false;
|
|
BDHCamPatchButton.Enabled = true;
|
|
BDHCamPatchLBL.Enabled = true;
|
|
BDHCamPatchTextLBL.Enabled = true;
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
public bool CheckDynamicHeadersPatchApplied() {
|
|
if (!flag_DynamicHeadersPatchApplied) {
|
|
if (!PatchToolboxDialog.CheckFilesDynamicHeadersPatchApplied()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
PatchToolboxDialog.flag_DynamicHeadersPatchApplied = true;
|
|
dynamicHeadersPatchCB.Visible = true;
|
|
|
|
DisableDynamicHeadersPatch("Already applied");
|
|
return true;
|
|
}
|
|
|
|
public static bool CheckFilesDynamicHeadersPatchApplied() {
|
|
DynamicHeadersPatchData data = new DynamicHeadersPatchData();
|
|
ushort initValue = BitConverter.ToUInt16(ARM9.ReadBytes(data.initOffset, 0x2), 0);
|
|
return initValue == 0xB500;
|
|
}
|
|
|
|
public bool CheckBDHCamPatchApplied() {
|
|
if (!CheckARM9ExpansionApplied()) {
|
|
BDHCamARM9requiredLBL.Visible = true;
|
|
DisableBDHCamPatch("ARM9 not expanded!");
|
|
return false;
|
|
}
|
|
|
|
if (!PatchToolboxDialog.flag_BDHCamPatchApplied) {
|
|
if (!PatchToolboxDialog.CheckFilesBDHCamPatchApplied()) {
|
|
return false;
|
|
}
|
|
}
|
|
PatchToolboxDialog.flag_BDHCamPatchApplied = true;
|
|
BDHCamCB.Visible = true;
|
|
|
|
DisableBDHCamPatch("Already applied");
|
|
return true;
|
|
}
|
|
public void CheckScrcmdRepointPatchApplied() {
|
|
//throw new NotImplementedException();
|
|
}
|
|
|
|
public void CheckExpandedTrainerNamesPatchApplied() {
|
|
if (flag_TrainerNamesExpanded) {
|
|
DisableTrainerNameExpansionPatch("Already\nApplied");
|
|
} else {
|
|
if (RomInfo.trainerNameLenOffset < 0 ) {
|
|
DisableTrainerNameExpansionPatch("Unsupported");
|
|
} else {
|
|
int v = RomInfo.SetTrainerNameMaxLen();
|
|
|
|
if (v > TrainerFile.defaultNameLen+1) {
|
|
DisableTrainerNameExpansionPatch("Already\nApplied");
|
|
PatchToolboxDialog.flag_TrainerNamesExpanded = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Button Actions
|
|
private void SentenceCasePatchButton_Click(object sender, EventArgs e) {
|
|
DialogResult d;
|
|
d = MessageBox.Show("Confirming this process will apply the following changes:\n\n" +
|
|
"- Every Pokémon name will be converted to Sentence Case." + "\n\n" +
|
|
"Do you wish to continue?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d == DialogResult.Yes) {
|
|
Parallel.ForEach(RomInfo.pokemonNamesTextNumbers, ID => {
|
|
TextArchive pokeName = new TextArchive(ID);
|
|
Parallel.For(1, pokeName.messages.Count, i => {
|
|
if (pokeName.messages[i].Length <= 1) {
|
|
i++;
|
|
}
|
|
|
|
pokeName.messages[i] = pokeName.messages[i].Replace(PokeDatabase.System.pokeNames[(ushort)i].ToUpper(), PokeDatabase.System.pokeNames[(ushort)i]);
|
|
});
|
|
pokeName.SaveToFileDefaultDir(ID, showSuccessMessage: false);
|
|
});
|
|
//sentenceCaseCB.Visible = true;
|
|
MessageBox.Show("Pokémon names have been converted to Sentence Case.", "Operation successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
} else {
|
|
MessageBox.Show("No changes have been made.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
private void BDHCAMPatchButton_Click(object sender, EventArgs e) {
|
|
BDHCAMPatchData data = new BDHCAMPatchData();
|
|
|
|
if (RomInfo.gameFamily == gFamEnum.HGSS) {
|
|
if (OverlayUtils.OverlayTable.IsDefaultCompressed(data.overlayNumber)) {
|
|
DialogResult d1 = MessageBox.Show("It is STRONGLY recommended to configure Overlay1 as uncompressed before proceeding.\n\n" +
|
|
"More details in the following dialog.\n\n" + "Do you want to know more?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d1 == DialogResult.Yes) {
|
|
overlay1uncomprButton_Click(null, null);
|
|
}
|
|
}
|
|
}
|
|
|
|
DialogResult d2;
|
|
d2 = MessageBox.Show("This process will apply the following changes:\n\n" +
|
|
"- Backup ARM9 file (arm9.bin" + backupSuffix + " will be created)." + "\n\n" +
|
|
"- Backup Overlay" + data.overlayNumber + " file (overlay" + data.overlayNumber + ".bin" + backupSuffix + " will be created)." + "\n\n" +
|
|
"- Replace " + (data.branchString.Length / 3 + 1) + " bytes of data at arm9 offset 0x" + data.branchOffset.ToString("X") + " with " + '\n' + data.branchString + "\n\n" +
|
|
"- Replace " + (data.overlayString1.Length / 3 + 1) + " bytes of data at overlay" + data.overlayNumber + " offset 0x" + data.overlayOffset1.ToString("X") + " with " + '\n' + data.overlayString1 + "\n\n" +
|
|
"- Replace " + (data.overlayString2.Length / 3 + 1) + " bytes of data at overlay" + data.overlayNumber + " offset 0x" + data.overlayOffset2.ToString("X") + " with " + '\n' + data.overlayString2 + "\n\n" +
|
|
"- Modify file #" + expandedARMfileID + " inside " + '\n' + RomInfo.gameDirs[DirNames.synthOverlay].unpackedDir + '\n' + "to insert the BDHCAM routine (any data between 0x" + BDHCAMPatchData.BDHCamSubroutineOffset.ToString("X") + " and 0x" + (BDHCAMPatchData.BDHCamSubroutineOffset + data.subroutine.Length).ToString("X") + " will be overwritten)." + "\n\n" +
|
|
"Do you wish to continue?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d2 == DialogResult.Yes) {
|
|
File.Copy(RomInfo.arm9Path, RomInfo.arm9Path + backupSuffix, overwrite: true);
|
|
|
|
try {
|
|
ARM9.WriteBytes(DSUtils.HexStringToByteArray(data.branchString), data.branchOffset); //Write new branchOffset
|
|
|
|
/* Write to overlayfile */
|
|
string overlayFilePath = OverlayUtils.GetPath(data.overlayNumber);
|
|
if (OverlayUtils.IsCompressed(data.overlayNumber)) {
|
|
OverlayUtils.Decompress(data.overlayNumber);
|
|
}
|
|
|
|
DSUtils.WriteToFile(overlayFilePath, DSUtils.HexStringToByteArray(data.overlayString1), data.overlayOffset1); //Write new overlayCode1
|
|
DSUtils.WriteToFile(overlayFilePath, DSUtils.HexStringToByteArray(data.overlayString2), data.overlayOffset2); //Write new overlayCode2
|
|
overlay1MustBeRestoredFromBackup = false;
|
|
|
|
String fullFilePath = RomInfo.gameDirs[DirNames.synthOverlay].unpackedDir + '\\' + expandedARMfileID.ToString("D4");
|
|
|
|
/*Write Expanded ARM9 File*/
|
|
DSUtils.WriteToFile(fullFilePath, data.subroutine, BDHCAMPatchData.BDHCamSubroutineOffset);
|
|
} catch {
|
|
MessageBox.Show("Operation failed. It is strongly advised that you restore the arm9 and overlay from their respective backups.", "Something went wrong",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
return;
|
|
}
|
|
|
|
overlay1MustBeRestoredFromBackup = false;
|
|
DisableBDHCamPatch("Already applied");
|
|
PatchToolboxDialog.flag_BDHCamPatchApplied = true;
|
|
BDHCamCB.Visible = true;
|
|
|
|
MessageBox.Show("The BDHCAM patch has been applied.", "Operation successful.", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
} else {
|
|
MessageBox.Show("No changes have been made.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
private void overlay1uncomprButton_Click(object sender, EventArgs e) {
|
|
if (ConfigureOverlay1Uncompressed()) {
|
|
DisableOverlay1patch("Already applied");
|
|
overlay1CB.Visible = true;
|
|
}
|
|
}
|
|
|
|
public static bool ConfigureOverlay1Uncompressed() {
|
|
bool isCompressed = false;
|
|
string stringDecompressOverlay = "";
|
|
|
|
if (OverlayUtils.IsCompressed(1)) {
|
|
isCompressed = true;
|
|
stringDecompressOverlay = "- Overlay 1 will be decompressed.\n\n";
|
|
}
|
|
|
|
DialogResult d = MessageBox.Show("This process will apply the following changes:\n\n" +
|
|
stringDecompressOverlay +
|
|
"- Overlay 1 will be configured as \"uncompressed\" in the overlay table.\n\n" +
|
|
"Do you wish to continue?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d == DialogResult.Yes) {
|
|
OverlayUtils.OverlayTable.SetDefaultCompressed(1, false);
|
|
if (isCompressed) {
|
|
OverlayUtils.Decompress(1);
|
|
}
|
|
|
|
MessageBox.Show("Overlay1 is now configured as uncompressed.", "Operation successful", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
return true;
|
|
} else {
|
|
MessageBox.Show("No changes have been made.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private void ApplyItemStandardizeButton_Click(object sender, EventArgs e) {
|
|
DialogResult d = MessageBox.Show("This process will apply the following changes:\n\n" +
|
|
"- Item scripts will be rearranged to follow the natural, ascending index order.\n\n" +
|
|
"- Any unsaved change to the current Event File will be discarded.\n\n",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d == DialogResult.Yes) {
|
|
|
|
DSUtils.TryUnpackNarcs(new List<RomInfo.DirNames> { RomInfo.DirNames.scripts });
|
|
DSUtils.TryUnpackNarcs(new List<RomInfo.DirNames> { RomInfo.DirNames.eventFiles });
|
|
|
|
if (PatchToolboxDialog.flag_standardizedItems) {
|
|
AlreadyApplied();
|
|
} else {
|
|
|
|
// Load item script file data
|
|
ScriptFile itemScriptFile = new ScriptFile(RomInfo.itemScriptFileNumber);
|
|
|
|
// Create map for: script no. -> vanilla item
|
|
int[] vanillaItemsArray = new int[itemScriptFile.allScripts.Count - 1];
|
|
|
|
for (int i = 0; i < itemScriptFile.allScripts.Count - 1; i++) {
|
|
vanillaItemsArray[i] = BitConverter.ToInt16(itemScriptFile.allScripts[i].commands[0].cmdParams[1], 0);
|
|
};
|
|
|
|
// Parse all event files and fix instances of ground items according to the new order
|
|
int cnt = RomInfo.GetEventFileCount();
|
|
(int min, int max) itemScriptRange = (7000, 8000);
|
|
|
|
for (int i = 0; i < cnt; i++) {
|
|
bool dirty = false;
|
|
|
|
EventFile eventFile = new EventFile(i);
|
|
|
|
for (int j = 0; j < eventFile.overworlds.Count; j++) {
|
|
// If ow is marked as an item, or in the rare case it is not but script no. falls within item script range:
|
|
bool isItem = eventFile.overworlds[j].type == (ushort)Overworld.OwType.ITEM
|
|
|| (eventFile.overworlds[j].scriptNumber >= itemScriptRange.min
|
|
&& eventFile.overworlds[j].scriptNumber <= itemScriptRange.max);
|
|
|
|
if (isItem) {
|
|
int itemScriptID = eventFile.overworlds[j].scriptNumber - (itemScriptRange.min - 1);
|
|
eventFile.overworlds[j].scriptNumber = (ushort)(itemScriptRange.min + vanillaItemsArray[itemScriptID - 1]);
|
|
dirty = true;
|
|
}
|
|
}
|
|
|
|
// Save event file
|
|
if (dirty) {
|
|
eventFile.SaveToFileDefaultDir(i, showSuccessMessage: false);
|
|
}
|
|
};
|
|
|
|
//Distortion world - turnback cave Griseous Orb fix
|
|
if (gameFamily.Equals(gFamEnum.Plat)) {
|
|
string ow9path = OverlayUtils.GetPath(9);
|
|
int ow9offs = 0x8E20 + 10;
|
|
|
|
int itemScriptID;
|
|
|
|
using (DSUtils.EasyReader ewr = new DSUtils.EasyReader(ow9path, ow9offs)) {
|
|
itemScriptID = ewr.ReadUInt16() - (itemScriptRange.min - 1);
|
|
}
|
|
|
|
using (DSUtils.EasyWriter ewr = new DSUtils.EasyWriter(ow9path, ow9offs)) {
|
|
ewr.Write((ushort)(itemScriptRange.min + vanillaItemsArray[itemScriptID - 1]));
|
|
}
|
|
}
|
|
|
|
// Sort scripts in the Script File according to item indices
|
|
int itemCount = new TextArchive(RomInfo.itemNamesTextNumber).messages.Count;
|
|
CommandContainer executeGive = new CommandContainer((uint)itemCount + 1, itemScriptFile.allScripts[itemScriptFile.allScripts.Count - 1]);
|
|
|
|
itemScriptFile.allScripts.Clear();
|
|
|
|
for (ushort i = 0; i < itemCount; i++) {
|
|
|
|
List<ScriptCommand> cmdList = new List<ScriptCommand> {
|
|
new ScriptCommand("SetVar 0x8008 " + i),
|
|
new ScriptCommand("SetVar 0x8009 0x1"),
|
|
new ScriptCommand("Jump Function_#1")
|
|
};
|
|
|
|
itemScriptFile.allScripts.Add(new CommandContainer((ushort)(i + 1), ScriptFile.containerTypes.Script, commandList: cmdList));
|
|
}
|
|
|
|
itemScriptFile.allScripts.Add(executeGive);
|
|
itemScriptFile.allFunctions[0].usedScript = itemCount + 1;
|
|
|
|
itemScriptFile.SaveToFileDefaultDir(RomInfo.itemScriptFileNumber, showSuccessMessage: false);
|
|
MessageBox.Show("Operation successful.", "Process completed.", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
DisableStandardizeItemsPatch("Already applied");
|
|
|
|
itemNumbersCB.Visible = true;
|
|
PatchToolboxDialog.flag_standardizedItems = true;
|
|
}
|
|
} else {
|
|
MessageBox.Show("No changes have been made.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
private void ApplyARM9ExpansionButton_Click(object sender, EventArgs e) {
|
|
ARM9PatchData data = new ARM9PatchData();
|
|
|
|
DialogResult d = MessageBox.Show("Confirming this process will apply the following changes:\n\n" +
|
|
"- Backup ARM9 file (arm9.bin" + backupSuffix + " will be created)." + "\n\n" +
|
|
"- Replace " + (data.branchString.Length / 3 + 1) + " bytes of data at arm9 offset 0x" + data.branchOffset.ToString("X") + " with " + '\n' + data.branchString + "\n\n" +
|
|
"- Replace " + (data.initString.Length / 3 + 1) + " bytes of data at arm9 offset 0x" + data.initOffset.ToString("X") + " with " + '\n' + data.initString + "\n\n" +
|
|
"- Modify file #" + expandedARMfileID + " inside " + '\n' + RomInfo.gameDirs[DirNames.synthOverlay].unpackedDir + '\n' + " to accommodate for 88KB of data (no backup)." + "\n\n" +
|
|
"Do you wish to continue?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d == DialogResult.Yes) {
|
|
File.Copy(RomInfo.arm9Path, RomInfo.arm9Path + backupSuffix, overwrite: true);
|
|
|
|
try {
|
|
ARM9.WriteBytes(DSUtils.HexStringToByteArray(data.branchString), data.branchOffset); //Write new branchOffset
|
|
ARM9.WriteBytes(DSUtils.HexStringToByteArray(data.initString), data.initOffset); //Write new initOffset
|
|
|
|
string fullFilePath = RomInfo.gameDirs[DirNames.synthOverlay].unpackedDir + '\\' + expandedARMfileID.ToString("D4");
|
|
File.Delete(fullFilePath);
|
|
using (BinaryWriter f = new BinaryWriter(File.Create(fullFilePath))) {
|
|
for (int i = 0; i < 0x16000; i++)
|
|
f.Write((byte)0x00); // Write Expanded ARM9 File
|
|
}
|
|
|
|
DisableARM9patch("Already applied");
|
|
arm9patchCB.Visible = true;
|
|
PatchToolboxDialog.flag_arm9Expanded = true;
|
|
|
|
switch (RomInfo.gameFamily) {
|
|
case gFamEnum.Plat:
|
|
case gFamEnum.HGSS:
|
|
BDHCamPatchButton.Text = "Apply Patch";
|
|
BDHCamPatchButton.Enabled = true;
|
|
BDHCamPatchLBL.Enabled = true;
|
|
BDHCamPatchTextLBL.Enabled = true;
|
|
BDHCamARM9requiredLBL.Visible = false;
|
|
break;
|
|
}
|
|
|
|
MessageBox.Show("The ARM9's usable memory has been expanded.", "Operation successful.", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
} catch {
|
|
MessageBox.Show("Operation failed. It is strongly advised that you restore the arm9 backup (arm9.bin" + backupSuffix + ").", "Something went wrong",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
} else {
|
|
MessageBox.Show("No changes have been made.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
private void expandMatrixButton_Click(object sender, EventArgs e) {
|
|
string listOfChanges = "";
|
|
int languageOffset = 0;
|
|
|
|
if (RomInfo.romID == "IPKE" || RomInfo.romID == "IPGE" || RomInfo.romID == "IPGS") {
|
|
languageOffset = +8;
|
|
}
|
|
|
|
foreach (KeyValuePair<uint[], string> kv in ToolboxDB.matrixExpansionDB) {
|
|
listOfChanges += " - Replace " + (kv.Value.Length / 3 + 1) + " bytes of data at arm9 offset";
|
|
if (kv.Key.Length > 1)
|
|
listOfChanges += "s";
|
|
|
|
for (int i = 0; i < kv.Key.Length; i++) {
|
|
listOfChanges += " 0x" + (kv.Key[i] - ARM9.address + languageOffset).ToString("X");
|
|
|
|
if (i < kv.Key.Length - 1)
|
|
listOfChanges += ",";
|
|
}
|
|
listOfChanges += " with " + '\n' + kv.Value + "\n\n";
|
|
}
|
|
|
|
DialogResult d;
|
|
d = MessageBox.Show("Confirming this process will apply the following changes:\n\n" +
|
|
listOfChanges +
|
|
"Do you wish to continue?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d == DialogResult.Yes) {
|
|
try {
|
|
foreach (KeyValuePair<uint[], string> kv in ToolboxDB.matrixExpansionDB) {
|
|
foreach (uint offset in kv.Key) {
|
|
ARM9.WriteBytes(DSUtils.HexStringToByteArray(kv.Value), (uint)(offset - ARM9.address + languageOffset));
|
|
}
|
|
}
|
|
} catch {
|
|
MessageBox.Show("Operation failed. It is strongly advised that you restore the arm9 backup (arm9.bin" + backupSuffix + ").", "Something went wrong",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
DisableMatrixExpansionPatch("Already applied");
|
|
expandedMatrixCB.Visible = true;
|
|
PatchToolboxDialog.flag_MatrixExpansionApplied = true;
|
|
MessageBox.Show("Matrix 0 can now be freely expanded up to twice its size.", "Operation successful.", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
} else {
|
|
MessageBox.Show("No changes have been made.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
private void dynamicHeadersButton_Click(object sender, EventArgs e) {
|
|
DynamicHeadersPatchData data = new DynamicHeadersPatchData();
|
|
var headersDir = RomInfo.gameDirs[DirNames.dynamicHeaders];
|
|
|
|
bool specialCase = RomInfo.gameFamily == gFamEnum.HGSS && RomInfo.gameLanguage != gLangEnum.Japanese && RomInfo.gameLanguage != gLangEnum.Spanish;
|
|
string specialCaseChanges = "";
|
|
|
|
if (specialCase) {
|
|
specialCaseChanges = "- Replace " + (data.specialCaseData1.Length / 3 + 1) + " bytes of data at arm9 offset 0x" + (data.specialCaseOffset1 + data.pointerDiff).ToString("X") + " with " + '\n' + data.specialCaseData1 + "\n\n" +
|
|
"- Replace " + (data.specialCaseData2.Length / 3 + 1) + " bytes of data at arm9 offset 0x" + (data.specialCaseOffset2 + data.pointerDiff).ToString("X") + " with " + '\n' + data.specialCaseData2 + "\n\n" +
|
|
"- Replace " + (data.specialCaseData3.Length / 3 + 1) + " bytes of data at arm9 offset 0x" + (data.specialCaseOffset3 + data.pointerDiff).ToString("X") + " with " + '\n' + data.specialCaseData3 + "\n\n";
|
|
}
|
|
|
|
DialogResult d;
|
|
d = MessageBox.Show("Confirming this process will apply the following changes:\n\n" +
|
|
"- Backup ARM9 file (arm9.bin" + backupSuffix + " will be created)." + "\n\n" +
|
|
"- NARC file at " + headersDir.packedDir + " will become the new header container." + "\n\n" +
|
|
"- The default ARM9 header table will be split into multiple files (one per header), each one saved into NARC" + headersDir.packedDir + " upon saving the ROM." + "\n\n" +
|
|
"- Replace " + (data.initString.Length / 3 + 1) + " bytes of data at arm9 offset 0x" + data.initOffset.ToString("X") + " with " + '\n' + data.initString + "\n\n" +
|
|
"- Neutralize instances of (HeaderID * 0x18) so the base offset which the data is read from is always 0x0." + "\n\n" +
|
|
"- Change pointers to header fields, from(ARM9_HEADER_TABLE_OFFSET + n) to simply(0 + n)" + "\n\n" +
|
|
specialCaseChanges +
|
|
"Do you wish to continue?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d == DialogResult.Yes) {
|
|
File.Copy(RomInfo.arm9Path, RomInfo.arm9Path + backupSuffix, overwrite: true);
|
|
|
|
try {
|
|
/* Write main routine (HG USA):
|
|
|
|
00 B5 push (lr)
|
|
01 1C mov r1, r0
|
|
32 20* mov r0, #0x32
|
|
00 22 mov r2, #0x0
|
|
CC F7 58 F9** bl 0x02007524 @Load_Memory
|
|
03 1C mov r3, r0
|
|
DF F7 49 FC** bl 0x0201AB0C @Free_Memory
|
|
00 BD pop, pc
|
|
|
|
*FOR PLATINUM (all languages):
|
|
94 20 mov r0, #0x94
|
|
|
|
**BRANCHES FOR OTHER VERSIONS/LANGUAGES:
|
|
|
|
HG ESP (IPKS):
|
|
CC F7 5C F9 bl 0x02007524 @Load_Memory
|
|
DF F7 4D FC bl 0x0201AB0C @Free_Memory
|
|
|
|
HG JAP (IPKJ) and SS JAP (IPGJ):
|
|
CC F7 08 FB bl 0x0200743C @Load_Memory
|
|
DF F7 C7 FC bl 0x0201A7C0 @Free_Memory
|
|
|
|
Plat USA (CPUE):
|
|
CC F7 48 FD bl 0x02006AC0 @Load_Memory
|
|
DE F7 C7 F8 bl 0x020181C4 @Free_Memory
|
|
|
|
Plat ESP (CPUS), ITA (CPUI), FRA (CPUF), GER (CPUD):
|
|
CC F7 00 FD bl 0x02006AD4 @Load_Memory
|
|
CC F7 74 FC bl 0x02018234 @Free_Memory
|
|
|
|
Plat JAP (CPUJ):
|
|
CC F7 0A FF bl 0x02006A00 @Load_Memory
|
|
DE F7 3D F9 bl 0x02017E6C @Free_Memory
|
|
*/
|
|
|
|
ARM9.WriteBytes(DSUtils.HexStringToByteArray(data.initString), data.initOffset);
|
|
|
|
/* - Neutralize instances of (HeaderID * 0x18) so the base offset which the data is read from is always 0x0:
|
|
|
|
Replace this:
|
|
18 21 mov r1, #0x18
|
|
41 43 mul r1, r0
|
|
|
|
with this:
|
|
19 00 lsl r1, r3, 0
|
|
C0 46 nop
|
|
|
|
- Change pointers to header fields, from (ARM9_HEADER_TABLE_OFFSET + n) to simply (0 + n)
|
|
|
|
* for ESP HG (IPKS): subtract 0x8 from every reference offset
|
|
* for JAP HG (IPKJ) and SS (IPGJ): subtract 0x448 from every reference offset
|
|
* for Plat ESP, ITA, FRA, GER, JAP: add 0xA4 to every reference offset
|
|
* for Plat JAP: subtract 0x444 from every reference offset
|
|
|
|
*/
|
|
|
|
foreach (Tuple<uint, uint> reference in DynamicHeadersPatchData.dynamicHeadersPointersDB[RomInfo.gameFamily]) {
|
|
ARM9.WriteBytes(DSUtils.HexStringToByteArray(data.REFERENCE_STRING), (uint)(reference.Item1 + data.pointerDiff));
|
|
uint pointerValue = BitConverter.ToUInt32(ARM9.ReadBytes((uint)(reference.Item2 + data.pointerDiff), 4), 0) - RomInfo.headerTableOffset - ARM9.address;
|
|
ARM9.WriteBytes(BitConverter.GetBytes(pointerValue), (uint)(reference.Item2 + data.pointerDiff));
|
|
}
|
|
|
|
if (specialCase) {
|
|
/* Special case: at 0x3B522 (non-JAP and non-Spanish HG offset) there is an instruction
|
|
between the (mov r1, #0x18) and (mul r1, r0) commands, so we must handle this separately */
|
|
|
|
ARM9.WriteBytes(DSUtils.HexStringToByteArray(data.specialCaseData1), (uint)(data.specialCaseOffset1 + data.pointerDiff));
|
|
ARM9.WriteBytes(DSUtils.HexStringToByteArray(data.specialCaseData2), (uint)(data.specialCaseOffset2 + data.pointerDiff));
|
|
ARM9.WriteBytes(DSUtils.HexStringToByteArray(data.specialCaseData3), (uint)(data.specialCaseOffset3 + data.pointerDiff));
|
|
}
|
|
|
|
// Clear the dynamic headers directory in 'unpacked'
|
|
Directory.Delete(headersDir.unpackedDir, true);
|
|
Directory.CreateDirectory(headersDir.unpackedDir);
|
|
|
|
/* Now move the headers data from arm9 to the new directory. Upon saving the ROM,
|
|
the data will be packed into a NARC and replace a/0/5/0 in HGSS or
|
|
debug/cb_edit/d_test.narc in Platinum */
|
|
|
|
int headerCount = RomInfo.GetHeaderCount();
|
|
for (int i = 0; i < headerCount; i++) {
|
|
byte[] headerData = MapHeader.LoadFromARM9((ushort)i).ToByteArray();
|
|
DSUtils.WriteToFile(headersDir.unpackedDir + "\\" + i.ToString("D4"), headerData);
|
|
}
|
|
|
|
DisableDynamicHeadersPatch("Already applied");
|
|
dynamicHeadersPatchCB.Visible = true;
|
|
PatchToolboxDialog.flag_DynamicHeadersPatchApplied = true;
|
|
|
|
MessageBox.Show("The headers are now dynamically allocated in memory.", "Operation successful.", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
} catch {
|
|
MessageBox.Show("Operation failed. It is strongly advised that you restore the arm9 backup (arm9.bin" + backupSuffix + ").", "Something went wrong",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
} else {
|
|
MessageBox.Show("No changes have been made.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
private void disableDynamicTexturesButton_Click(object sender, EventArgs e) {
|
|
DialogResult d;
|
|
d = MessageBox.Show("Applying this patch will set the Dynamic Textures field of all AreaData files to 0xFFFF.\n\n" +
|
|
"Are you sure you want to proceed?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d == DialogResult.Yes) {
|
|
DSUtils.TryUnpackNarcs(new List<RomInfo.DirNames> { DirNames.areaData });
|
|
|
|
string[] adFiles = Directory.GetFiles(gameDirs[DirNames.areaData].unpackedDir);
|
|
foreach (string s in adFiles) {
|
|
AreaData a = new AreaData(new FileStream(s, FileMode.Open)) {
|
|
dynamicTextureType = 0xFFFF
|
|
};
|
|
a.SaveToFile(s, showSuccessMessage: false);
|
|
}
|
|
|
|
DisableKillTextureAnimationsPatch("Already applied");
|
|
disableTextureAnimationsCB.Visible = true;
|
|
MessageBox.Show("Texture Animations have been disabled in every AreaData.", "Operation successful.", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
} else {
|
|
MessageBox.Show("No changes have been made.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
|
|
private void expandTrainerNamesButton_Click(object sender, EventArgs e) {
|
|
// Pearl USA ARM9 at 0x6AC32 // TODO: Verify
|
|
// Pearl Spain ARM9 at 0x6AC8E // TODO: Verify
|
|
// Diamond USA ARM9 at 0x6AC32
|
|
// Diamond Spain ARM9 at 0x6AC8E
|
|
// Platinum USA ARM9 at 0x791DE
|
|
// Platinum Spain ARM9 at 0x7927E
|
|
// HeartGold USA ARM9 at 0x7342E
|
|
// HeartGold Spain ARM9 at 0x73426
|
|
// SoulSilver USA ARM9 at 0x7342E
|
|
// SoulSilver Spain ARM9 at 0x7342E // TODO: Verify
|
|
|
|
DialogResult d = MessageBox.Show($"Applying this patch will set the Trainer Name max length to {PatchToolboxDialog.expandedTrainerNameLength-1} usable characters.\n" +
|
|
"Are you sure you want to proceed?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d == DialogResult.Yes) {
|
|
try {
|
|
using (ARM9.Writer wr = new ARM9.Writer(RomInfo.trainerNameLenOffset)) {
|
|
wr.Write((byte)PatchToolboxDialog.expandedTrainerNameLength);
|
|
}
|
|
|
|
PatchToolboxDialog.flag_TrainerNamesExpanded = true;
|
|
DisableTrainerNameExpansionPatch("Already applied");
|
|
expandTrainerNamesCB.Visible = true;
|
|
RomInfo.SetTrainerNameMaxLen();
|
|
MessageBox.Show("Trainer Names have been extended.", "Operation successful.", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
} catch (IOException) {
|
|
MessageBox.Show("ARM9 could not be written.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
}
|
|
} else {
|
|
MessageBox.Show("No changes have been made.", "Operation canceled", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
|
|
#region Mikelan's custom commands
|
|
private void applyCustomCommands(object sender, EventArgs e) {
|
|
int expTableOffset = GetCommandTableOffset();
|
|
|
|
if (expTableOffset < 0) {
|
|
DialogResult d;
|
|
d = MessageBox.Show("Script command table has not been repointed.\n\n" +
|
|
"Do you wish to repoint it to the expanded ARM9 file?\n\n" +
|
|
"By default it will be written from 0x200 to 0x1700.\n" +
|
|
"If you already have something there, you must cancel this window and move these things to a new location, or you can manually repoint the script command table to a different free location in the expanded ARM9 file",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
|
|
if (d == DialogResult.Yes) {
|
|
RepointCommandTable();
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ImportCustomCommand()) {
|
|
MessageBox.Show("Script commands succesfully installed in the ROM", "Done", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
|
|
}
|
|
private int GetCommandTableOffset() { // Checks if command table is repointed IN THE EXPANDED ARM9 FILE, returns pointer inside this file
|
|
ResourceManager customcmdDB = new ResourceManager("DSPRE.Resources.ROMToolboxDB.CustomScrCmdDB", Assembly.GetExecutingAssembly());
|
|
int pointerOffset = int.Parse(customcmdDB.GetString("pointerOffset" + "_" + RomInfo.gameVersion + "_" + RomInfo.gameLanguage));
|
|
using (ARM9.Reader r = new ARM9.Reader(pointerOffset)) {
|
|
uint cmdTable = r.ReadUInt32();
|
|
uint offset = cmdTable - synthOverlayLoadAddress;
|
|
|
|
if ((offset >= 0) && (offset <= 0x12B00)) {
|
|
return (int)offset; // Table position inside the expanded arm9 file
|
|
}
|
|
}
|
|
return -1; // No table in expanded arm9 file
|
|
}
|
|
private void RepointCommandTable() {
|
|
string expandedPath = RomInfo.gameDirs[DirNames.synthOverlay].unpackedDir + "\\0000";
|
|
ResourceManager customcmdDB = new ResourceManager("DSPRE.Resources.ROMToolboxDB.CustomScrCmdDB", Assembly.GetExecutingAssembly());
|
|
|
|
FileStream arm9FileStream = new FileStream(RomInfo.arm9Path, FileMode.Open); // I make a copy of the stream so the file is free for writing
|
|
MemoryStream arm9Stream = new MemoryStream();
|
|
arm9FileStream.CopyTo(arm9Stream);
|
|
byte[] cmdTbl = arm9Stream.ToArray();
|
|
|
|
using (BinaryWriter expArmWriter = new BinaryWriter(new FileStream(expandedPath, FileMode.Open))) {
|
|
expArmWriter.BaseStream.Position = 0x200; // Command table default offset
|
|
expArmWriter.Write(cmdTbl, int.Parse(customcmdDB.GetString("originalTableOffset" + "_" + RomInfo.gameVersion + "_" + RomInfo.gameLanguage)), 4 * 0x355);
|
|
}
|
|
|
|
arm9FileStream.Close();
|
|
|
|
using (ARM9.Writer wr = new ARM9.Writer()) { // Change both the pointer and the limit
|
|
wr.BaseStream.Position = int.Parse(customcmdDB.GetString("pointerOffset" + "_" + RomInfo.gameVersion + "_" + RomInfo.gameLanguage));
|
|
wr.Write((uint)0x023C8200);
|
|
|
|
wr.BaseStream.Position = int.Parse(customcmdDB.GetString("limitOffset" + "_" + RomInfo.gameVersion + "_" + RomInfo.gameLanguage));
|
|
wr.Write((uint)0x053C);
|
|
}
|
|
}
|
|
private bool ImportCustomCommand() {
|
|
string expandedPath = RomInfo.gameDirs[DirNames.synthOverlay].unpackedDir + "\\0000";
|
|
int appliedPatches = 0;
|
|
|
|
OpenFileDialog of = new OpenFileDialog();
|
|
of.Filter = "Custom Script Command File (*.scrcmd)|*.scrcmd";
|
|
if (of.ShowDialog(this) != DialogResult.OK) {
|
|
return false;
|
|
}
|
|
|
|
FileStream expandedFileStream = new FileStream(expandedPath, FileMode.Open);
|
|
MemoryStream expandedStream = new MemoryStream();
|
|
expandedFileStream.CopyTo(expandedStream);
|
|
expandedFileStream.Close();
|
|
|
|
using (DSUtils.EasyWriter expandedWriter = new DSUtils.EasyWriter(expandedPath, fmode: FileMode.Open)) {
|
|
using (BinaryReader expandedReader = new BinaryReader(expandedStream)) {
|
|
try {
|
|
System.Xml.Linq.XDocument xmldoc = System.Xml.Linq.XDocument.Load(new FileStream(of.FileName, FileMode.Open));
|
|
|
|
foreach (var node in xmldoc.Root.Elements("scriptcommand")) {
|
|
ushort commandID = ushort.Parse(node.Attribute("ID").Value, System.Globalization.NumberStyles.HexNumber);
|
|
string targetROM = node.Element("ROM").Value;
|
|
string targetLang = node.Element("lang").Value;
|
|
string commandName = node.Element("name").Value;
|
|
string paramCount = node.Element("paramcount").Value;
|
|
string paramCode = node.Element("paramcode").Value;
|
|
int asmOffset = Int32.Parse(node.Element("asmoffset").Value, System.Globalization.NumberStyles.HexNumber);
|
|
string asmCode = node.Element("asmcode").Value.Replace("\n", "").Replace("\t", "").Replace(" ", "");
|
|
|
|
if (RomInfo.gameVersion.ToString().Equals(targetROM) && RomInfo.gameLanguage.Equals(targetLang)) {
|
|
expandedReader.BaseStream.Position = 0x200 + commandID * 4;
|
|
if (expandedReader.ReadUInt32() != 0) {
|
|
DialogResult d;
|
|
d = MessageBox.Show("Script command " + commandID.ToString("X4") + " is already used.\n\n" +
|
|
"Do you really want to overwrite it?",
|
|
"Confirm to proceed", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
|
if (d == DialogResult.No) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
expandedWriter.BaseStream.Position = 0x200 + commandID * 4;
|
|
expandedWriter.Write((int)(synthOverlayLoadAddress + asmOffset + 1));
|
|
|
|
byte[] asmCodeBytes = DSUtils.StringToByteArray(asmCode);
|
|
expandedWriter.BaseStream.Position = asmOffset;
|
|
expandedWriter.Write(asmCodeBytes);
|
|
|
|
appliedPatches++;
|
|
}
|
|
}
|
|
|
|
} catch {
|
|
MessageBox.Show("Selected command installation file is corrupted.\n\n" +
|
|
"Please, download it again or contact its creator.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (appliedPatches == 0) {
|
|
MessageBox.Show("No command could be installed from this file.\n\n" +
|
|
"Make sure the command installation file supports your current ROM.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
#endregion
|
|
|
|
#endregion
|
|
|
|
#region Error Messsages
|
|
private void AlreadyApplied() {
|
|
MessageBox.Show("This patch has already been applied.", "Can't reapply patch", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
#endregion
|
|
|
|
|
|
}
|
|
} |