From 8f15da654501e80d5c7de426a8f5f44e7c2c0d66 Mon Sep 17 00:00:00 2001 From: AsY!um- <377468+AsYlum-@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:06:50 +0200 Subject: [PATCH 1/5] Fix tiledata CSV import when importing from newer client to older client. --- Ultima/TileData.cs | 44 +++++++++++-------- .../UserControls/TileDataControl.cs | 4 +- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Ultima/TileData.cs b/Ultima/TileData.cs index 253df27..044c016 100644 --- a/Ultima/TileData.cs +++ b/Ultima/TileData.cs @@ -1604,21 +1604,25 @@ public static void ImportItemDataFromCsv(string fileName) continue; } - try + string[] split = line.Split(';'); + if (split.Length < 44) { - string[] split = line.Split(';'); - if (split.Length < 44) - { - continue; - } + continue; + } - int id = TileDataHelpers.ConvertStringToInt(split[0]); + int id = TileDataHelpers.ConvertStringToInt(split[0]); + if (id < 0 || id >= ItemTable.Length) + { + continue; + } + + try + { ItemTable[id].ReadData(split); } catch { - // TODO: ignored? - // ignored + // Malformed CSV field value — skip } } } @@ -1647,21 +1651,25 @@ public static void ImportLandDataFromCsv(string fileName) continue; } - try + string[] split = line.Split(';'); + if (split.Length < 35) { - string[] split = line.Split(';'); - if (split.Length < 35) - { - continue; - } + continue; + } - int id = TileDataHelpers.ConvertStringToInt(split[0]); + int id = TileDataHelpers.ConvertStringToInt(split[0]); + if (id < 0 || id >= LandTable.Length) + { + continue; + } + + try + { LandTable[id].ReadData(split); } catch { - // TODO: ignored? - // ignored + // Malformed CSV field value — skip } } } diff --git a/UoFiddler.Controls/UserControls/TileDataControl.cs b/UoFiddler.Controls/UserControls/TileDataControl.cs index 0b7b559..3575c71 100644 --- a/UoFiddler.Controls/UserControls/TileDataControl.cs +++ b/UoFiddler.Controls/UserControls/TileDataControl.cs @@ -1626,13 +1626,13 @@ private void OnClickImport(object sender, EventArgs e) if (tabcontrol.SelectedIndex == 0) // items { TileData.ImportItemDataFromCsv(dialog.FileName); - AfterSelectTreeViewItem(this, new TreeViewEventArgs(treeViewItem.SelectedNode)); } else { TileData.ImportLandDataFromCsv(dialog.FileName); - AfterSelectTreeViewLand(this, new TreeViewEventArgs(treeViewLand.SelectedNode)); } + + Reload(); } } From bc2066ac74e4c414e531c5ee87156976943e12fc Mon Sep 17 00:00:00 2001 From: AsY!um- <377468+AsYlum-@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:52:02 +0200 Subject: [PATCH 2/5] Add change background color to other previews. --- .../RadarColorControl.Designer.cs | 26 ++++++++++++-- .../UserControls/RadarColorControl.cs | 35 +++++++++++++++++-- .../UserControls/TileDataControl.Designer.cs | 29 +++++++++++++-- .../UserControls/TileDataControl.cs | 34 ++++++++++++++++-- .../UserControls/VerdataControl.Designer.cs | 29 ++++++++++++--- .../UserControls/VerdataControl.cs | 23 +++++++++++- 6 files changed, 162 insertions(+), 14 deletions(-) diff --git a/UoFiddler.Controls/UserControls/RadarColorControl.Designer.cs b/UoFiddler.Controls/UserControls/RadarColorControl.Designer.cs index a70dbaa..39f3dfc 100644 --- a/UoFiddler.Controls/UserControls/RadarColorControl.Designer.cs +++ b/UoFiddler.Controls/UserControls/RadarColorControl.Designer.cs @@ -93,8 +93,12 @@ private void InitializeComponent() button2 = new System.Windows.Forms.Button(); button1 = new System.Windows.Forms.Button(); buttonMean = new System.Windows.Forms.Button(); + PictureBoxContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(components); + changeBackgroundColorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + colorDialog = new System.Windows.Forms.ColorDialog(); contextMenuStrip1.SuspendLayout(); contextMenuStrip2.SuspendLayout(); + PictureBoxContextMenuStrip.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)pictureBoxArt).BeginInit(); ((System.ComponentModel.ISupportInitialize)pictureBoxColor).BeginInit(); ((System.ComponentModel.ISupportInitialize)splitContainer5).BeginInit(); @@ -229,7 +233,8 @@ private void InitializeComponent() setAsRangeToToolStripMenuItem1.Click += OnClickSetRangeTo; // // pictureBoxArt - // + // + pictureBoxArt.ContextMenuStrip = PictureBoxContextMenuStrip; pictureBoxArt.Dock = System.Windows.Forms.DockStyle.Fill; pictureBoxArt.Location = new System.Drawing.Point(0, 0); pictureBoxArt.Margin = new System.Windows.Forms.Padding(4); @@ -237,7 +242,20 @@ private void InitializeComponent() pictureBoxArt.Size = new System.Drawing.Size(244, 154); pictureBoxArt.TabIndex = 0; pictureBoxArt.TabStop = false; - // + // + // PictureBoxContextMenuStrip + // + PictureBoxContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { changeBackgroundColorToolStripMenuItem }); + PictureBoxContextMenuStrip.Name = "PictureBoxContextMenuStrip"; + PictureBoxContextMenuStrip.Size = new System.Drawing.Size(213, 26); + // + // changeBackgroundColorToolStripMenuItem + // + changeBackgroundColorToolStripMenuItem.Name = "changeBackgroundColorToolStripMenuItem"; + changeBackgroundColorToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + changeBackgroundColorToolStripMenuItem.Text = "Change background color"; + changeBackgroundColorToolStripMenuItem.Click += ChangeBackgroundColorToolStripMenuItem_Click; + // // pictureBoxColor // pictureBoxColor.Location = new System.Drawing.Point(4, 4); @@ -757,6 +775,7 @@ private void InitializeComponent() Load += OnLoad; contextMenuStrip1.ResumeLayout(false); contextMenuStrip2.ResumeLayout(false); + PictureBoxContextMenuStrip.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)pictureBoxArt).EndInit(); ((System.ComponentModel.ISupportInitialize)pictureBoxColor).EndInit(); splitContainer5.Panel1.ResumeLayout(false); @@ -806,6 +825,9 @@ private void InitializeComponent() private System.Windows.Forms.Button buttonMean; private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; private System.Windows.Forms.ContextMenuStrip contextMenuStrip2; + private System.Windows.Forms.ContextMenuStrip PictureBoxContextMenuStrip; + private System.Windows.Forms.ToolStripMenuItem changeBackgroundColorToolStripMenuItem; + private System.Windows.Forms.ColorDialog colorDialog; private System.Windows.Forms.NumericUpDown numericUpDownB; private System.Windows.Forms.NumericUpDown numericUpDownG; private System.Windows.Forms.NumericUpDown numericUpDownR; diff --git a/UoFiddler.Controls/UserControls/RadarColorControl.cs b/UoFiddler.Controls/UserControls/RadarColorControl.cs index 5f138e8..dc33bbd 100644 --- a/UoFiddler.Controls/UserControls/RadarColorControl.cs +++ b/UoFiddler.Controls/UserControls/RadarColorControl.cs @@ -190,6 +190,9 @@ public void OnLoad(object sender, EventArgs e) if (!IsLoaded) { ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; + ControlEvents.PreviewBackgroundColorChangeEvent += OnPreviewBackgroundColorChanged; + + pictureBoxArt.BackColor = Options.PreviewBackgroundColor; } IsLoaded = true; @@ -201,6 +204,34 @@ private void OnFilePathChangeEvent() Reload(); } + private void ChangeBackgroundColorToolStripMenuItem_Click(object sender, EventArgs e) + { + if (colorDialog.ShowDialog() != DialogResult.OK) + { + return; + } + + Options.PreviewBackgroundColor = colorDialog.Color; + ControlEvents.FirePreviewBackgroundColorChangeEvent(); + } + + private void OnPreviewBackgroundColorChanged() + { + pictureBoxArt.BackColor = Options.PreviewBackgroundColor; + + if (_selectedIndex >= 0) + { + if (tabControl2.SelectedIndex == 0) + { + AfterSelectTreeViewItem(this, new TreeViewEventArgs(treeViewItem.SelectedNode)); + } + else + { + AfterSelectTreeViewLand(this, new TreeViewEventArgs(treeViewLand.SelectedNode)); + } + } + } + private void AfterSelectTreeViewItem(object sender, TreeViewEventArgs e) { SaveColor(); @@ -213,7 +244,7 @@ private void AfterSelectTreeViewItem(object sender, TreeViewEventArgs e) Bitmap newBitmap = new Bitmap(pictureBoxArt.Size.Width, pictureBoxArt.Size.Height); using (Graphics newGraphic = Graphics.FromImage(newBitmap)) { - newGraphic.Clear(Color.FromArgb(-1)); + newGraphic.Clear(Options.PreviewBackgroundColor); newGraphic.DrawImage(bitmap, (pictureBoxArt.Size.Width - bitmap.Width) / 2, 1); } @@ -242,7 +273,7 @@ private void AfterSelectTreeViewLand(object sender, TreeViewEventArgs e) Bitmap newBitmap = new Bitmap(pictureBoxArt.Size.Width, pictureBoxArt.Size.Height); using (Graphics newGraphic = Graphics.FromImage(newBitmap)) { - newGraphic.Clear(Color.FromArgb(-1)); + newGraphic.Clear(Options.PreviewBackgroundColor); newGraphic.DrawImage(bitmap, (pictureBoxArt.Size.Width - bitmap.Width) / 2, 1); } diff --git a/UoFiddler.Controls/UserControls/TileDataControl.Designer.cs b/UoFiddler.Controls/UserControls/TileDataControl.Designer.cs index 83fe713..cd14d09 100644 --- a/UoFiddler.Controls/UserControls/TileDataControl.Designer.cs +++ b/UoFiddler.Controls/UserControls/TileDataControl.Designer.cs @@ -130,6 +130,9 @@ private void InitializeComponent() toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); helpToolStripButton = new System.Windows.Forms.ToolStripButton(); toolTipComponent = new System.Windows.Forms.ToolTip(components); + PictureBoxContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(components); + changeBackgroundColorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + colorDialog = new System.Windows.Forms.ColorDialog(); tabcontrol.SuspendLayout(); tabPageItems.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit(); @@ -156,6 +159,7 @@ private void InitializeComponent() splitContainer6.Panel2.SuspendLayout(); splitContainer6.SuspendLayout(); LandTilesContextMenuStrip.SuspendLayout(); + PictureBoxContextMenuStrip.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)pictureBoxLand).BeginInit(); ((System.ComponentModel.ISupportInitialize)splitContainer7).BeginInit(); splitContainer7.Panel1.SuspendLayout(); @@ -281,7 +285,8 @@ private void InitializeComponent() selectInGumpsTabFemaleToolStripMenuItem.Click += SelectInGumpsTabFemaleToolStripMenuItem_Click; // // pictureBoxItem - // + // + pictureBoxItem.ContextMenuStrip = PictureBoxContextMenuStrip; pictureBoxItem.Dock = System.Windows.Forms.DockStyle.Fill; pictureBoxItem.Location = new System.Drawing.Point(0, 0); pictureBoxItem.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); @@ -289,7 +294,20 @@ private void InitializeComponent() pictureBoxItem.Size = new System.Drawing.Size(245, 129); pictureBoxItem.TabIndex = 0; pictureBoxItem.TabStop = false; - // + // + // PictureBoxContextMenuStrip + // + PictureBoxContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { changeBackgroundColorToolStripMenuItem }); + PictureBoxContextMenuStrip.Name = "PictureBoxContextMenuStrip"; + PictureBoxContextMenuStrip.Size = new System.Drawing.Size(213, 26); + // + // changeBackgroundColorToolStripMenuItem + // + changeBackgroundColorToolStripMenuItem.Name = "changeBackgroundColorToolStripMenuItem"; + changeBackgroundColorToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + changeBackgroundColorToolStripMenuItem.Text = "Change background color"; + changeBackgroundColorToolStripMenuItem.Click += ChangeBackgroundColorToolStripMenuItem_Click; + // // splitContainer3 // splitContainer3.Dock = System.Windows.Forms.DockStyle.Fill; @@ -794,7 +812,8 @@ private void InitializeComponent() selToolStripMenuItem.Click += OnClickSelectRadarLand; // // pictureBoxLand - // + // + pictureBoxLand.ContextMenuStrip = PictureBoxContextMenuStrip; pictureBoxLand.Dock = System.Windows.Forms.DockStyle.Fill; pictureBoxLand.Location = new System.Drawing.Point(0, 0); pictureBoxLand.Margin = new System.Windows.Forms.Padding(4, 3, 4, 3); @@ -1100,6 +1119,7 @@ private void InitializeComponent() ((System.ComponentModel.ISupportInitialize)splitContainer6).EndInit(); splitContainer6.ResumeLayout(false); LandTilesContextMenuStrip.ResumeLayout(false); + PictureBoxContextMenuStrip.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)pictureBoxLand).EndInit(); splitContainer7.Panel1.ResumeLayout(false); splitContainer7.Panel1.PerformLayout(); @@ -1118,6 +1138,9 @@ private void InitializeComponent() private System.Windows.Forms.CheckedListBox checkedListBox2; private System.Windows.Forms.ContextMenuStrip ItemsContextMenuStrip; private System.Windows.Forms.ContextMenuStrip LandTilesContextMenuStrip; + private System.Windows.Forms.ContextMenuStrip PictureBoxContextMenuStrip; + private System.Windows.Forms.ToolStripMenuItem changeBackgroundColorToolStripMenuItem; + private System.Windows.Forms.ColorDialog colorDialog; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label10; private System.Windows.Forms.Label label11; diff --git a/UoFiddler.Controls/UserControls/TileDataControl.cs b/UoFiddler.Controls/UserControls/TileDataControl.cs index 3575c71..3966f74 100644 --- a/UoFiddler.Controls/UserControls/TileDataControl.cs +++ b/UoFiddler.Controls/UserControls/TileDataControl.cs @@ -40,6 +40,9 @@ public TileDataControl() ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; ControlEvents.TileDataChangeEvent += OnTileDataChangeEvent; + ControlEvents.PreviewBackgroundColorChangeEvent += OnPreviewBackgroundColorChanged; + + pictureBoxItem.BackColor = Options.PreviewBackgroundColor; } private void InitLandTilesFlagsCheckBoxes() @@ -614,6 +617,33 @@ private void OnFilePathChangeEvent() Reload(); } + private void ChangeBackgroundColorToolStripMenuItem_Click(object sender, EventArgs e) + { + if (colorDialog.ShowDialog() != DialogResult.OK) + { + return; + } + + Options.PreviewBackgroundColor = colorDialog.Color; + ControlEvents.FirePreviewBackgroundColorChangeEvent(); + } + + private void OnPreviewBackgroundColorChanged() + { + pictureBoxItem.BackColor = Options.PreviewBackgroundColor; + pictureBoxLand.BackColor = Options.PreviewBackgroundColor; + + if (treeViewItem.SelectedNode != null) + { + AfterSelectTreeViewItem(this, new TreeViewEventArgs(treeViewItem.SelectedNode)); + } + + if (treeViewLand.SelectedNode != null) + { + AfterSelectTreeViewLand(this, new TreeViewEventArgs(treeViewLand.SelectedNode)); + } + } + private void OnTileDataChangeEvent(object sender, int index) { if (!IsLoaded) @@ -698,7 +728,7 @@ private void AfterSelectTreeViewItem(object sender, TreeViewEventArgs e) Bitmap newBit = new Bitmap(pictureBoxItem.Size.Width, pictureBoxItem.Size.Height); using (Graphics newGraph = Graphics.FromImage(newBit)) { - newGraph.Clear(Color.FromArgb(-1)); + newGraph.Clear(Options.PreviewBackgroundColor); newGraph.DrawImage(bit, (pictureBoxItem.Size.Width - bit.Width) / 2, 1); } @@ -749,7 +779,7 @@ private void AfterSelectTreeViewLand(object sender, TreeViewEventArgs e) Bitmap newBit = new Bitmap(pictureBoxLand.Size.Width, pictureBoxLand.Size.Height); using (Graphics newGraph = Graphics.FromImage(newBit)) { - newGraph.Clear(Color.FromArgb(-1)); + newGraph.Clear(Options.PreviewBackgroundColor); newGraph.DrawImage(bit, (pictureBoxLand.Size.Width - bit.Width) / 2, 1); } diff --git a/UoFiddler.Controls/UserControls/VerdataControl.Designer.cs b/UoFiddler.Controls/UserControls/VerdataControl.Designer.cs index 09053b9..acd65e4 100644 --- a/UoFiddler.Controls/UserControls/VerdataControl.Designer.cs +++ b/UoFiddler.Controls/UserControls/VerdataControl.Designer.cs @@ -17,6 +17,7 @@ protected override void Dispose(bool disposing) private void InitializeComponent() { + components = new System.ComponentModel.Container(); toolStrip = new System.Windows.Forms.ToolStrip(); buttonReload = new System.Windows.Forms.ToolStripButton(); buttonLoadFile = new System.Windows.Forms.ToolStripButton(); @@ -59,6 +60,9 @@ private void InitializeComponent() pictureBoxMulti = new System.Windows.Forms.PictureBox(); tabPageMultiComponents = new System.Windows.Forms.TabPage(); richTextBoxMultiComponents = new System.Windows.Forms.RichTextBox(); + PictureBoxContextMenuStrip = new System.Windows.Forms.ContextMenuStrip(components); + changeBackgroundColorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + colorDialog = new System.Windows.Forms.ColorDialog(); toolStrip.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)splitContainerMain).BeginInit(); splitContainerMain.Panel1.SuspendLayout(); @@ -86,6 +90,7 @@ private void InitializeComponent() panelAnimControls.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)trackBarDirection).BeginInit(); ((System.ComponentModel.ISupportInitialize)pictureBoxPreview).BeginInit(); + PictureBoxContextMenuStrip.SuspendLayout(); panelMulti.SuspendLayout(); tabControlMulti.SuspendLayout(); tabPageMultiPreview.SuspendLayout(); @@ -462,8 +467,8 @@ private void InitializeComponent() buttonPlayStop.Click += OnClickPlayStop; // // pictureBoxPreview - // - pictureBoxPreview.BackColor = System.Drawing.Color.White; + // + pictureBoxPreview.ContextMenuStrip = PictureBoxContextMenuStrip; pictureBoxPreview.Dock = System.Windows.Forms.DockStyle.Fill; pictureBoxPreview.Location = new System.Drawing.Point(0, 0); pictureBoxPreview.Name = "pictureBoxPreview"; @@ -471,7 +476,20 @@ private void InitializeComponent() pictureBoxPreview.TabIndex = 1; pictureBoxPreview.TabStop = false; pictureBoxPreview.Visible = false; - // + // + // PictureBoxContextMenuStrip + // + PictureBoxContextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { changeBackgroundColorToolStripMenuItem }); + PictureBoxContextMenuStrip.Name = "PictureBoxContextMenuStrip"; + PictureBoxContextMenuStrip.Size = new System.Drawing.Size(213, 26); + // + // changeBackgroundColorToolStripMenuItem + // + changeBackgroundColorToolStripMenuItem.Name = "changeBackgroundColorToolStripMenuItem"; + changeBackgroundColorToolStripMenuItem.Size = new System.Drawing.Size(212, 22); + changeBackgroundColorToolStripMenuItem.Text = "Change background color"; + changeBackgroundColorToolStripMenuItem.Click += ChangeBackgroundColorToolStripMenuItem_Click; + // // richTextBoxDetails // richTextBoxDetails.BackColor = System.Drawing.SystemColors.Window; @@ -517,7 +535,6 @@ private void InitializeComponent() // panelMultiScroll // panelMultiScroll.AutoScroll = true; - panelMultiScroll.BackColor = System.Drawing.Color.White; panelMultiScroll.Controls.Add(pictureBoxMulti); panelMultiScroll.Dock = System.Windows.Forms.DockStyle.Fill; panelMultiScroll.Location = new System.Drawing.Point(0, 0); @@ -598,6 +615,7 @@ private void InitializeComponent() panelAnimControls.PerformLayout(); ((System.ComponentModel.ISupportInitialize)trackBarDirection).EndInit(); ((System.ComponentModel.ISupportInitialize)pictureBoxPreview).EndInit(); + PictureBoxContextMenuStrip.ResumeLayout(false); panelMulti.ResumeLayout(false); tabControlMulti.ResumeLayout(false); tabPageMultiPreview.ResumeLayout(false); @@ -653,5 +671,8 @@ private void InitializeComponent() private System.Windows.Forms.PictureBox pictureBoxMulti; private System.Windows.Forms.TabPage tabPageMultiComponents; private System.Windows.Forms.RichTextBox richTextBoxMultiComponents; + private System.Windows.Forms.ContextMenuStrip PictureBoxContextMenuStrip; + private System.Windows.Forms.ToolStripMenuItem changeBackgroundColorToolStripMenuItem; + private System.Windows.Forms.ColorDialog colorDialog; } } diff --git a/UoFiddler.Controls/UserControls/VerdataControl.cs b/UoFiddler.Controls/UserControls/VerdataControl.cs index fb958f9..557971e 100644 --- a/UoFiddler.Controls/UserControls/VerdataControl.cs +++ b/UoFiddler.Controls/UserControls/VerdataControl.cs @@ -100,6 +100,10 @@ private void OnLoad(object sender, EventArgs e) if (!_loaded) { ControlEvents.FilePathChangeEvent += OnFilePathChangeEvent; + ControlEvents.PreviewBackgroundColorChangeEvent += OnPreviewBackgroundColorChanged; + + pictureBoxPreview.BackColor = Options.PreviewBackgroundColor; + panelMultiScroll.BackColor = Options.PreviewBackgroundColor; } _loaded = true; @@ -113,6 +117,23 @@ private void OnFilePathChangeEvent() Populate(); } + private void ChangeBackgroundColorToolStripMenuItem_Click(object sender, EventArgs e) + { + if (colorDialog.ShowDialog() != DialogResult.OK) + { + return; + } + + Options.PreviewBackgroundColor = colorDialog.Color; + ControlEvents.FirePreviewBackgroundColorChangeEvent(); + } + + private void OnPreviewBackgroundColorChanged() + { + pictureBoxPreview.BackColor = Options.PreviewBackgroundColor; + panelMultiScroll.BackColor = Options.PreviewBackgroundColor; + } + private void Populate() { listBoxType.BeginUpdate(); @@ -583,7 +604,7 @@ private void ShowImage(Bitmap bmp, string info) richTextBoxDetails.Visible = false; pictureBoxPreview.Visible = true; pictureBoxPreview.Image = bmp; - pictureBoxPreview.BackColor = Color.White; + pictureBoxPreview.BackColor = Options.PreviewBackgroundColor; } } From 9f72f33602b81ad8068d53c45ab5d7488de07a22 Mon Sep 17 00:00:00 2001 From: AsY!um- <377468+AsYlum-@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:53:06 +0200 Subject: [PATCH 3/5] Update layout in compare RadarCol plugin. --- .../CompareRadarColControl.Designer.cs | 203 +++++++++--------- 1 file changed, 102 insertions(+), 101 deletions(-) diff --git a/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.Designer.cs b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.Designer.cs index bed5c20..b85b183 100644 --- a/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.Designer.cs +++ b/UoFiddler.Plugin.Compare/UserControls/CompareRadarColControl.Designer.cs @@ -26,19 +26,19 @@ private void InitializeComponent() contextMenuStripOrg = new System.Windows.Forms.ContextMenuStrip(components); copyEntry1To2ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); panelDetail = new System.Windows.Forms.Panel(); + groupBoxOrg = new System.Windows.Forms.GroupBox(); + labelOrgColorCaption = new System.Windows.Forms.Label(); + labelOrgColorValue = new System.Windows.Forms.Label(); + pictureBoxOrgColor = new System.Windows.Forms.PictureBox(); + groupBoxSec = new System.Windows.Forms.GroupBox(); + labelSecColorCaption = new System.Windows.Forms.Label(); + labelSecColorValue = new System.Windows.Forms.Label(); + pictureBoxSecColor = new System.Windows.Forms.PictureBox(); groupBoxLegend = new System.Windows.Forms.GroupBox(); legendSwatchDifferent = new System.Windows.Forms.Label(); legendLabelDifferent = new System.Windows.Forms.Label(); legendSwatchIdentical = new System.Windows.Forms.Label(); legendLabelIdentical = new System.Windows.Forms.Label(); - groupBoxSec = new System.Windows.Forms.GroupBox(); - labelSecColorCaption = new System.Windows.Forms.Label(); - labelSecColorValue = new System.Windows.Forms.Label(); - pictureBoxSecColor = new System.Windows.Forms.PictureBox(); - groupBoxOrg = new System.Windows.Forms.GroupBox(); - labelOrgColorCaption = new System.Windows.Forms.Label(); - labelOrgColorValue = new System.Windows.Forms.Label(); - pictureBoxOrgColor = new System.Windows.Forms.PictureBox(); tileViewSec = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); contextMenuStripSec = new System.Windows.Forms.ContextMenuStrip(components); copyEntry2To1ToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -61,11 +61,11 @@ private void InitializeComponent() tableLayoutLand.SuspendLayout(); contextMenuStripOrg.SuspendLayout(); panelDetail.SuspendLayout(); - groupBoxLegend.SuspendLayout(); - groupBoxSec.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)pictureBoxSecColor).BeginInit(); groupBoxOrg.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)pictureBoxOrgColor).BeginInit(); + groupBoxSec.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)pictureBoxSecColor).BeginInit(); + groupBoxLegend.SuspendLayout(); contextMenuStripSec.SuspendLayout(); tabPageItem.SuspendLayout(); tableLayoutItem.SuspendLayout(); @@ -93,7 +93,7 @@ private void InitializeComponent() splitContainer1.Panel2.Controls.Add(buttonBrowse); splitContainer1.Panel2.Controls.Add(textBoxSecondFile); splitContainer1.Size = new System.Drawing.Size(940, 510); - splitContainer1.SplitterDistance = 451; + splitContainer1.SplitterDistance = 449; splitContainer1.SplitterWidth = 5; splitContainer1.TabIndex = 0; // @@ -105,7 +105,7 @@ private void InitializeComponent() tabControl.Location = new System.Drawing.Point(0, 0); tabControl.Name = "tabControl"; tabControl.SelectedIndex = 0; - tabControl.Size = new System.Drawing.Size(940, 451); + tabControl.Size = new System.Drawing.Size(940, 449); tabControl.TabIndex = 0; tabControl.SelectedIndexChanged += OnTabChanged; // @@ -114,7 +114,7 @@ private void InitializeComponent() tabPageLand.Controls.Add(tableLayoutLand); tabPageLand.Location = new System.Drawing.Point(4, 24); tabPageLand.Name = "tabPageLand"; - tabPageLand.Size = new System.Drawing.Size(932, 423); + tabPageLand.Size = new System.Drawing.Size(932, 421); tabPageLand.TabIndex = 0; tabPageLand.Text = "Land Tiles"; tabPageLand.UseVisualStyleBackColor = true; @@ -133,7 +133,7 @@ private void InitializeComponent() tableLayoutLand.Name = "tableLayoutLand"; tableLayoutLand.RowCount = 1; tableLayoutLand.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - tableLayoutLand.Size = new System.Drawing.Size(932, 423); + tableLayoutLand.Size = new System.Drawing.Size(932, 421); tableLayoutLand.TabIndex = 0; // // tileViewOrg @@ -144,7 +144,7 @@ private void InitializeComponent() tileViewOrg.Location = new System.Drawing.Point(3, 3); tileViewOrg.MultiSelect = false; tileViewOrg.Name = "tileViewOrg"; - tileViewOrg.Size = new System.Drawing.Size(248, 417); + tileViewOrg.Size = new System.Drawing.Size(248, 415); tileViewOrg.TabIndex = 0; tileViewOrg.TileBackgroundColor = System.Drawing.SystemColors.Window; tileViewOrg.TileBorderColor = System.Drawing.Color.FromArgb(0, 0, 0); @@ -176,64 +176,55 @@ private void InitializeComponent() // // panelDetail // + panelDetail.BackColor = System.Drawing.SystemColors.Control; panelDetail.Controls.Add(groupBoxOrg); panelDetail.Controls.Add(groupBoxSec); panelDetail.Controls.Add(groupBoxLegend); panelDetail.Dock = System.Windows.Forms.DockStyle.Fill; panelDetail.Location = new System.Drawing.Point(257, 3); panelDetail.Name = "panelDetail"; - panelDetail.Size = new System.Drawing.Size(417, 417); + panelDetail.Size = new System.Drawing.Size(417, 415); panelDetail.TabIndex = 1; // - // groupBoxLegend - // - groupBoxLegend.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; - groupBoxLegend.Controls.Add(legendSwatchDifferent); - groupBoxLegend.Controls.Add(legendLabelDifferent); - groupBoxLegend.Controls.Add(legendSwatchIdentical); - groupBoxLegend.Controls.Add(legendLabelIdentical); - groupBoxLegend.Location = new System.Drawing.Point(6, 325); - groupBoxLegend.Name = "groupBoxLegend"; - groupBoxLegend.Size = new System.Drawing.Size(405, 70); - groupBoxLegend.TabIndex = 2; - groupBoxLegend.TabStop = false; - groupBoxLegend.Text = "Legend"; - // - // legendSwatchDifferent + // groupBoxOrg // - legendSwatchDifferent.BackColor = System.Drawing.Color.Blue; - legendSwatchDifferent.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - legendSwatchDifferent.Location = new System.Drawing.Point(8, 22); - legendSwatchDifferent.Name = "legendSwatchDifferent"; - legendSwatchDifferent.Size = new System.Drawing.Size(16, 16); - legendSwatchDifferent.TabIndex = 0; + groupBoxOrg.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + groupBoxOrg.Controls.Add(labelOrgColorCaption); + groupBoxOrg.Controls.Add(labelOrgColorValue); + groupBoxOrg.Controls.Add(pictureBoxOrgColor); + groupBoxOrg.Location = new System.Drawing.Point(6, 3); + groupBoxOrg.Name = "groupBoxOrg"; + groupBoxOrg.Size = new System.Drawing.Size(405, 155); + groupBoxOrg.TabIndex = 0; + groupBoxOrg.TabStop = false; + groupBoxOrg.Text = "Left (Original)"; // - // legendLabelDifferent + // labelOrgColorCaption // - legendLabelDifferent.AutoSize = true; - legendLabelDifferent.Location = new System.Drawing.Point(30, 22); - legendLabelDifferent.Name = "legendLabelDifferent"; - legendLabelDifferent.Size = new System.Drawing.Size(89, 15); - legendLabelDifferent.TabIndex = 1; - legendLabelDifferent.Text = "Different values"; + labelOrgColorCaption.AutoSize = true; + labelOrgColorCaption.Location = new System.Drawing.Point(8, 115); + labelOrgColorCaption.Name = "labelOrgColorCaption"; + labelOrgColorCaption.Size = new System.Drawing.Size(39, 15); + labelOrgColorCaption.TabIndex = 0; + labelOrgColorCaption.Text = "Color:"; // - // legendSwatchIdentical + // labelOrgColorValue // - legendSwatchIdentical.BackColor = System.Drawing.Color.Gray; - legendSwatchIdentical.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - legendSwatchIdentical.Location = new System.Drawing.Point(8, 46); - legendSwatchIdentical.Name = "legendSwatchIdentical"; - legendSwatchIdentical.Size = new System.Drawing.Size(16, 16); - legendSwatchIdentical.TabIndex = 2; + labelOrgColorValue.AutoSize = true; + labelOrgColorValue.Location = new System.Drawing.Point(55, 115); + labelOrgColorValue.Name = "labelOrgColorValue"; + labelOrgColorValue.Size = new System.Drawing.Size(12, 15); + labelOrgColorValue.TabIndex = 1; + labelOrgColorValue.Text = "-"; // - // legendLabelIdentical + // pictureBoxOrgColor // - legendLabelIdentical.AutoSize = true; - legendLabelIdentical.Location = new System.Drawing.Point(30, 46); - legendLabelIdentical.Name = "legendLabelIdentical"; - legendLabelIdentical.Size = new System.Drawing.Size(52, 15); - legendLabelIdentical.TabIndex = 3; - legendLabelIdentical.Text = "Identical"; + pictureBoxOrgColor.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + pictureBoxOrgColor.Location = new System.Drawing.Point(60, 22); + pictureBoxOrgColor.Name = "pictureBoxOrgColor"; + pictureBoxOrgColor.Size = new System.Drawing.Size(80, 80); + pictureBoxOrgColor.TabIndex = 2; + pictureBoxOrgColor.TabStop = false; // // groupBoxSec // @@ -275,45 +266,55 @@ private void InitializeComponent() pictureBoxSecColor.TabIndex = 2; pictureBoxSecColor.TabStop = false; // - // groupBoxOrg + // groupBoxLegend // - groupBoxOrg.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; - groupBoxOrg.Controls.Add(labelOrgColorCaption); - groupBoxOrg.Controls.Add(labelOrgColorValue); - groupBoxOrg.Controls.Add(pictureBoxOrgColor); - groupBoxOrg.Location = new System.Drawing.Point(6, 3); - groupBoxOrg.Name = "groupBoxOrg"; - groupBoxOrg.Size = new System.Drawing.Size(405, 155); - groupBoxOrg.TabIndex = 0; - groupBoxOrg.TabStop = false; - groupBoxOrg.Text = "Left (Original)"; + groupBoxLegend.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + groupBoxLegend.Controls.Add(legendSwatchDifferent); + groupBoxLegend.Controls.Add(legendLabelDifferent); + groupBoxLegend.Controls.Add(legendSwatchIdentical); + groupBoxLegend.Controls.Add(legendLabelIdentical); + groupBoxLegend.Location = new System.Drawing.Point(6, 325); + groupBoxLegend.Name = "groupBoxLegend"; + groupBoxLegend.Size = new System.Drawing.Size(405, 70); + groupBoxLegend.TabIndex = 2; + groupBoxLegend.TabStop = false; + groupBoxLegend.Text = "Legend"; // - // labelOrgColorCaption + // legendSwatchDifferent // - labelOrgColorCaption.AutoSize = true; - labelOrgColorCaption.Location = new System.Drawing.Point(8, 115); - labelOrgColorCaption.Name = "labelOrgColorCaption"; - labelOrgColorCaption.Size = new System.Drawing.Size(39, 15); - labelOrgColorCaption.TabIndex = 0; - labelOrgColorCaption.Text = "Color:"; + legendSwatchDifferent.BackColor = System.Drawing.Color.Blue; + legendSwatchDifferent.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + legendSwatchDifferent.Location = new System.Drawing.Point(8, 22); + legendSwatchDifferent.Name = "legendSwatchDifferent"; + legendSwatchDifferent.Size = new System.Drawing.Size(16, 16); + legendSwatchDifferent.TabIndex = 0; // - // labelOrgColorValue + // legendLabelDifferent // - labelOrgColorValue.AutoSize = true; - labelOrgColorValue.Location = new System.Drawing.Point(55, 115); - labelOrgColorValue.Name = "labelOrgColorValue"; - labelOrgColorValue.Size = new System.Drawing.Size(12, 15); - labelOrgColorValue.TabIndex = 1; - labelOrgColorValue.Text = "-"; + legendLabelDifferent.AutoSize = true; + legendLabelDifferent.Location = new System.Drawing.Point(30, 22); + legendLabelDifferent.Name = "legendLabelDifferent"; + legendLabelDifferent.Size = new System.Drawing.Size(89, 15); + legendLabelDifferent.TabIndex = 1; + legendLabelDifferent.Text = "Different values"; // - // pictureBoxOrgColor + // legendSwatchIdentical // - pictureBoxOrgColor.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - pictureBoxOrgColor.Location = new System.Drawing.Point(60, 22); - pictureBoxOrgColor.Name = "pictureBoxOrgColor"; - pictureBoxOrgColor.Size = new System.Drawing.Size(80, 80); - pictureBoxOrgColor.TabIndex = 2; - pictureBoxOrgColor.TabStop = false; + legendSwatchIdentical.BackColor = System.Drawing.Color.Gray; + legendSwatchIdentical.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + legendSwatchIdentical.Location = new System.Drawing.Point(8, 46); + legendSwatchIdentical.Name = "legendSwatchIdentical"; + legendSwatchIdentical.Size = new System.Drawing.Size(16, 16); + legendSwatchIdentical.TabIndex = 2; + // + // legendLabelIdentical + // + legendLabelIdentical.AutoSize = true; + legendLabelIdentical.Location = new System.Drawing.Point(30, 46); + legendLabelIdentical.Name = "legendLabelIdentical"; + legendLabelIdentical.Size = new System.Drawing.Size(52, 15); + legendLabelIdentical.TabIndex = 3; + legendLabelIdentical.Text = "Identical"; // // tileViewSec // @@ -323,7 +324,7 @@ private void InitializeComponent() tileViewSec.Location = new System.Drawing.Point(680, 3); tileViewSec.MultiSelect = false; tileViewSec.Name = "tileViewSec"; - tileViewSec.Size = new System.Drawing.Size(249, 417); + tileViewSec.Size = new System.Drawing.Size(249, 415); tileViewSec.TabIndex = 2; tileViewSec.TileBackgroundColor = System.Drawing.SystemColors.Window; tileViewSec.TileBorderColor = System.Drawing.Color.FromArgb(0, 0, 0); @@ -358,7 +359,7 @@ private void InitializeComponent() tabPageItem.Controls.Add(tableLayoutItem); tabPageItem.Location = new System.Drawing.Point(4, 24); tabPageItem.Name = "tabPageItem"; - tabPageItem.Size = new System.Drawing.Size(932, 424); + tabPageItem.Size = new System.Drawing.Size(932, 421); tabPageItem.TabIndex = 1; tabPageItem.Text = "Static Tiles"; tabPageItem.UseVisualStyleBackColor = true; @@ -376,7 +377,7 @@ private void InitializeComponent() tableLayoutItem.Name = "tableLayoutItem"; tableLayoutItem.RowCount = 1; tableLayoutItem.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - tableLayoutItem.Size = new System.Drawing.Size(932, 424); + tableLayoutItem.Size = new System.Drawing.Size(932, 421); tableLayoutItem.TabIndex = 0; // // tileViewItemOrg @@ -387,7 +388,7 @@ private void InitializeComponent() tileViewItemOrg.Location = new System.Drawing.Point(3, 3); tileViewItemOrg.MultiSelect = false; tileViewItemOrg.Name = "tileViewItemOrg"; - tileViewItemOrg.Size = new System.Drawing.Size(248, 418); + tileViewItemOrg.Size = new System.Drawing.Size(248, 415); tileViewItemOrg.TabIndex = 0; tileViewItemOrg.TileBackgroundColor = System.Drawing.SystemColors.Window; tileViewItemOrg.TileBorderColor = System.Drawing.Color.FromArgb(0, 0, 0); @@ -412,7 +413,7 @@ private void InitializeComponent() tileViewItemSec.Location = new System.Drawing.Point(680, 3); tileViewItemSec.MultiSelect = false; tileViewItemSec.Name = "tileViewItemSec"; - tileViewItemSec.Size = new System.Drawing.Size(249, 418); + tileViewItemSec.Size = new System.Drawing.Size(249, 415); tileViewItemSec.TabIndex = 2; tileViewItemSec.TileBackgroundColor = System.Drawing.SystemColors.Window; tileViewItemSec.TileBorderColor = System.Drawing.Color.FromArgb(0, 0, 0); @@ -509,14 +510,14 @@ private void InitializeComponent() tableLayoutLand.ResumeLayout(false); contextMenuStripOrg.ResumeLayout(false); panelDetail.ResumeLayout(false); - groupBoxLegend.ResumeLayout(false); - groupBoxLegend.PerformLayout(); - groupBoxSec.ResumeLayout(false); - groupBoxSec.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)pictureBoxSecColor).EndInit(); groupBoxOrg.ResumeLayout(false); groupBoxOrg.PerformLayout(); ((System.ComponentModel.ISupportInitialize)pictureBoxOrgColor).EndInit(); + groupBoxSec.ResumeLayout(false); + groupBoxSec.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)pictureBoxSecColor).EndInit(); + groupBoxLegend.ResumeLayout(false); + groupBoxLegend.PerformLayout(); contextMenuStripSec.ResumeLayout(false); tabPageItem.ResumeLayout(false); tableLayoutItem.ResumeLayout(false); From a07e85f149f2512a51e8e70ccb5221068e318533 Mon Sep 17 00:00:00 2001 From: AsY!um- <377468+AsYlum-@users.noreply.github.com> Date: Thu, 23 Apr 2026 20:06:22 +0200 Subject: [PATCH 4/5] Add support for reading anim6.mul and uop animations. --- Ultima/Animations.cs | 52 +- Ultima/AnimationsUopLoader.cs | 646 +++++ Ultima/BodyConverter.cs | 68 +- Ultima/Files.cs | 9 + Ultima/Helpers/UopUtils.cs | 33 +- .../AnimationListControl.Designer.cs | 23 +- .../UserControls/AnimationListControl.cs | 157 +- UoFiddler/Animationlist.xml | 2081 +++++++++++------ 8 files changed, 2236 insertions(+), 833 deletions(-) create mode 100644 Ultima/AnimationsUopLoader.cs diff --git a/Ultima/Animations.cs b/Ultima/Animations.cs index f7ff06a..234068b 100644 --- a/Ultima/Animations.cs +++ b/Ultima/Animations.cs @@ -14,6 +14,7 @@ public static class Animations private static FileIndex _fileIndex3 = new FileIndex("Anim3.idx", "Anim3.mul", 0x20000, -1); private static FileIndex _fileIndex4 = new FileIndex("Anim4.idx", "Anim4.mul", 0x20000, -1); private static FileIndex _fileIndex5 = new FileIndex("Anim5.idx", "Anim5.mul", 0x20000, -1); + private static FileIndex _fileIndex6 = new FileIndex("Anim6.idx", "Anim6.mul", 0x20000, -1); private static byte[] _streamBuffer; @@ -27,9 +28,11 @@ public static void Reload() _fileIndex3 = new FileIndex("Anim3.idx", "Anim3.mul", 0x20000, -1); _fileIndex4 = new FileIndex("Anim4.idx", "Anim4.mul", 0x20000, -1); _fileIndex5 = new FileIndex("Anim5.idx", "Anim5.mul", 0x20000, -1); + _fileIndex6 = new FileIndex("Anim6.idx", "Anim6.mul", 0x20000, -1); BodyConverter.Initialize(); BodyTable.Initialize(); + AnimationsUopLoader.Reload(); } /// @@ -46,6 +49,11 @@ public static void Reload() /// public static AnimationFrame[] GetAnimation(int body, int action, int direction, ref int hue, bool preserveHue, bool firstFrame) { + if (AnimationsUopLoader.IsUopBody(body)) + { + return AnimationsUopLoader.GetAnimation(body, action, direction, ref hue, preserveHue, firstFrame); + } + if (preserveHue) { Translate(ref body); @@ -262,6 +270,11 @@ private static void LoadTable() /// public static bool IsActionDefined(int body, int action, int direction) { + if (AnimationsUopLoader.IsUopBody(body)) + { + return AnimationsUopLoader.IsActionDefined(body, action); + } + Translate(ref body); int fileType = BodyConverter.Convert(ref body); @@ -272,6 +285,19 @@ public static bool IsActionDefined(int body, int action, int direction) return valid && (length >= 1); } + public static bool IsUopBody(int body) => AnimationsUopLoader.IsUopBody(body); + + public static int GetUopAnimationType(int body) => AnimationsUopLoader.GetAnimationType(body); + + public static System.Collections.Generic.List GetUopDefinedActions(int body) => + AnimationsUopLoader.GetDefinedActions(body); + + public static System.Collections.Generic.IEnumerable GetAllUopBodies() => + AnimationsUopLoader.GetAllUopBodyIds(); + + public static System.Collections.Generic.IEnumerable GetAllMobTypeBodies() => + AnimationsUopLoader.GetAllMobTypeBodyIds(); + /// /// Is Animation in given anim file defined /// @@ -313,6 +339,8 @@ public static int GetAnimCount(int fileType) return 400 + ((int)(_fileIndex4.IdxLength - (35000 * 12)) / (12 * 175)); case 5: return 400 + ((int)(_fileIndex5.IdxLength - (35000 * 12)) / (12 * 175)); + case 6: + return 400 + ((int)(_fileIndex6.IdxLength - (35000 * 12)) / (12 * 175)); } } @@ -371,6 +399,7 @@ public static int GetAnimLength(int body, int fileType) break; case 4: case 5: + case 6: if (body < 200) { length = 22; @@ -478,6 +507,22 @@ private static void GetFileIndex(int body, int action, int direction, int fileTy index = 35000 + ((body - 400) * 175); } + break; + case 6: + fileIndex = _fileIndex6; + if (body < 200) + { + index = body * 110; + } + else if (body < 400) + { + index = 22000 + ((body - 200) * 65); + } + else + { + index = 35000 + ((body - 400) * 175); + } + break; } @@ -500,10 +545,15 @@ private static void GetFileIndex(int body, int action, int direction, int fileTy /// anim{0}.mul public static string GetFileName(int body) { + if (AnimationsUopLoader.IsUopBody(body)) + { + return AnimationsUopLoader.GetUopFileName(body); + } + Translate(ref body); int fileType = BodyConverter.Convert(ref body); - return fileType == 1 ? "anim.mul" : $"anim{fileType}.mul"; + return fileType == 1 ? "anim.mul" : $"anim{fileType}.mul"; // covers anim2–anim6 } } diff --git a/Ultima/AnimationsUopLoader.cs b/Ultima/AnimationsUopLoader.cs new file mode 100644 index 0000000..5034d4e --- /dev/null +++ b/Ultima/AnimationsUopLoader.cs @@ -0,0 +1,646 @@ +/*************************************************************************** + * + * $Author: UOFiddler Contributors + * + * "THE BEER-WARE LICENSE" + * As long as you retain this notice you can do whatever you want with + * this stuff. If we meet some day, and you think this stuff is worth it, + * you can buy me a beer in return. + * + ***************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using Ultima.Helpers; + +namespace Ultima +{ + internal static class AnimationsUopLoader + { + private const int _maxAnimActions = 80; + private const int _maxDirections = 5; + + private static FileStream[] _uopFiles = new FileStream[6]; + private static readonly Dictionary _hashTable = new(); + private static readonly Dictionary _mobTypes = new(); + private static readonly Dictionary _sequenceReplacements = new(); + private static bool _isLoaded; + + private struct UopEntry + { + public int FileIndex; + public long Position; + public int CompressedSize; + public int DecompressedSize; + public short CompressionFlag; + } + + internal struct MobTypeInfo + { + public int Type; + public uint Flags; + } + + static AnimationsUopLoader() + { + Initialize(); + } + + public static bool IsLoaded => _isLoaded; + + public static void Reload() + { + if (_uopFiles != null) + { + foreach (var f in _uopFiles) + { + f?.Close(); + } + } + + _uopFiles = new FileStream[6]; + _hashTable.Clear(); + _mobTypes.Clear(); + _sequenceReplacements.Clear(); + _isLoaded = false; + + Initialize(); + } + + private static void Initialize() + { + LoadUopFiles(); + LoadMobTypes(); + LoadAnimationSequence(); + _isLoaded = _uopFiles.Any(f => f != null); + } + + private static void LoadUopFiles() + { + for (int i = 0; i < _uopFiles.Length; i++) + { + string path = Files.GetFilePath($"AnimationFrame{i + 1}.uop"); + if (path == null) + { + continue; + } + + try + { + _uopFiles[i] = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + BuildHashTable(_uopFiles[i], i); + } + catch + { + _uopFiles[i] = null; + } + } + } + + private static void BuildHashTable(FileStream fs, int fileIdx) + { + using var reader = new BinaryReader(fs, System.Text.Encoding.Default, leaveOpen: true); + + reader.BaseStream.Seek(0, SeekOrigin.Begin); + + if (reader.ReadUInt32() != 0x50594D) + { + return; + } + + reader.ReadUInt32(); // version + reader.ReadUInt32(); // format_timestamp + long nextBlock = reader.ReadInt64(); + reader.ReadUInt32(); // block_size + reader.ReadInt32(); // count + + reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin); + + do + { + int filesCount = reader.ReadInt32(); + nextBlock = reader.ReadInt64(); + + for (int i = 0; i < filesCount; i++) + { + long offset = reader.ReadInt64(); + int headerLength = reader.ReadInt32(); + int compressedLength = reader.ReadInt32(); + int decompressedLength = reader.ReadInt32(); + ulong hash = reader.ReadUInt64(); + reader.ReadUInt32(); // data_hash + short flag = reader.ReadInt16(); + + if (offset == 0) + { + continue; + } + + int dataSize = flag == 1 ? compressedLength : decompressedLength; + + _hashTable[hash] = new UopEntry + { + FileIndex = fileIdx, + Position = offset + headerLength, + CompressedSize = dataSize, + DecompressedSize = decompressedLength, + CompressionFlag = flag, + }; + } + + if (nextBlock == 0) + { + break; + } + + reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin); + } + while (true); + } + + private static void LoadMobTypes() + { + string path = Files.GetFilePath("mobtypes.txt"); + if (path == null) + { + return; + } + + string[] typeNames = + { + "monster", + "sea_monster", + "animal", + "human", + "equipment" + }; + + try + { + foreach (string rawLine in File.ReadLines(path)) + { + string line = rawLine.Trim(); + if (line.Length == 0 || line[0] == '#' || !char.IsDigit(line[0])) + { + continue; + } + + string[] parts = line.Split(new[] { '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length < 3) + { + continue; + } + + if (!int.TryParse(parts[0], out int id)) + { + continue; + } + + string typeName = parts[1].ToLowerInvariant(); + + string flagStr = parts[2]; + int commentIdx = flagStr.IndexOf('#'); + if (commentIdx == 0) + { + continue; + } + + if (commentIdx > 0) + { + flagStr = flagStr.Substring(0, commentIdx).Trim(); + } + + flagStr = flagStr.Replace("0x", "").Replace("0X", ""); + if (!uint.TryParse(flagStr, NumberStyles.HexNumber, null, out uint flags)) + { + continue; + } + + int typeIdx = Array.IndexOf(typeNames, typeName); + if (typeIdx < 0) + { + continue; + } + + _mobTypes[id] = new MobTypeInfo + { + Type = typeIdx, + Flags = 0x80000000u | flags, + }; + } + } + catch + { + // mobtypes.txt is optional; parsing failures are non-fatal + } + } + + private static void LoadAnimationSequence() + { + string path = Files.GetFilePath("AnimationSequence.uop"); + if (path == null) + { + return; + } + + try + { + using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + using var reader = new BinaryReader(fileStream); + + reader.BaseStream.Seek(0, SeekOrigin.Begin); + if (reader.ReadUInt32() != 0x50594D) + { + return; + } + + reader.ReadUInt32(); // version + reader.ReadUInt32(); // format_timestamp + long nextBlock = reader.ReadInt64(); + reader.ReadUInt32(); // block_size + reader.ReadInt32(); // count + + var seqEntries = new Dictionary(); + + reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin); + + do + { + int filesCount = reader.ReadInt32(); + nextBlock = reader.ReadInt64(); + + for (int i = 0; i < filesCount; i++) + { + long offset = reader.ReadInt64(); + int headerLength = reader.ReadInt32(); + int compressedLength = reader.ReadInt32(); + int decompressedLength = reader.ReadInt32(); + ulong hash = reader.ReadUInt64(); + reader.ReadUInt32(); // data_hash + short flag = reader.ReadInt16(); + + if (offset == 0) + { + continue; + } + + int dataSize = flag == 1 ? compressedLength : decompressedLength; + seqEntries[hash] = new UopEntry + { + FileIndex = -1, + Position = offset + headerLength, + CompressedSize = dataSize, + DecompressedSize = decompressedLength, + CompressionFlag = flag, + }; + } + + if (nextBlock == 0) + { + break; + } + + reader.BaseStream.Seek(nextBlock, SeekOrigin.Begin); + } + while (true); + + // Scan all plausible body IDs for sequence entries + for (int animId = 0; animId < Animations._maxAnimationValue; animId++) + { + ulong hash = UopUtils.HashFileName($"build/animationsequence/{animId:D8}.bin"); + if (!seqEntries.TryGetValue(hash, out var entry)) + { + continue; + } + + fileStream.Seek(entry.Position, SeekOrigin.Begin); + byte[] buffer = new byte[entry.CompressedSize]; + _ = fileStream.Read(buffer, 0, buffer.Length); + + if (entry.CompressionFlag >= 1) + { + var (ok, dec) = UopUtils.Decompress(buffer); + if (!ok) + { + continue; + } + + buffer = dec; + } + + ParseSequenceEntry(animId, buffer); + } + } + catch + { + // AnimationSequence.uop is optional; parsing failures are non-fatal + } + } + + private static void ParseSequenceEntry(int animId, byte[] data) + { + if (data.Length < 56) + { + return; + } + + using var memoryStream = new MemoryStream(data); + using var binaryReader = new BinaryReader(memoryStream); + + binaryReader.ReadUInt32(); // animId stored in file + binaryReader.BaseStream.Seek(48, SeekOrigin.Current); // skip 12 × u32 + + int replaces = binaryReader.ReadInt32(); + + var replacements = new int[_maxAnimActions]; + for (int i = 0; i < _maxAnimActions; i++) + { + replacements[i] = i; + } + + if (replaces != 48 && replaces != 68) + { + for (int k = 0; k < replaces; k++) + { + if (binaryReader.BaseStream.Position + 72 > binaryReader.BaseStream.Length) + { + break; + } + + int oldGroup = binaryReader.ReadInt32(); + uint frameCount = binaryReader.ReadUInt32(); + int newGroup = binaryReader.ReadInt32(); + + if (frameCount == 0 && oldGroup >= 0 && oldGroup < _maxAnimActions && newGroup >= 0) + { + replacements[oldGroup] = newGroup; + } + + binaryReader.BaseStream.Seek(60, SeekOrigin.Current); // skip remaining per-replacement fields + } + } + + _sequenceReplacements[animId] = replacements; + } + + public static bool IsUopBody(int body) + { + if (!_isLoaded) + { + return false; + } + + return _mobTypes.TryGetValue(body, out var info) && (info.Flags & 0x10000u) != 0; + } + + public static int GetAnimationType(int body) + { + return _mobTypes.TryGetValue(body, out var info) ? info.Type : 0; + } + + public static bool IsActionDefined(int body, int action) + { + if (!_isLoaded) + { + return false; + } + + int resolved = GetResolvedAction(body, action); + ulong hash = UopUtils.HashFileName($"build/animationlegacyframe/{body:D6}/{resolved:D2}.bin"); + return _hashTable.ContainsKey(hash); + } + + public static List GetDefinedActions(int body) + { + var result = new List(); + if (!_isLoaded) + { + return result; + } + + for (int i = 0; i < _maxAnimActions; i++) + { + if (IsActionDefined(body, i)) + { + result.Add(i); + } + } + + return result; + } + + public static IEnumerable GetAllUopBodyIds() + { + return _mobTypes + .Where(kv => (kv.Value.Flags & 0x10000u) != 0) + .Select(kv => kv.Key) + .OrderBy(id => id); + } + + public static IEnumerable GetAllMobTypeBodyIds() + { + return _mobTypes + .Keys + .OrderBy(id => id); + } + + public static string GetUopFileName(int body) + { + for (int action = 0; action < _maxAnimActions; action++) + { + ulong hash = UopUtils.HashFileName($"build/animationlegacyframe/{body:D6}/{action:D2}.bin"); + if (_hashTable.TryGetValue(hash, out var entry)) + { + return $"AnimationFrame{entry.FileIndex + 1}.uop"; + } + } + + return "AnimationFrame*.uop"; + } + + private static int GetResolvedAction(int body, int action) + { + if (_sequenceReplacements.TryGetValue(body, out int[] repl) && action < repl.Length) + { + return repl[action]; + } + + return action; + } + + public static AnimationFrame[] GetAnimation(int body, int action, int direction, + ref int hue, bool preserveHue, bool firstFrame) + { + if (!_isLoaded) + { + return null; + } + + int resolved = GetResolvedAction(body, action); + ulong hash = UopUtils.HashFileName($"build/animationlegacyframe/{body:D6}/{resolved:D2}.bin"); + + if (!_hashTable.TryGetValue(hash, out var entry)) + { + return null; + } + + bool flip = direction > 4; + int readDir = direction <= 4 ? direction : direction - ((direction - 4) * 2); + + byte[] data = ReadEntryData(entry); + if (data == null) + { + return null; + } + + AnimationFrame[] frames = ParseUopFrames(data, readDir, flip); + if (frames == null || frames.Length == 0) + { + return null; + } + + int hueIdx = (hue & 0x3FFF) - 1; + bool onlyGray = (hue & 0x8000) != 0; + if (hueIdx >= 0 && hueIdx < Hues.List.Length) + { + var hueObj = Hues.List[hueIdx]; + foreach (var frame in frames) + { + if (frame?.Bitmap != null && frame != AnimationFrame.Empty) + { + hueObj.ApplyTo(frame.Bitmap, onlyGray); + } + } + } + + if (firstFrame && frames.Length > 1) + { + return new[] { frames[0] }; + } + + return frames; + } + + private static byte[] ReadEntryData(UopEntry entry) + { + int idx = entry.FileIndex; + if (idx < 0 || idx >= _uopFiles.Length || _uopFiles[idx] == null) + { + return null; + } + + var fileStream = _uopFiles[idx]; + byte[] buffer; + + lock (fileStream) + { + fileStream.Seek(entry.Position, SeekOrigin.Begin); + buffer = new byte[entry.CompressedSize]; + _ = fileStream.Read(buffer, 0, buffer.Length); + } + + if (entry.CompressionFlag >= 1) + { + var (ok, data) = UopUtils.Decompress(buffer); + return ok ? data : null; + } + + return buffer; + } + + private static AnimationFrame[] ParseUopFrames(byte[] data, int direction, bool flip) + { + if (data.Length < 36) + { + return null; + } + + using var memoryStream = new MemoryStream(data); + using var reader = new BinaryReader(memoryStream); + + reader.BaseStream.Seek(32, SeekOrigin.Begin); + int frameCount = reader.ReadInt32(); + uint dataStart = reader.ReadUInt32(); + + if (frameCount <= 0 || dataStart >= data.Length) + { + return null; + } + + reader.BaseStream.Seek(dataStart, SeekOrigin.Begin); + + var headers = new List<(long pos, ushort frameId, uint pixelOffset)>(frameCount); + for (int i = 0; i < frameCount; i++) + { + long pos = reader.BaseStream.Position; + reader.ReadUInt16(); // group + ushort frameId = reader.ReadUInt16(); + reader.ReadInt64(); // unknown + uint pixelOffset = reader.ReadUInt32(); + headers.Add((pos, frameId, pixelOffset)); + } + + // Gap-fill missing frame IDs with placeholder entries + var filled = new List<(long pos, ushort frameId, uint pixelOffset)>(headers.Count); + int lastId = 1; + foreach (var (pos, frameId, pixelOffset) in headers) + { + while (frameId - lastId > 1) + { + lastId++; + filled.Add((0L, (ushort)lastId, 0u)); + } + + filled.Add((pos, frameId, pixelOffset)); + lastId = frameId; + } + + int realFrameCount = (int)Math.Round(filled.Count / (float)_maxDirections); + if (realFrameCount <= 0) + { + return null; + } + + var result = new List(); + var palette = new ushort[Animations.PaletteCapacity]; + + foreach (var (pos, frameId, pixelOffset) in filled) + { + int frameDir = (frameId - 1) / realFrameCount; + if (frameDir < direction) + { + continue; + } + + if (frameDir > direction) + { + break; + } + + if (pos == 0) + { + result.Add(AnimationFrame.Empty); + continue; + } + + reader.BaseStream.Seek(pos + pixelOffset, SeekOrigin.Begin); + + // Palette is ARGB1555 stored with bit 15 cleared; set alpha bit on all non-zero entries. + // Index 0 stays 0 (transparent); all others get bit 15 set to make them opaque. + for (int i = 0; i < Animations.PaletteCapacity; i++) + { + ushort raw = reader.ReadUInt16(); + palette[i] = raw == 0 ? (ushort)0 : (ushort)(raw | 0x8000); + } + + result.Add(new AnimationFrame(palette, reader, flip)); + } + + return result.Count > 0 ? result.ToArray() : null; + } + + } +} diff --git a/Ultima/BodyConverter.cs b/Ultima/BodyConverter.cs index ea76973..b6c22a7 100644 --- a/Ultima/BodyConverter.cs +++ b/Ultima/BodyConverter.cs @@ -14,6 +14,7 @@ public static class BodyConverter public static int[] Table2 { get; private set; } public static int[] Table3 { get; private set; } public static int[] Table4 { get; private set; } + public static int[] Table5 { get; private set; } static BodyConverter() { @@ -35,11 +36,13 @@ public static void Initialize() List list2 = new List(); List list3 = new List(); List list4 = new List(); + List list5 = new List(); int max1 = 0; int max2 = 0; int max3 = 0; int max4 = 0; + int max5 = 0; using (var ip = new StreamReader(path)) { @@ -84,6 +87,12 @@ public static void Initialize() anim5 = -1; } + int anim6 = -1; + if (split.Length > 5 && !int.TryParse(split[5], out anim6)) + { + anim6 = -1; + } + if (anim2 != -1) { if (anim2 == 68) @@ -132,6 +141,17 @@ public static void Initialize() list4.Add(original); list4.Add(anim5); } + + if (anim6 != -1) + { + if (original > max5) + { + max5 = original; + } + + list5.Add(original); + list5.Add(anim6); + } } catch { @@ -187,6 +207,18 @@ public static void Initialize() { Table4[list4[i]] = list4[i + 1]; } + + Table5 = new int[max5 + 1]; + + for (int i = 0; i < Table5.Length; ++i) + { + Table5[i] = -1; + } + + for (int i = 0; i < list5.Count; i += 2) + { + Table5[list5[i]] = list5[i + 1]; + } } /// @@ -215,6 +247,11 @@ public static bool Contains(int body) return true; } + if (Table5 != null && body >= 0 && body < Table5.Length && Table5[body] != -1) + { + return true; + } + return false; } @@ -248,6 +285,10 @@ public static bool Contains(int body) /// 5 /// Anim5.mul, Anim5.idx (ML) /// + /// + /// 6 + /// Anim6.mul, Anim6.idx (SA/HS) + /// /// /// public static int Convert(ref int body) @@ -288,13 +329,24 @@ public static int Convert(ref int body) if (Table4 != null && body >= 0 && body < Table4.Length) { int val = Table4[body]; + + if (val != -1) + { + body = val; + return 5; + } + } + + if (Table5 != null && body >= 0 && body < Table5.Length) + { + int val = Table5[body]; if (val == -1) { return 1; } body = val; - return 5; + return 6; } return 1; @@ -371,6 +423,20 @@ public static int GetTrueBody(int fileType, int index) } break; } + case 6: + { + if (Table5 != null && index >= 0) + { + for (int i = 0; i < Table5.Length; ++i) + { + if (Table5[i] == index) + { + return i; + } + } + } + break; + } } return -1; } diff --git a/Ultima/Files.cs b/Ultima/Files.cs index d6d38fa..e83490e 100644 --- a/Ultima/Files.cs +++ b/Ultima/Files.cs @@ -46,7 +46,16 @@ public static void FireFileSaveEvent() "anim4.mul", "anim5.idx", "anim5.mul", + "anim6.idx", + "anim6.mul", "animdata.mul", + "animationframe1.uop", + "animationframe2.uop", + "animationframe3.uop", + "animationframe4.uop", + "animationframe5.uop", + "animationframe6.uop", + "animationsequence.uop", "art.mul", "artidx.mul", "artlegacymul.uop", diff --git a/Ultima/Helpers/UopUtils.cs b/Ultima/Helpers/UopUtils.cs index 04b9d3e..86f8055 100644 --- a/Ultima/Helpers/UopUtils.cs +++ b/Ultima/Helpers/UopUtils.cs @@ -111,15 +111,13 @@ public static (bool success, byte[] data) Decompress(byte[] compressedData) try { - using (var compressedStream = new MemoryStream(compressedData)) - using (var zlibStream = new ZLibStream(compressedStream, CompressionMode.Decompress, false)) - using (var resultStream = new MemoryStream()) - { - zlibStream.CopyTo(resultStream); - resultStream.Flush(); - zlibStream.Close(); - return (true, resultStream.ToArray()); - } + using var compressedStream = new MemoryStream(compressedData); + using var zlibStream = new ZLibStream(compressedStream, CompressionMode.Decompress, false); + using var resultStream = new MemoryStream(); + zlibStream.CopyTo(resultStream); + resultStream.Flush(); + zlibStream.Close(); + return (true, resultStream.ToArray()); } catch (Exception) { @@ -130,7 +128,6 @@ public static (bool success, byte[] data) Decompress(byte[] compressedData) /// /// Method for compressing zlib byte arrays inside .uop /// - /// Input compressed array of bytes /// compressed byte[] data public static (bool success, byte[] compressedData) Compress(byte[] rawData) { @@ -141,15 +138,13 @@ public static (bool success, byte[] compressedData) Compress(byte[] rawData) try { - using (var dataStream = new MemoryStream(rawData)) - using (var resultStream = new MemoryStream()) - using (var zlibStream = new ZLibStream(resultStream, CompressionLevel.Optimal)) - { - dataStream.CopyTo(zlibStream); - zlibStream.Flush(); - zlibStream.Close(); - return (true, resultStream.ToArray()); - } + using var dataStream = new MemoryStream(rawData); + using var resultStream = new MemoryStream(); + using var zlibStream = new ZLibStream(resultStream, CompressionLevel.Optimal); + dataStream.CopyTo(zlibStream); + zlibStream.Flush(); + zlibStream.Close(); + return (true, resultStream.ToArray()); } catch (Exception) { diff --git a/UoFiddler.Controls/UserControls/AnimationListControl.Designer.cs b/UoFiddler.Controls/UserControls/AnimationListControl.Designer.cs index 7723218..b2eb7de 100644 --- a/UoFiddler.Controls/UserControls/AnimationListControl.Designer.cs +++ b/UoFiddler.Controls/UserControls/AnimationListControl.Designer.cs @@ -75,7 +75,7 @@ private void InitializeComponent() AnimateCheckBox = new System.Windows.Forms.CheckBox(); FacingBar = new System.Windows.Forms.TrackBar(); tabPage2 = new System.Windows.Forms.TabPage(); - listView = new System.Windows.Forms.ListView(); + listView = new UoFiddler.Controls.UserControls.TileView.TileViewControl(); statusStrip1 = new System.Windows.Forms.StatusStrip(); SettingsButton = new System.Windows.Forms.ToolStripDropDownButton(); sortAlphaToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); @@ -450,21 +450,28 @@ private void InitializeComponent() // // listView // - listView.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + listView.AutoScroll = true; + listView.AutoScrollMinSize = new System.Drawing.Size(0, 116); listView.Dock = System.Windows.Forms.DockStyle.Fill; - listView.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F); + listView.FocusIndex = -1; + listView.Font = new System.Drawing.Font("Segoe UI", 9F); listView.Location = new System.Drawing.Point(4, 3); listView.Margin = new System.Windows.Forms.Padding(0); listView.MultiSelect = false; listView.Name = "listView"; - listView.OwnerDraw = true; listView.Size = new System.Drawing.Size(480, 344); listView.TabIndex = 0; + listView.TileBackgroundColor = System.Drawing.SystemColors.Window; + listView.TileBorderColor = System.Drawing.Color.Gray; + listView.TileBorderWidth = 1F; + listView.TileFocusColor = System.Drawing.Color.DarkBlue; + listView.TileHighlightColor = System.Drawing.SystemColors.Highlight; + listView.TileMargin = new System.Windows.Forms.Padding(2, 2, 0, 0); + listView.TilePadding = new System.Windows.Forms.Padding(1); listView.TileSize = new System.Drawing.Size(81, 110); - listView.UseCompatibleStateImageBehavior = false; - listView.View = System.Windows.Forms.View.Tile; + listView.VirtualListSize = 1; + listView.ItemSelectionChanged += SelectChanged_listView; listView.DrawItem += ListViewDrawItem; - listView.SelectedIndexChanged += SelectChanged_listView; listView.MouseDoubleClick += ListView_DoubleClick; // // statusStrip1 @@ -631,7 +638,7 @@ private void InitializeComponent() private System.Windows.Forms.TabControl tabControl1; private System.Windows.Forms.TabPage tabPage1; private System.Windows.Forms.TabPage tabPage2; - private System.Windows.Forms.ListView listView; + private TileView.TileViewControl listView; private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1; private System.Windows.Forms.SplitContainer splitContainer2; private AnimatedPictureBox MainPictureBox; diff --git a/UoFiddler.Controls/UserControls/AnimationListControl.cs b/UoFiddler.Controls/UserControls/AnimationListControl.cs index 3a67635..0c51f30 100644 --- a/UoFiddler.Controls/UserControls/AnimationListControl.cs +++ b/UoFiddler.Controls/UserControls/AnimationListControl.cs @@ -22,6 +22,7 @@ using UoFiddler.Controls.Classes; using UoFiddler.Controls.Forms; using UoFiddler.Controls.Helpers; +using UoFiddler.Controls.UserControls.TileView; namespace UoFiddler.Controls.UserControls { @@ -142,6 +143,7 @@ public AnimationListControl() private bool _sortAlpha; private int _displayType; private bool _loaded; + private readonly List _listViewGraphics = new List(); /// /// ReLoads if loaded @@ -255,19 +257,26 @@ public void AddGraphic(int graphic, int type, string name) TreeViewMobs.Nodes[0].Nodes.Add(nodeParent); } - for (int i = 0; i < GetActionNames[type].GetLength(0); ++i) + if (Animations.IsUopBody(graphic)) { - if (!Animations.IsActionDefined(graphic, i, 0)) + AddUopActionNodes(nodeParent, graphic, type); + } + else + { + for (int i = 0; i < GetActionNames[type].GetLength(0); ++i) { - continue; - } + if (!Animations.IsActionDefined(graphic, i, 0)) + { + continue; + } - TreeNode node = new TreeNode($"{i} {GetActionNames[type][i]}") - { - Tag = i - }; + TreeNode node = new TreeNode($"{i} {GetActionNames[type][i]}") + { + Tag = i + }; - nodeParent.Nodes.Add(node); + nodeParent.Nodes.Add(node); + } } TreeViewMobs.TreeViewNodeSorter = !_sortAlpha @@ -500,80 +509,134 @@ private bool LoadXml() MessageBoxIcon.Warning); } + LoadFromMobTypes(); + return true; } - private void LoadListView() + private void LoadFromMobTypes() { - listView.BeginUpdate(); + TreeViewMobs.BeginUpdate(); try { - listView.Clear(); - foreach (TreeNode node in TreeViewMobs.Nodes[_displayType].Nodes) + foreach (int body in Animations.GetAllUopBodies()) { - ListViewItem item = new ListViewItem($"({((int[])node.Tag)[0]})", 0) + if (IsAlreadyDefined(body)) + { + continue; + } + + int type = Animations.GetUopAnimationType(body); + bool isEquip = type == 4; + int actionType = isEquip ? 3 : (type < 0 || type >= GetActionNames.Length ? 0 : type); + if (!isEquip && (type < 0 || type >= GetActionNames.Length)) + { + type = 0; + } + + string name = $"Body 0x{body:X}"; + + TreeNode nodeParent = new TreeNode($"{name} (0x{body:X})") { - Tag = ((int[])node.Tag)[0] + Tag = new[] { body, type }, + ToolTipText = Animations.GetFileName(body) }; - listView.Items.Add(item); + + TreeNode targetRoot = isEquip ? TreeViewMobs.Nodes[1] : TreeViewMobs.Nodes[0]; + targetRoot.Nodes.Add(nodeParent); + + AddUopActionNodes(nodeParent, body, actionType); } } finally { - listView.EndUpdate(); + TreeViewMobs.EndUpdate(); } } - private void SelectChanged_listView(object sender, EventArgs e) + private void AddUopActionNodes(TreeNode parent, int body, int actionType) { - if (listView.SelectedItems.Count > 0) + var definedActions = Animations.GetUopDefinedActions(body); + foreach (int i in definedActions) { - TreeViewMobs.SelectedNode = TreeViewMobs.Nodes[_displayType].Nodes[listView.SelectedItems[0].Index]; + string actionName = i < GetActionNames[actionType].Length + ? GetActionNames[actionType][i] + : $"Action{i}"; + + parent.Nodes.Add(new TreeNode($"{i} {actionName}") { Tag = i }); } } - private void ListView_DoubleClick(object sender, MouseEventArgs e) + private void LoadListView() { - tabControl1.SelectTab(tabPage1); + _listViewGraphics.Clear(); + foreach (TreeNode node in TreeViewMobs.Nodes[_displayType].Nodes) + { + _listViewGraphics.Add(((int[])node.Tag)[0]); + } + listView.VirtualListSize = _listViewGraphics.Count; } - private void ListViewDrawItem(object sender, DrawListViewItemEventArgs e) + private void SelectChanged_listView(object sender, ListViewItemSelectionChangedEventArgs e) { - int graphic = (int)e.Item.Tag; - int hue = 0; - Bitmap bmp = Animations.GetAnimation(graphic, 0, 1, ref hue, false, true)?[0].Bitmap; - - if (bmp == null) + if (!e.IsSelected) { return; } + TreeViewMobs.SelectedNode = TreeViewMobs.Nodes[_displayType].Nodes[e.ItemIndex]; + } - int width = bmp.Width; - int height = bmp.Height; + private void ListView_DoubleClick(object sender, MouseEventArgs e) + { + tabControl1.SelectTab(tabPage1); + } - if (width > e.Bounds.Width) + private void ListViewDrawItem(object sender, TileViewControl.DrawTileListItemEventArgs e) + { + if (e.Index < 0 || e.Index >= _listViewGraphics.Count) { - width = e.Bounds.Width; + return; } - if (height > e.Bounds.Height) - { - height = e.Bounds.Height; - } + int graphic = _listViewGraphics[e.Index]; + Point itemPoint = new Point(e.Bounds.X + listView.TilePadding.Left, e.Bounds.Y + listView.TilePadding.Top); + Rectangle tileRect = new Rectangle(itemPoint, listView.TileSize); + var previousClip = e.Graphics.Clip; + e.Graphics.Clip = new Region(tileRect); - e.Graphics.DrawImage(bmp, e.Bounds.X, e.Bounds.Y, width, height); - e.DrawText(TextFormatFlags.Bottom | TextFormatFlags.HorizontalCenter); - if (listView.SelectedItems.Contains(e.Item)) + if (!listView.SelectedIndices.Contains(e.Index)) { - e.DrawFocusRectangle(); + using var bgBrush = new SolidBrush(listView.BackColor); + e.Graphics.FillRectangle(bgBrush, tileRect); } - else + + int hue = 0; + Bitmap bmp = Animations.GetAnimation(graphic, 0, 1, ref hue, false, true)?[0].Bitmap; + if (bmp != null) { - using (var pen = new Pen(Color.Gray)) + int maxW = tileRect.Width; + int maxH = tileRect.Height - 18; + int drawWidth = bmp.Width; + int drawHeight = bmp.Height; + if (drawWidth > maxW || drawHeight > maxH) { - e.Graphics.DrawRectangle(pen, e.Bounds.X, e.Bounds.Y, e.Bounds.Width, e.Bounds.Height); + float scale = Math.Min((float)maxW / drawWidth, (float)maxH / drawHeight); + drawWidth = (int)(drawWidth * scale); + drawHeight = (int)(drawHeight * scale); } + int drawX = tileRect.X + (tileRect.Width - drawWidth) / 2; + int drawY = tileRect.Y + Math.Max(0, (tileRect.Height - 18 - drawHeight) / 2); + e.Graphics.DrawImage(bmp, drawX, drawY, drawWidth, drawHeight); } + + using var stringFormat = new StringFormat(); + stringFormat.Alignment = StringAlignment.Center; + stringFormat.LineAlignment = StringAlignment.Far; + + e.Graphics.DrawString($"({graphic})", listView.Font, Brushes.Black, + new RectangleF(tileRect.X, tileRect.Y, tileRect.Width, tileRect.Height), stringFormat); + + e.Graphics.Clip = previousClip; } private HuePopUpForm _showForm; @@ -621,7 +684,13 @@ private void Frames_ListView_DrawItem(object sender, DrawListViewItemEventArgs e return; } - Bitmap bmp = MainPictureBox.Frames[(int)e.Item.Tag].Bitmap; + int frameIndex = (int)e.Item.Tag; + if (frameIndex < 0 || frameIndex >= MainPictureBox.Frames.Count) + { + return; + } + + Bitmap bmp = MainPictureBox.Frames[frameIndex].Bitmap; int width = bmp.Width; int height = bmp.Height; diff --git a/UoFiddler/Animationlist.xml b/UoFiddler/Animationlist.xml index 13bc101..5832100 100644 --- a/UoFiddler/Animationlist.xml +++ b/UoFiddler/Animationlist.xml @@ -1,763 +1,1324 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 280cafa392295acce63294690ddfcd987f1c75ab Mon Sep 17 00:00:00 2001 From: AsY!um- <377468+AsYlum-@users.noreply.github.com> Date: Thu, 23 Apr 2026 20:11:18 +0200 Subject: [PATCH 5/5] Update change log and version. --- UoFiddler/Forms/AboutBoxForm.resx | 8 +++++++- UoFiddler/UoFiddler.csproj | 6 +++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/UoFiddler/Forms/AboutBoxForm.resx b/UoFiddler/Forms/AboutBoxForm.resx index fa2fb2a..15b32cc 100644 --- a/UoFiddler/Forms/AboutBoxForm.resx +++ b/UoFiddler/Forms/AboutBoxForm.resx @@ -118,7 +118,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - Version 4.18.2 + Version 4.19.0 +- Added support for previewing contents of animations in anim6.mul and AnimationFrame1-6.uop (no export or edit option for uop yet). +- Fixed possible crash and slowdown during tiledata CSV import from newer client to older client. +- More preview boxes now support change background color and use background color set in Options. +- Small adjustments to RadarCol compare layout. + +Version 4.18.2 - Fixed WSC multi import where file has absolute coordinates. Now all coordinates are converted to relative ones. - Added DynamicItems.xml with list of items that should be marked as dynamic when importing multis from WSC. - Added support for viewing and importing Multicollection.uop multis (there is no save option for now). diff --git a/UoFiddler/UoFiddler.csproj b/UoFiddler/UoFiddler.csproj index e2b637a..ce5756b 100644 --- a/UoFiddler/UoFiddler.csproj +++ b/UoFiddler/UoFiddler.csproj @@ -9,9 +9,9 @@ UoFiddler UoFiddler Copyright © 2026 - 4.18.2 - 4.18.2 - 4.18.2 + 4.19.0 + 4.19.0 + 4.19.0 true