From da4b2925888435c411d43f5cd76cbaff8af8aaf4 Mon Sep 17 00:00:00 2001 From: Kurt Date: Sun, 29 Mar 2020 17:12:41 -0700 Subject: [PATCH] Add villager item editing Furniture array is inside the villager's item list; there's another list of a different format in the offsets below probably just a struct within another struct, like struct villagerItem { item; (0x08 bytes) metadata; (0x24 bytes) } --- NHSE.Core/Structures/Item/Item.cs | 28 ++++++++++------------- NHSE.Core/Structures/Villager/Villager.cs | 7 ++++++ NHSE.Core/Util/StructConverter.cs | 17 ++++++++++++++ NHSE.WinForms/Editor.Designer.cs | 13 +++++++++++ NHSE.WinForms/Editor.cs | 12 ++++++++++ 5 files changed, 61 insertions(+), 16 deletions(-) diff --git a/NHSE.Core/Structures/Item/Item.cs b/NHSE.Core/Structures/Item/Item.cs index 2eb82ca..d5c5845 100644 --- a/NHSE.Core/Structures/Item/Item.cs +++ b/NHSE.Core/Structures/Item/Item.cs @@ -4,7 +4,7 @@ namespace NHSE.Core { [StructLayout(LayoutKind.Sequential)] - public sealed class Item + public class Item { public static readonly Item NO_ITEM = new Item {ItemId = NONE}; public const ushort NONE = 0xFFFE; @@ -55,21 +55,8 @@ public void CopyFrom(Item item) UseCount = item.UseCount; } - public static Item[] GetArray(byte[] data) - { - var result = new Item[data.Length / SIZE]; - for (int i = 0; i < result.Length; i++) - result[i] = data.Slice(i * SIZE, SIZE).ToClass(); - return result; - } - - public static byte[] SetArray(IReadOnlyList data) - { - var result = new byte[data.Count * SIZE]; - for (int i = 0; i < data.Count; i++) - data[i].ToBytesClass().CopyTo(result, i * SIZE); - return result; - } + public static Item[] GetArray(byte[] data) => data.GetArray(SIZE); + public static byte[] SetArray(IReadOnlyList data) => data.SetArray(SIZE); public ushort GetInventoryNameFromFlags() { @@ -85,4 +72,13 @@ public ushort GetInventoryNameFromFlags() }; } } + + [StructLayout(LayoutKind.Sequential)] + public sealed class VillagerItem : Item + { + public new const int SIZE = 0x2C; + public uint U08, U0C, U10, U14, U18, U1C, U20, U24, U28; + public new static VillagerItem[] GetArray(byte[] data) => data.GetArray(SIZE); + public static byte[] SetArray(IReadOnlyList data) => data.SetArray(SIZE); + } } diff --git a/NHSE.Core/Structures/Villager/Villager.cs b/NHSE.Core/Structures/Villager/Villager.cs index ed85ae4..f2a5ce3 100644 --- a/NHSE.Core/Structures/Villager/Villager.cs +++ b/NHSE.Core/Structures/Villager/Villager.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Text; namespace NHSE.Core @@ -65,6 +66,12 @@ public string CatchPhrase set => GetBytes(value, 2 * 12).CopyTo(Data, 0x10014); } + public IReadOnlyList Furniture + { + get => VillagerItem.GetArray(Data.Slice(0x105EC, 16 * VillagerItem.SIZE)); + set => VillagerItem.SetArray(value).CopyTo(Data, 0x105EC); + } + public override string ToString() => InternalName; public string InternalName => VillagerUtil.GetInternalVillagerName((VillagerSpecies) Species, Variant); public int Gender => ((int)Personality / 4) & 1; // 0 = M, 1 = F diff --git a/NHSE.Core/Util/StructConverter.cs b/NHSE.Core/Util/StructConverter.cs index 59fe72b..5c702c4 100644 --- a/NHSE.Core/Util/StructConverter.cs +++ b/NHSE.Core/Util/StructConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; namespace NHSE.Core @@ -45,5 +46,21 @@ internal static class StructConverter Marshal.FreeHGlobal(ptr); return arr; } + + public static T[] GetArray(this byte[] data, int size) where T : class + { + var result = new T[data.Length / size]; + for (int i = 0; i < result.Length; i++) + result[i] = data.Slice(i * size, size).ToClass(); + return result; + } + + public static byte[] SetArray(this IReadOnlyList data, int size) where T : class + { + var result = new byte[data.Count * size]; + for (int i = 0; i < data.Count; i++) + data[i].ToBytesClass().CopyTo(result, i * size); + return result; + } } } diff --git a/NHSE.WinForms/Editor.Designer.cs b/NHSE.WinForms/Editor.Designer.cs index 90e8b4d..d9905eb 100644 --- a/NHSE.WinForms/Editor.Designer.cs +++ b/NHSE.WinForms/Editor.Designer.cs @@ -74,6 +74,7 @@ private void InitializeComponent() this.B_RecycleBin = new System.Windows.Forms.Button(); this.Menu_LoadDecrypted = new System.Windows.Forms.ToolStripMenuItem(); this.B_LoadVillager = new System.Windows.Forms.Button(); + this.B_EditFurniture = new System.Windows.Forms.Button(); this.Menu_Editor.SuspendLayout(); this.TC_Editors.SuspendLayout(); this.Tab_Players.SuspendLayout(); @@ -353,6 +354,7 @@ private void InitializeComponent() // // Tab_Villagers // + this.Tab_Villagers.Controls.Add(this.B_EditFurniture); this.Tab_Villagers.Controls.Add(this.B_LoadVillager); this.Tab_Villagers.Controls.Add(this.B_DumpVillager); this.Tab_Villagers.Controls.Add(this.L_ExternalName); @@ -566,6 +568,16 @@ private void InitializeComponent() this.B_LoadVillager.UseVisualStyleBackColor = true; this.B_LoadVillager.Click += new System.EventHandler(this.B_LoadVillager_Click); // + // B_EditFurniture + // + this.B_EditFurniture.Location = new System.Drawing.Point(218, 168); + this.B_EditFurniture.Name = "B_EditFurniture"; + this.B_EditFurniture.Size = new System.Drawing.Size(100, 40); + this.B_EditFurniture.TabIndex = 26; + this.B_EditFurniture.Text = "Edit Furniture"; + this.B_EditFurniture.UseVisualStyleBackColor = true; + this.B_EditFurniture.Click += new System.EventHandler(this.B_EditFurniture_Click); + // // Editor // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -648,6 +660,7 @@ private void InitializeComponent() private System.Windows.Forms.Button B_EditPlayerStorage; private System.Windows.Forms.ToolStripMenuItem Menu_LoadDecrypted; private System.Windows.Forms.Button B_LoadVillager; + private System.Windows.Forms.Button B_EditFurniture; } } diff --git a/NHSE.WinForms/Editor.cs b/NHSE.WinForms/Editor.cs index b7d4aeb..d33bdb8 100644 --- a/NHSE.WinForms/Editor.cs +++ b/NHSE.WinForms/Editor.cs @@ -351,5 +351,17 @@ private void B_LoadVillager_Click(object sender, EventArgs e) SAV.Main.SetVillager(v, VillagerIndex); } + + private void B_EditFurniture_Click(object sender, EventArgs e) + { + var v = SAV.Main.GetVillager(VillagerIndex); + var items = v.Furniture; + using var editor = new PlayerItemEditor(items, 8, 2); + if (editor.ShowDialog() != DialogResult.OK) + return; + + v.Furniture = items; + SAV.Main.SetVillager(v, VillagerIndex); + } } }