diff --git a/DS_Map/DSPRE.csproj b/DS_Map/DSPRE.csproj
index 8b3ca99..131a35c 100644
--- a/DS_Map/DSPRE.csproj
+++ b/DS_Map/DSPRE.csproj
@@ -122,6 +122,18 @@
+
+ Form
+
+
+ BtxEditor.cs
+
+
+ Form
+
+
+ BtxExitConfirmation.cs
+
UserControl
@@ -219,6 +231,7 @@
Form
+
@@ -431,6 +444,12 @@
DVCalcNatureViewerForm.cs
+
+ BtxEditor.cs
+
+
+ BtxExitConfirmation.cs
+
EncountersEditor.cs
diff --git a/DS_Map/Editors/BtxEditor/BtxEditor.Designer.cs b/DS_Map/Editors/BtxEditor/BtxEditor.Designer.cs
new file mode 100644
index 0000000..3e54d2b
--- /dev/null
+++ b/DS_Map/Editors/BtxEditor/BtxEditor.Designer.cs
@@ -0,0 +1,203 @@
+namespace DSPRE.Editors.BtxEditor
+{
+ partial class BtxEditor
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.overworldList = new System.Windows.Forms.ComboBox();
+ this.overworldPictureBox = new System.Windows.Forms.PictureBox();
+ this.showBtxFileButton = new System.Windows.Forms.Button();
+ this.exportImagePng = new System.Windows.Forms.Button();
+ this.importImagePng = new System.Windows.Forms.Button();
+ this.shinyCheckbox = new System.Windows.Forms.CheckBox();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.saveSelected_Button = new System.Windows.Forms.Button();
+ this.SaveAll_Button = new System.Windows.Forms.Button();
+ ((System.ComponentModel.ISupportInitialize)(this.overworldPictureBox)).BeginInit();
+ this.panel1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.AutoSize = true;
+ this.label1.Location = new System.Drawing.Point(13, 13);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(55, 13);
+ this.label1.TabIndex = 0;
+ this.label1.Text = "Overworld";
+ //
+ // overworldList
+ //
+ this.overworldList.FormattingEnabled = true;
+ this.overworldList.Location = new System.Drawing.Point(12, 29);
+ this.overworldList.Name = "overworldList";
+ this.overworldList.Size = new System.Drawing.Size(125, 21);
+ this.overworldList.TabIndex = 1;
+ this.overworldList.SelectedIndexChanged += new System.EventHandler(this.overworldList_SelectedIndexChanged);
+ //
+ // overworldPictureBox
+ //
+ this.overworldPictureBox.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.overworldPictureBox.Location = new System.Drawing.Point(3, 0);
+ this.overworldPictureBox.Name = "overworldPictureBox";
+ this.overworldPictureBox.Size = new System.Drawing.Size(117, 209);
+ this.overworldPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
+ this.overworldPictureBox.TabIndex = 2;
+ this.overworldPictureBox.TabStop = false;
+ //
+ // showBtxFileButton
+ //
+ this.showBtxFileButton.Enabled = false;
+ this.showBtxFileButton.Image = global::DSPRE.Properties.Resources.lens;
+ this.showBtxFileButton.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.showBtxFileButton.Location = new System.Drawing.Point(148, 27);
+ this.showBtxFileButton.Name = "showBtxFileButton";
+ this.showBtxFileButton.Size = new System.Drawing.Size(121, 23);
+ this.showBtxFileButton.TabIndex = 3;
+ this.showBtxFileButton.Text = "Show BTX File";
+ this.showBtxFileButton.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
+ this.showBtxFileButton.UseVisualStyleBackColor = true;
+ this.showBtxFileButton.Click += new System.EventHandler(this.showBtxFileButton_Click);
+ //
+ // exportImagePng
+ //
+ this.exportImagePng.Enabled = false;
+ this.exportImagePng.Image = global::DSPRE.Properties.Resources.exportArrow;
+ this.exportImagePng.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.exportImagePng.Location = new System.Drawing.Point(148, 145);
+ this.exportImagePng.Name = "exportImagePng";
+ this.exportImagePng.Size = new System.Drawing.Size(121, 23);
+ this.exportImagePng.TabIndex = 4;
+ this.exportImagePng.Text = "Export PNG";
+ this.exportImagePng.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
+ this.exportImagePng.UseVisualStyleBackColor = true;
+ this.exportImagePng.Click += new System.EventHandler(this.exportImagePng_Click);
+ //
+ // importImagePng
+ //
+ this.importImagePng.Enabled = false;
+ this.importImagePng.Image = global::DSPRE.Properties.Resources.importArrow;
+ this.importImagePng.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.importImagePng.Location = new System.Drawing.Point(16, 145);
+ this.importImagePng.Name = "importImagePng";
+ this.importImagePng.Size = new System.Drawing.Size(121, 23);
+ this.importImagePng.TabIndex = 5;
+ this.importImagePng.Text = "Import PNG";
+ this.importImagePng.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
+ this.importImagePng.UseVisualStyleBackColor = true;
+ this.importImagePng.Click += new System.EventHandler(this.importImagePng_Click);
+ //
+ // shinyCheckbox
+ //
+ this.shinyCheckbox.AutoSize = true;
+ this.shinyCheckbox.Enabled = false;
+ this.shinyCheckbox.Location = new System.Drawing.Point(13, 57);
+ this.shinyCheckbox.Name = "shinyCheckbox";
+ this.shinyCheckbox.Size = new System.Drawing.Size(52, 17);
+ this.shinyCheckbox.TabIndex = 6;
+ this.shinyCheckbox.Text = "Shiny";
+ this.shinyCheckbox.UseVisualStyleBackColor = true;
+ this.shinyCheckbox.CheckedChanged += new System.EventHandler(this.shinyCheckbox_CheckedChanged);
+ //
+ // panel1
+ //
+ this.panel1.AutoScroll = true;
+ this.panel1.Controls.Add(this.overworldPictureBox);
+ this.panel1.Dock = System.Windows.Forms.DockStyle.Right;
+ this.panel1.Location = new System.Drawing.Point(283, 0);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(123, 209);
+ this.panel1.TabIndex = 7;
+ //
+ // saveSelected_Button
+ //
+ this.saveSelected_Button.Image = global::DSPRE.Properties.Resources.saveButton;
+ this.saveSelected_Button.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.saveSelected_Button.Location = new System.Drawing.Point(16, 174);
+ this.saveSelected_Button.Name = "saveSelected_Button";
+ this.saveSelected_Button.Size = new System.Drawing.Size(121, 23);
+ this.saveSelected_Button.TabIndex = 8;
+ this.saveSelected_Button.Text = "Save Selected";
+ this.saveSelected_Button.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
+ this.saveSelected_Button.UseVisualStyleBackColor = true;
+ this.saveSelected_Button.Click += new System.EventHandler(this.saveSelected_Button_Click);
+ //
+ // SaveAll_Button
+ //
+ this.SaveAll_Button.Image = global::DSPRE.Properties.Resources.saveButton;
+ this.SaveAll_Button.ImageAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.SaveAll_Button.Location = new System.Drawing.Point(148, 174);
+ this.SaveAll_Button.Name = "SaveAll_Button";
+ this.SaveAll_Button.Size = new System.Drawing.Size(121, 23);
+ this.SaveAll_Button.TabIndex = 9;
+ this.SaveAll_Button.Text = "Save All";
+ this.SaveAll_Button.TextImageRelation = System.Windows.Forms.TextImageRelation.TextBeforeImage;
+ this.SaveAll_Button.UseVisualStyleBackColor = true;
+ this.SaveAll_Button.Click += new System.EventHandler(this.SaveAll_Button_Click);
+ //
+ // BtxEditor
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(406, 209);
+ this.Controls.Add(this.SaveAll_Button);
+ this.Controls.Add(this.saveSelected_Button);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.shinyCheckbox);
+ this.Controls.Add(this.importImagePng);
+ this.Controls.Add(this.exportImagePng);
+ this.Controls.Add(this.showBtxFileButton);
+ this.Controls.Add(this.overworldList);
+ this.Controls.Add(this.label1);
+ this.MaximumSize = new System.Drawing.Size(422, 248);
+ this.MinimumSize = new System.Drawing.Size(422, 248);
+ this.Name = "BtxEditor";
+ this.ShowIcon = false;
+ this.Text = "Overworld (BTX) Editor";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.BtxEditor_FormClosing);
+ ((System.ComponentModel.ISupportInitialize)(this.overworldPictureBox)).EndInit();
+ this.panel1.ResumeLayout(false);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.ComboBox overworldList;
+ private System.Windows.Forms.PictureBox overworldPictureBox;
+ private System.Windows.Forms.Button showBtxFileButton;
+ private System.Windows.Forms.Button exportImagePng;
+ private System.Windows.Forms.Button importImagePng;
+ private System.Windows.Forms.CheckBox shinyCheckbox;
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.Button saveSelected_Button;
+ private System.Windows.Forms.Button SaveAll_Button;
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/Editors/BtxEditor/BtxEditor.cs b/DS_Map/Editors/BtxEditor/BtxEditor.cs
new file mode 100644
index 0000000..4aa714e
--- /dev/null
+++ b/DS_Map/Editors/BtxEditor/BtxEditor.cs
@@ -0,0 +1,230 @@
+using DSPRE.LibNDSFormats;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Windows.Forms;
+using static DSPRE.RomInfo;
+
+namespace DSPRE.Editors.BtxEditor
+{
+ public partial class BtxEditor : Form
+ {
+ private Bitmap bm;
+ private byte[] BTXFile;
+
+ // Track modified BTX files
+ private Dictionary modifiedBTXFiles = new Dictionary();
+
+ public BtxEditor()
+ {
+ RomInfo.SetOWtable();
+ RomInfo.Set3DOverworldsDict();
+ RomInfo.ReadOWTable();
+ InitializeComponent();
+ overworldList.Items.Clear();
+
+ foreach (ushort key in RomInfo.OverworldTable.Keys)
+ {
+ overworldList.Items.Add("OW Entry " + key);
+ }
+
+ this.FormClosing += BtxEditor_FormClosing;
+ }
+
+ private void overworldList_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ int selection = overworldList.SelectedIndex;
+ if (selection < 0)
+ {
+ return;
+ }
+
+ showBtxFileButton.Enabled = true;
+ exportImagePng.Enabled = true;
+ importImagePng.Enabled = true;
+
+ ushort overlayTableEntryID = (ushort)RomInfo.OverworldTable.Keys.ElementAt(selection);
+ uint spriteID = RomInfo.OverworldTable[overlayTableEntryID].spriteID;
+ string path = RomInfo.gameDirs[DirNames.OWSprites].unpackedDir + "\\" + spriteID.ToString("D4");
+
+ if (modifiedBTXFiles.TryGetValue(overlayTableEntryID, out byte[] modifiedData))
+ {
+ BTXFile = modifiedData;
+ }
+ else if (File.Exists(path))
+ {
+ BTXFile = File.ReadAllBytes(path);
+ }
+ else
+ {
+ overworldPictureBox.Image = (Bitmap)Properties.Resources.ResourceManager.GetObject("overworldUnreadable");
+ return;
+ }
+
+ bm = BTX0.Read(BTXFile);
+ if (bm != null)
+ {
+ shinyCheckbox.Enabled = (BTX0.PaletteSize == 64 && BTX0.PaletteCount == 2);
+
+ overworldPictureBox.Width = bm.Width;
+ overworldPictureBox.Height = bm.Height;
+ overworldPictureBox.Image = bm;
+ }
+ else
+ {
+ MessageBox.Show("This file is not supported.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
+ }
+ }
+
+ private void shinyCheckbox_CheckedChanged(object sender, EventArgs e)
+ {
+ if (shinyCheckbox.Enabled)
+ {
+ BTX0.PaletteIndex = shinyCheckbox.Checked ? 1u : 0u;
+ bm = BTX0.Read(BTXFile);
+ overworldPictureBox.Image = bm;
+ }
+ }
+
+ private void exportImagePng_Click(object sender, EventArgs e)
+ {
+ SaveFileDialog saveFileDialog = new SaveFileDialog();
+ saveFileDialog.Title = "Save As";
+ saveFileDialog.Filter = "PNG (*.png)|*.png";
+ if (saveFileDialog.ShowDialog() == DialogResult.OK)
+ {
+ bm.Save(saveFileDialog.FileName);
+ }
+ }
+
+ private void importImagePng_Click(object sender, EventArgs e)
+ {
+ OpenFileDialog openFileDialog = new OpenFileDialog();
+ openFileDialog.Title = "Open";
+ openFileDialog.Filter = "PNG (*.png)|*.png";
+ if (openFileDialog.ShowDialog() != DialogResult.OK)
+ {
+ return;
+ }
+
+ Bitmap bitmap = new Bitmap(openFileDialog.FileName);
+ if (bm.Width == bitmap.Width && bm.Height == bitmap.Height)
+ {
+ if (GetColorCount(bitmap) <= BTX0.ColorCount)
+ {
+ BTXFile = BTX0.Write(BTXFile, bitmap);
+ bm = BTX0.Read(BTXFile);
+ overworldPictureBox.Image = bm;
+
+ ushort overlayTableEntryID = (ushort)RomInfo.OverworldTable.Keys.ElementAt(overworldList.SelectedIndex);
+ modifiedBTXFiles[overlayTableEntryID] = BTXFile;
+
+ MessageBox.Show($"OW Entry {overlayTableEntryID} marked as modified. Use Save Selected or Save All to write it.", "Pending Save", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ else
+ {
+ MessageBox.Show("Too many colors!\nBTX: " + BTX0.ColorCount + "\nPNG: " + GetColorCount(bitmap), "Information", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
+ }
+ }
+ else
+ {
+ MessageBox.Show("Not the same size!\nBTX: " + bm.Width + "x" + bm.Height + "\nPNG: " + bitmap.Width + "x" + bitmap.Height, "Information", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
+ }
+ }
+
+ private uint GetColorCount(Bitmap temp)
+ {
+ HashSet hashSet = new HashSet();
+ for (int y = 0; y < temp.Height; y++)
+ {
+ for (int x = 0; x < temp.Width; x++)
+ {
+ hashSet.Add(temp.GetPixel(x, y));
+ }
+ }
+ return (uint)hashSet.Count;
+ }
+
+ private void showBtxFileButton_Click(object sender, EventArgs e)
+ {
+ ushort overlayTableEntryID = (ushort)RomInfo.OverworldTable.Keys.ElementAt(overworldList.SelectedIndex);
+ uint spriteID = RomInfo.OverworldTable[overlayTableEntryID].spriteID;
+ string path = RomInfo.gameDirs[DirNames.OWSprites].unpackedDir + "\\" + spriteID.ToString("D4");
+ Helpers.ExplorerSelect(path);
+ }
+
+ private void SaveAll_Button_Click(object sender, EventArgs e)
+ {
+ int savedCount = 0;
+ foreach (var kvp in modifiedBTXFiles.ToList())
+ {
+ ushort entryID = kvp.Key;
+ byte[] data = kvp.Value;
+ uint spriteID = RomInfo.OverworldTable[entryID].spriteID;
+ string path = Path.Combine(RomInfo.gameDirs[DirNames.OWSprites].unpackedDir, spriteID.ToString("D4"));
+
+ try
+ {
+ File.WriteAllBytes(path, data);
+ modifiedBTXFiles.Remove(entryID);
+ savedCount++;
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"Failed to save OW Entry {entryID}: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ MessageBox.Show($"Saved {savedCount} modified BTX file(s).", "Batch Save Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+
+ private void saveSelected_Button_Click(object sender, EventArgs e)
+ {
+ if (overworldList.SelectedIndex < 0) return;
+
+ ushort overlayTableEntryID = (ushort)RomInfo.OverworldTable.Keys.ElementAt(overworldList.SelectedIndex);
+
+ if (!modifiedBTXFiles.TryGetValue(overlayTableEntryID, out byte[] btxData))
+ {
+ MessageBox.Show("No modification to save for the selected OW Entry.", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ return;
+ }
+
+ uint spriteID = RomInfo.OverworldTable[overlayTableEntryID].spriteID;
+ string path = Path.Combine(RomInfo.gameDirs[DirNames.OWSprites].unpackedDir, spriteID.ToString("D4"));
+
+ try
+ {
+ File.WriteAllBytes(path, btxData);
+ modifiedBTXFiles.Remove(overlayTableEntryID);
+ MessageBox.Show($"Saved OW Entry {overlayTableEntryID} successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"Failed to save OW Entry {overlayTableEntryID}: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+ private bool isConfirmingExit = false;
+
+ private void BtxEditor_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ if (modifiedBTXFiles.Count == 0 || isConfirmingExit || e.Cancel)
+ return;
+
+ BtxExitConfirmation dialog = new BtxExitConfirmation(modifiedBTXFiles, RomInfo.OverworldTable);
+ DialogResult result = dialog.ShowDialog();
+
+ if (result == DialogResult.No)
+ {
+ e.Cancel = true;
+ } else
+ {
+ isConfirmingExit = true;
+ }
+
+ }
+
+ }
+}
diff --git a/DS_Map/Editors/BtxEditor/BtxEditor.resx b/DS_Map/Editors/BtxEditor/BtxEditor.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/DS_Map/Editors/BtxEditor/BtxEditor.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/DS_Map/Editors/BtxEditor/BtxExitConfirmation.Designer.cs b/DS_Map/Editors/BtxEditor/BtxExitConfirmation.Designer.cs
new file mode 100644
index 0000000..f0a77f4
--- /dev/null
+++ b/DS_Map/Editors/BtxEditor/BtxExitConfirmation.Designer.cs
@@ -0,0 +1,178 @@
+namespace DSPRE.Editors.BtxEditor
+{
+ partial class BtxExitConfirmation
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.exitWithoutSavingButton = new System.Windows.Forms.Button();
+ this.cancelButton = new System.Windows.Forms.Button();
+ this.unsavedFileCountLabel = new System.Windows.Forms.Label();
+ this.modifiedOverworldsDetails = new System.Windows.Forms.ListBox();
+ this.beforeSpriteBox = new System.Windows.Forms.PictureBox();
+ this.afterSpriteBox = new System.Windows.Forms.PictureBox();
+ this.pictureBox4 = new System.Windows.Forms.PictureBox();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.panel2 = new System.Windows.Forms.Panel();
+ ((System.ComponentModel.ISupportInitialize)(this.beforeSpriteBox)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.afterSpriteBox)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).BeginInit();
+ this.panel1.SuspendLayout();
+ this.panel2.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // exitWithoutSavingButton
+ //
+ this.exitWithoutSavingButton.Anchor = System.Windows.Forms.AnchorStyles.None;
+ this.exitWithoutSavingButton.DialogResult = System.Windows.Forms.DialogResult.Yes;
+ this.exitWithoutSavingButton.Location = new System.Drawing.Point(12, 165);
+ this.exitWithoutSavingButton.Name = "exitWithoutSavingButton";
+ this.exitWithoutSavingButton.Size = new System.Drawing.Size(112, 43);
+ this.exitWithoutSavingButton.TabIndex = 0;
+ this.exitWithoutSavingButton.Text = "Exit Without Saving";
+ this.exitWithoutSavingButton.UseVisualStyleBackColor = true;
+ //
+ // cancelButton
+ //
+ this.cancelButton.Anchor = System.Windows.Forms.AnchorStyles.None;
+ this.cancelButton.DialogResult = System.Windows.Forms.DialogResult.No;
+ this.cancelButton.Location = new System.Drawing.Point(141, 165);
+ this.cancelButton.Name = "cancelButton";
+ this.cancelButton.Size = new System.Drawing.Size(112, 43);
+ this.cancelButton.TabIndex = 1;
+ this.cancelButton.Text = "Cancel";
+ this.cancelButton.UseVisualStyleBackColor = true;
+ //
+ // unsavedFileCountLabel
+ //
+ this.unsavedFileCountLabel.AutoSize = true;
+ this.unsavedFileCountLabel.Location = new System.Drawing.Point(12, 9);
+ this.unsavedFileCountLabel.Name = "unsavedFileCountLabel";
+ this.unsavedFileCountLabel.Size = new System.Drawing.Size(35, 13);
+ this.unsavedFileCountLabel.TabIndex = 2;
+ this.unsavedFileCountLabel.Text = "label1";
+ //
+ // modifiedOverworldsDetails
+ //
+ this.modifiedOverworldsDetails.FormattingEnabled = true;
+ this.modifiedOverworldsDetails.Location = new System.Drawing.Point(12, 25);
+ this.modifiedOverworldsDetails.Name = "modifiedOverworldsDetails";
+ this.modifiedOverworldsDetails.Size = new System.Drawing.Size(241, 134);
+ this.modifiedOverworldsDetails.TabIndex = 3;
+ this.modifiedOverworldsDetails.SelectedIndexChanged += new System.EventHandler(this.modifiedOverworldsDetails_SelectedIndexChanged);
+ //
+ // beforeSpriteBox
+ //
+ this.beforeSpriteBox.Location = new System.Drawing.Point(0, 0);
+ this.beforeSpriteBox.Name = "beforeSpriteBox";
+ this.beforeSpriteBox.Size = new System.Drawing.Size(48, 190);
+ this.beforeSpriteBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
+ this.beforeSpriteBox.TabIndex = 4;
+ this.beforeSpriteBox.TabStop = false;
+ //
+ // afterSpriteBox
+ //
+ this.afterSpriteBox.Location = new System.Drawing.Point(0, 0);
+ this.afterSpriteBox.Name = "afterSpriteBox";
+ this.afterSpriteBox.Size = new System.Drawing.Size(48, 190);
+ this.afterSpriteBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
+ this.afterSpriteBox.TabIndex = 5;
+ this.afterSpriteBox.TabStop = false;
+ //
+ // pictureBox4
+ //
+ this.pictureBox4.BackgroundImage = global::DSPRE.Properties.Resources.arrowright;
+ this.pictureBox4.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Center;
+ this.pictureBox4.InitialImage = global::DSPRE.Properties.Resources.arrowright;
+ this.pictureBox4.Location = new System.Drawing.Point(327, 98);
+ this.pictureBox4.Name = "pictureBox4";
+ this.pictureBox4.Size = new System.Drawing.Size(29, 28);
+ this.pictureBox4.TabIndex = 6;
+ this.pictureBox4.TabStop = false;
+ //
+ // panel1
+ //
+ this.panel1.AutoScroll = true;
+ this.panel1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.panel1.Controls.Add(this.beforeSpriteBox);
+ this.panel1.Location = new System.Drawing.Point(272, 12);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(51, 196);
+ this.panel1.TabIndex = 7;
+ this.panel1.Scroll += new System.Windows.Forms.ScrollEventHandler(this.panel1_Scroll);
+ //
+ // panel2
+ //
+ this.panel2.AutoScroll = true;
+ this.panel2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.panel2.Controls.Add(this.afterSpriteBox);
+ this.panel2.Location = new System.Drawing.Point(362, 12);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(51, 196);
+ this.panel2.TabIndex = 8;
+ this.panel2.Scroll += new System.Windows.Forms.ScrollEventHandler(this.panel2_Scroll);
+ //
+ // BtxExitConfirmation
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(425, 243);
+ this.ControlBox = false;
+ this.Controls.Add(this.panel2);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.pictureBox4);
+ this.Controls.Add(this.modifiedOverworldsDetails);
+ this.Controls.Add(this.unsavedFileCountLabel);
+ this.Controls.Add(this.cancelButton);
+ this.Controls.Add(this.exitWithoutSavingButton);
+ this.MaximumSize = new System.Drawing.Size(441, 282);
+ this.MinimumSize = new System.Drawing.Size(441, 259);
+ this.Name = "BtxExitConfirmation";
+ this.ShowIcon = false;
+ this.Text = "Unsaved modifications";
+ ((System.ComponentModel.ISupportInitialize)(this.beforeSpriteBox)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.afterSpriteBox)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).EndInit();
+ this.panel1.ResumeLayout(false);
+ this.panel2.ResumeLayout(false);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Button exitWithoutSavingButton;
+ private System.Windows.Forms.Button cancelButton;
+ private System.Windows.Forms.Label unsavedFileCountLabel;
+ private System.Windows.Forms.ListBox modifiedOverworldsDetails;
+ private System.Windows.Forms.PictureBox beforeSpriteBox;
+ private System.Windows.Forms.PictureBox afterSpriteBox;
+ private System.Windows.Forms.PictureBox pictureBox4;
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.Panel panel2;
+ }
+}
\ No newline at end of file
diff --git a/DS_Map/Editors/BtxEditor/BtxExitConfirmation.cs b/DS_Map/Editors/BtxEditor/BtxExitConfirmation.cs
new file mode 100644
index 0000000..c8ef7ea
--- /dev/null
+++ b/DS_Map/Editors/BtxEditor/BtxExitConfirmation.cs
@@ -0,0 +1,109 @@
+using DSPRE.LibNDSFormats;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Controls;
+using System.Windows.Forms;
+using static DSPRE.RomInfo;
+using Panel = System.Windows.Forms.Panel;
+
+namespace DSPRE.Editors.BtxEditor
+{
+ public partial class BtxExitConfirmation : Form
+ {
+ private SortedDictionary _overworldList;
+ private Dictionary _modifiedBtx;
+
+ public BtxExitConfirmation(Dictionary modifiedBtx, SortedDictionary overworldList)
+ {
+ InitializeComponent();
+ unsavedFileCountLabel.Text = $"{modifiedBtx.Count} BTX file(s) unsaved";
+ _overworldList = overworldList;
+ _modifiedBtx = modifiedBtx;
+
+ foreach (var entryID in modifiedBtx.Keys)
+ {
+ uint spriteID = RomInfo.OverworldTable[entryID].spriteID;
+ modifiedOverworldsDetails.Items.Add($"OW Entry {entryID} → Sprite {spriteID:D4}");
+ }
+
+ panel1.MouseWheel += Panel_MouseWheel;
+ panel2.MouseWheel += Panel_MouseWheel;
+ }
+
+ private void modifiedOverworldsDetails_SelectedIndexChanged(object sender, EventArgs e)
+ {
+ var selection = modifiedOverworldsDetails.SelectedIndex;
+
+ if (selection == -1) return;
+ var selectedObj = _modifiedBtx.ElementAt(selection);
+ Bitmap newSprite = BTX0.Read(selectedObj.Value);
+ afterSpriteBox.Image = newSprite;
+ afterSpriteBox.Width = newSprite.Width;
+ afterSpriteBox.Height = newSprite.Height;
+
+ ushort overlayTableEntryID = (ushort)_overworldList.ElementAt(selectedObj.Key).Key;
+ uint spriteID = _overworldList[overlayTableEntryID].spriteID;
+ string path = RomInfo.gameDirs[DirNames.OWSprites].unpackedDir + "\\" + spriteID.ToString("D4");
+
+ if (File.Exists(path))
+ {
+ Bitmap oldSprite = BTX0.Read(File.ReadAllBytes(path));
+ beforeSpriteBox.Image = oldSprite;
+ beforeSpriteBox.Width = oldSprite.Width;
+ beforeSpriteBox.Height = oldSprite.Height;
+ }
+
+ }
+
+ private bool syncing = false;
+
+ private void panel1_Scroll(object sender, ScrollEventArgs e)
+ {
+ if (syncing) return;
+ syncing = true;
+ panel2.AutoScrollPosition = new Point(
+ panel2.AutoScrollPosition.X,
+ panel1.VerticalScroll.Value
+ );
+ syncing = false;
+ }
+
+ private void panel2_Scroll(object sender, ScrollEventArgs e)
+ {
+ if (syncing) return;
+ syncing = true;
+ panel1.AutoScrollPosition = new Point(
+ panel1.AutoScrollPosition.X,
+ panel2.VerticalScroll.Value
+ );
+ syncing = false;
+ }
+
+
+ private void Panel_MouseWheel(object sender, MouseEventArgs e)
+ {
+ var source = sender as Panel;
+ var target = (source == panel1) ? panel2 : panel1;
+
+ int scrollDelta = e.Delta; // Usually 120 or -120
+ int newValue = source.VerticalScroll.Value - scrollDelta;
+
+ // Clamp the new scroll value within limits
+ newValue = Math.Max(source.VerticalScroll.Minimum,
+ Math.Min(source.VerticalScroll.Maximum - source.Height, newValue));
+
+ source.AutoScrollPosition = new Point(0, newValue);
+ target.AutoScrollPosition = new Point(0, newValue);
+ }
+
+
+
+ }
+}
diff --git a/DS_Map/Editors/BtxEditor/BtxExitConfirmation.resx b/DS_Map/Editors/BtxEditor/BtxExitConfirmation.resx
new file mode 100644
index 0000000..1af7de1
--- /dev/null
+++ b/DS_Map/Editors/BtxEditor/BtxExitConfirmation.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/DS_Map/LibNDSFormats/BTX0.cs b/DS_Map/LibNDSFormats/BTX0.cs
new file mode 100644
index 0000000..f6c5780
--- /dev/null
+++ b/DS_Map/LibNDSFormats/BTX0.cs
@@ -0,0 +1,167 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DSPRE.LibNDSFormats
+{
+ internal class BTX0
+ {
+ public static uint PaletteIndex;
+
+ public static uint PaletteCount;
+
+ public static uint PaletteSize;
+
+ public static uint ColorCount;
+
+ public static uint ImageOffset;
+
+ public static uint PaletteOffset;
+
+ public static uint ImageWidth;
+
+ public static uint ImageHeight;
+ public static Bitmap Read(byte[] BTXFile)
+ {
+ if (BitConverter.ToUInt32(BTXFile, 0) != 811095106)
+ {
+ return null;
+ }
+ uint num = BitConverter.ToUInt32(BTXFile, 16);
+ if (BitConverter.ToUInt32(BTXFile, (int)num) != 811091284)
+ {
+ return null;
+ }
+ uint num2 = num + BitConverter.ToUInt16(BTXFile, (int)(num + 14));
+ uint num3 = (ImageOffset = num + BitConverter.ToUInt32(BTXFile, (int)(num + 20)));
+ uint num4 = BitConverter.ToUInt32(BTXFile, (int)(num + 48)) << 3;
+ uint num5 = num + BitConverter.ToUInt32(BTXFile, (int)(num + 52));
+ uint num6 = (PaletteOffset = num + BitConverter.ToUInt32(BTXFile, (int)(num + 56)));
+ uint num7 = BTXFile[num2 + 1];
+ uint num8 = BitConverter.ToUInt16(BTXFile, (int)(num2 + 12 + num7 * 4 + 6));
+ uint num9 = (uint)(8 << (((int)num8 >> 4) & 7));
+ uint num10 = (num8 >> 10) & 7;
+ uint num11 = (PaletteCount = BTXFile[num5 + 1]);
+ PaletteSize = num4;
+ if (num10 == 3)
+ {
+ Color[] array = new Color[num4 / num11 / 2];
+ if (num4 < 64 && num11 >= 2)
+ {
+ array = new Color[(BTXFile.Length - num6) / 2];
+ }
+ ColorCount = (uint)array.Length;
+ for (int i = 0; i < array.Length; i++)
+ {
+ ushort num12 = BitConverter.ToUInt16(BTXFile, (int)(num6 + PaletteIndex * (ColorCount * 2)) + i * 2);
+ uint red = (uint)((num12 & 0x1F) << 3);
+ uint green = (uint)(num12 & 0x3E0) >> 2;
+ uint blue = (uint)(num12 & 0x7C00) >> 7;
+ array[i] = Color.FromArgb(255, (int)red, (int)green, (int)blue);
+ }
+ ImageWidth = num9;
+ ImageHeight = (num6 - num3) * 2 / num9;
+ Bitmap bitmap = new Bitmap((int)ImageWidth, (int)ImageHeight);
+ uint num13 = 0u;
+ uint num14 = 0u;
+ for (int j = (int)num3; j < num6; j++)
+ {
+ uint num15 = BTXFile[j];
+ uint[] array2 = new uint[2]
+ {
+ num15 & 0xF,
+ num15 >> 4
+ };
+ for (int k = 0; k < array2.Length; k++)
+ {
+ bitmap.SetPixel((int)num13, (int)num14, array[array2[k]]);
+ num13++;
+ }
+ if (num13 >= num9)
+ {
+ num13 = 0u;
+ num14++;
+ }
+ }
+ return bitmap;
+ }
+ return null;
+ }
+
+ public static byte[] Write(byte[] BTXFile, Bitmap bm)
+ {
+ HashSet hashSet = new HashSet();
+ uint num = 0u;
+ uint num2 = 0u;
+ for (int i = 0; i < bm.Width * bm.Height; i++)
+ {
+ hashSet.Add(bm.GetPixel((int)num, (int)num2));
+ num++;
+ if (num >= bm.Width)
+ {
+ num = 0u;
+ num2++;
+ }
+ }
+ Color[] array = hashSet.ToArray();
+ num = 0u;
+ num2 = 0u;
+ for (int j = (int)ImageOffset; j < PaletteOffset; j++)
+ {
+ Color pixel = bm.GetPixel((int)num, (int)num2);
+ num++;
+ uint num3 = 0u;
+ for (int k = 0; k < array.Length; k++)
+ {
+ if (array[k] == pixel)
+ {
+ num3 = (uint)k;
+ break;
+ }
+ }
+ pixel = bm.GetPixel((int)num, (int)num2);
+ num++;
+ for (int l = 0; l < array.Length; l++)
+ {
+ if (array[l] == pixel)
+ {
+ num3 += (uint)(l << 4);
+ break;
+ }
+ }
+ BTXFile[j] = (byte)num3;
+ if (num >= ImageWidth)
+ {
+ num = 0u;
+ num2++;
+ }
+ }
+ for (int m = 0; m < array.Length; m++)
+ {
+ uint num4 = (uint)Math.Round((double)(int)array[m].R / 8.0);
+ uint num5 = (uint)Math.Round((double)(int)array[m].G / 8.0);
+ uint num6 = (uint)Math.Round((double)(int)array[m].B / 8.0);
+ if (num4 > 31)
+ {
+ num4 = 31u;
+ }
+ if (num5 > 31)
+ {
+ num5 = 31u;
+ }
+ if (num6 > 31)
+ {
+ num6 = 31u;
+ }
+ uint num7 = num4 + (num5 << 5) + (num6 << 10);
+ BTXFile[PaletteOffset + PaletteIndex * (ColorCount * 2) + m * 2] = (byte)num7;
+ BTXFile[PaletteOffset + PaletteIndex * (ColorCount * 2) + m * 2 + 1] = (byte)(num7 >> 8);
+ }
+ return BTXFile;
+ }
+ }
+
+}
diff --git a/DS_Map/Main Window.Designer.cs b/DS_Map/Main Window.Designer.cs
index 17f8123..b574e09 100644
--- a/DS_Map/Main Window.Designer.cs
+++ b/DS_Map/Main Window.Designer.cs
@@ -825,7 +825,8 @@
this.overlayEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.spawnEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.moveDataEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
- this.flyWarpEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.overworldEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.flyWarpEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.aboutToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.statusStrip1 = new System.Windows.Forms.StatusStrip();
this.statusLabel = new System.Windows.Forms.ToolStripStatusLabel();
@@ -10550,7 +10551,8 @@
this.spawnEditorToolStripMenuItem,
this.moveDataEditorToolStripMenuItem,
this.flyWarpEditorToolStripMenuItem,
- this.itemEditorToolStripMenuItem});
+ this.itemEditorToolStripMenuItem,
+ this.overworldEditorToolStripMenuItem});
this.otherEditorsToolStripMenuItem.Enabled = false;
this.otherEditorsToolStripMenuItem.Name = "otherEditorsToolStripMenuItem";
this.otherEditorsToolStripMenuItem.Size = new System.Drawing.Size(88, 20);
@@ -10590,7 +10592,15 @@
this.flyWarpEditorToolStripMenuItem.Size = new System.Drawing.Size(180, 22);
this.flyWarpEditorToolStripMenuItem.Text = "Fly Warp Editor";
this.flyWarpEditorToolStripMenuItem.Click += new System.EventHandler(this.flyWarpEditorToolStripMenuItem_Click);
+
+ //
+ // overworldEditorToolStripMenuItem
//
+ this.overworldEditorToolStripMenuItem.Name = "overworldEditorToolStripMenuItem";
+ this.overworldEditorToolStripMenuItem.Size = new System.Drawing.Size(174, 22);
+ this.overworldEditorToolStripMenuItem.Text = "Overworld Editor";
+ this.overworldEditorToolStripMenuItem.Click += new System.EventHandler(this.overworldEditorToolStripMenuItem_Click);
+
// aboutToolStripMenuItem1
//
this.aboutToolStripMenuItem1.Name = "aboutToolStripMenuItem1";
@@ -12130,6 +12140,7 @@
private System.Windows.Forms.TrackBar transparencyBar;
private System.Windows.Forms.ToolStripMenuItem addressHelperToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem exportScriptDatabaseJSONToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem overworldEditorToolStripMenuItem;
private System.Windows.Forms.ToolStripMenuItem generateCSVToolStripMenuItem;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.Panel panel1;
diff --git a/DS_Map/Main Window.cs b/DS_Map/Main Window.cs
index 7f3d202..30e145d 100644
--- a/DS_Map/Main Window.cs
+++ b/DS_Map/Main Window.cs
@@ -37,6 +37,7 @@ using static DSPRE.ROMFiles.SpeciesFile;
using System.Reflection;
using System.ComponentModel;
using DSPRE.Editors;
+using DSPRE.Editors.BtxEditor;
namespace DSPRE {
@@ -10182,6 +10183,13 @@ namespace DSPRE {
form.Show();
}
+
+ private void overworldEditorToolStripMenuItem_Click(object sender, EventArgs e)
+ {
+
+ BtxEditor form = new BtxEditor();
+ form.Show();
+ }
private void exportScriptDatabaseJSONToolStripMenuItem_Click(object sender, EventArgs e)
{
MessageBox.Show("Not implemented yet");