Merge pull request #24 from Mixone-FinallyHere/dev-kuha

BtxEditor + Confirmation window
This commit is contained in:
Miguel 2025-06-18 19:22:57 +02:00 committed by GitHub
commit b6875db38f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 1167 additions and 2 deletions

View File

@ -122,6 +122,18 @@
</Compile>
<Compile Include="DVCalculator\DVCalculator.cs" />
<Compile Include="EditorPanels.cs" />
<Compile Include="Editors\BtxEditor\BtxEditor.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Editors\BtxEditor\BtxEditor.Designer.cs">
<DependentUpon>BtxEditor.cs</DependentUpon>
</Compile>
<Compile Include="Editors\BtxEditor\BtxExitConfirmation.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Editors\BtxEditor\BtxExitConfirmation.Designer.cs">
<DependentUpon>BtxExitConfirmation.cs</DependentUpon>
</Compile>
<Compile Include="Editors\EncountersEditor.cs">
<SubType>UserControl</SubType>
</Compile>
@ -219,6 +231,7 @@
<SubType>Form</SubType>
</Compile>
<Compile Include="FlyEditor\FlyEditor.Designer.cs" />
<Compile Include="LibNDSFormats\BTX0.cs" />
<Compile Include="GameCamera.cs" />
<Compile Include="Helpers.cs" />
<Compile Include="InputComboBox.cs">
@ -431,6 +444,12 @@
<EmbeddedResource Include="DVCalculator\DVCalcNatureViewerForm.resx">
<DependentUpon>DVCalcNatureViewerForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Editors\BtxEditor\BtxEditor.resx">
<DependentUpon>BtxEditor.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Editors\BtxEditor\BtxExitConfirmation.resx">
<DependentUpon>BtxExitConfirmation.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Editors\EncountersEditor.resx">
<DependentUpon>EncountersEditor.cs</DependentUpon>
</EmbeddedResource>

View File

@ -0,0 +1,203 @@
namespace DSPRE.Editors.BtxEditor
{
partial class BtxEditor
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

View File

@ -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<ushort, byte[]> modifiedBTXFiles = new Dictionary<ushort, byte[]>();
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<Color> hashSet = new HashSet<Color>();
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;
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,178 @@
namespace DSPRE.Editors.BtxEditor
{
partial class BtxExitConfirmation
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

View File

@ -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<uint, (uint spriteID, ushort properties)> _overworldList;
private Dictionary<ushort, byte[]> _modifiedBtx;
public BtxExitConfirmation(Dictionary<ushort, byte[]> modifiedBtx, SortedDictionary<uint, (uint spriteID, ushort properties)> 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);
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -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<Color> hashSet = new HashSet<Color>();
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;
}
}
}

View File

@ -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;

View File

@ -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");