mirror of
https://github.com/kwsch/NHSE.git
synced 2026-08-20 17:45:47 -05:00
Add player & villager house dump/load
share your house, but not your toothbrush!
This commit is contained in:
@@ -44,6 +44,34 @@ public IReadOnlyList<Building> Buildings
|
||||
set => Building.SetArray(value).CopyTo(Data, Offsets.Buildings);
|
||||
}
|
||||
|
||||
public PlayerHouse GetPlayerHouse(int index)
|
||||
{
|
||||
if ((uint)index >= MainSaveOffsets.PlayerCount)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
return Data.Slice(Offsets.PlayerHouseList + (index * PlayerHouse.SIZE), PlayerHouse.SIZE).ToClass<PlayerHouse>();
|
||||
}
|
||||
|
||||
public void SetPlayerHouse(PlayerHouse h, int index)
|
||||
{
|
||||
if ((uint)index >= MainSaveOffsets.PlayerCount)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
h.ToBytesClass().CopyTo(Data, Offsets.PlayerHouseList + (index * PlayerHouse.SIZE));
|
||||
}
|
||||
|
||||
public VillagerHouse GetVillagerHouse(int index)
|
||||
{
|
||||
if ((uint)index >= MainSaveOffsets.VillagerCount)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
return Data.Slice(Offsets.NpcHouseList + (index * VillagerHouse.SIZE), VillagerHouse.SIZE).ToClass<VillagerHouse>();
|
||||
}
|
||||
|
||||
public void SetVillagerHouse(VillagerHouse h, int index)
|
||||
{
|
||||
if ((uint)index >= MainSaveOffsets.VillagerCount)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
h.ToBytesClass().CopyTo(Data, Offsets.NpcHouseList + (index * VillagerHouse.SIZE));
|
||||
}
|
||||
|
||||
public TurnipStonk Turnips
|
||||
{
|
||||
get => Data.Slice(Offsets.TurnipExchange, TurnipStonk.SIZE).ToClass<TurnipStonk>();
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace NHSE.Core
|
||||
/// </summary>
|
||||
public abstract class MainSaveOffsets
|
||||
{
|
||||
public const int PlayerCount = 8;
|
||||
|
||||
public abstract int Villager { get; }
|
||||
public const int VillagerSize = 0x12AB0;
|
||||
public const int VillagerCount = 10;
|
||||
@@ -22,9 +24,12 @@ public abstract class MainSaveOffsets
|
||||
|
||||
public abstract int TurnipExchange { get; }
|
||||
|
||||
public abstract int EventFlagLand { get; }
|
||||
public abstract int FieldItem { get; }
|
||||
public abstract int Acres { get; }
|
||||
public abstract int Terrain { get; }
|
||||
public abstract int PlayerHouseList { get; }
|
||||
public abstract int NpcHouseList { get; }
|
||||
|
||||
public static MainSaveOffsets GetOffsets(FileHeaderInfo Info)
|
||||
{
|
||||
|
||||
@@ -7,10 +7,16 @@ public class MainSaveOffsets10 : MainSaveOffsets
|
||||
{
|
||||
public override int Villager => 0x110;
|
||||
public override int Patterns => 0x1D72F0;
|
||||
|
||||
public override int EventFlagLand => FieldItem - 0x800;
|
||||
public override int FieldItem => 0x2018FC;
|
||||
public override int Terrain => Buildings - 0x24C00; // dunno where exactly it starts???
|
||||
public override int Terrain => Buildings - 0x24C00;
|
||||
public override int Buildings => 0x2D0EFC;
|
||||
public override int Acres => 0x2D1294;
|
||||
|
||||
public override int PlayerHouseList => FieldItem + 0xDAA2C;
|
||||
public override int NpcHouseList => PlayerHouseList + (PlayerCount * PlayerHouse.SIZE);
|
||||
|
||||
public override int TurnipExchange => 0x4118C0;
|
||||
public override int RecycleBin => 0xABC000; // yep.
|
||||
}
|
||||
|
||||
@@ -7,10 +7,18 @@ public class MainSaveOffsets11 : MainSaveOffsets
|
||||
{
|
||||
public override int Villager => 0x120;
|
||||
public override int Patterns => 0x1D7310; // +0x20 from v1.0
|
||||
public override int FieldItem => 0x20191C; // +0x20 from v1.0
|
||||
public override int Terrain => Buildings - 0x24C00; // dunno where exactly it starts??? // +0x20 from v1.0
|
||||
|
||||
public override int EventFlagLand => FieldItem - 0x800;
|
||||
|
||||
// GSaveMainField
|
||||
public override int FieldItem => 0x20191C; // +0x20 from v1.0 // Layer 1&2, and 2*0x1500
|
||||
public override int Terrain => Buildings - 0x24C00;// +0x20 from v1.0 // LandMakingMap
|
||||
public override int Buildings => 0x2D0F1C; // +0x20 from v1.0
|
||||
public override int Acres => 0x2D12B4; // +0x20 from v1.0
|
||||
|
||||
public override int PlayerHouseList => FieldItem + 0xDAA2C;
|
||||
public override int NpcHouseList => PlayerHouseList + (PlayerCount * PlayerHouse.SIZE);
|
||||
|
||||
public override int TurnipExchange => 0x412060; // +0x7A0 from v1.0
|
||||
public override int RecycleBin => 0xABDE70; // +0x1E70 from v1.0
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace NHSE.Core
|
||||
@@ -16,7 +17,7 @@ public static class GameFileDumper
|
||||
/// <param name="path">Path to dump to</param>
|
||||
public static void Dump(this HorizonSave sav, string path)
|
||||
{
|
||||
sav.Main.Dump(path);
|
||||
sav.Main.DumpVillagerHouses(path);
|
||||
foreach (var p in sav.Players)
|
||||
{
|
||||
var dir = Path.Combine(path, p.DirectoryName);
|
||||
@@ -53,7 +54,54 @@ private static void Dump(string path, byte[] data, string name)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumps all villagers in their decrypted state to the requested <see cref="path"/>.
|
||||
/// Dumps all villager houses to the requested <see cref="path"/>.
|
||||
/// </summary>
|
||||
/// <param name="sav">Save Data to dump from</param>
|
||||
/// <param name="path">Path to dump to</param>
|
||||
public static void DumpPlayerHouses(this HorizonSave sav, string path)
|
||||
{
|
||||
var count = Math.Min(sav.Players.Length, MainSaveOffsets.PlayerCount);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var p = sav.Players[i];
|
||||
var h = sav.Main.GetPlayerHouse(i);
|
||||
h.Dump(path, p.Personal);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Dump(this PlayerHouse h, string path, Personal p)
|
||||
{
|
||||
var name = GameInfo.Strings.GetVillager(p.PlayerName);
|
||||
var dest = Path.Combine(path, $"{name}.nhph");
|
||||
var data = h.ToBytesClass();
|
||||
File.WriteAllBytes(dest, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumps all villager houses to the requested <see cref="path"/>.
|
||||
/// </summary>
|
||||
/// <param name="sav">Save Data to dump from</param>
|
||||
/// <param name="path">Path to dump to</param>
|
||||
public static void DumpVillagerHouses(this MainSave sav, string path)
|
||||
{
|
||||
for (int i = 0; i < MainSaveOffsets.VillagerCount; i++)
|
||||
{
|
||||
var v = sav.GetVillager(i);
|
||||
var h = sav.GetVillagerHouse(i);
|
||||
h.Dump(path, v);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Dump(this VillagerHouse h, string path, Villager v)
|
||||
{
|
||||
var name = GameInfo.Strings.GetVillager(v.InternalName);
|
||||
var dest = Path.Combine(path, $"{name}.nhvh");
|
||||
var data = h.ToBytesClass();
|
||||
File.WriteAllBytes(dest, data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumps all villagers to the requested <see cref="path"/>.
|
||||
/// </summary>
|
||||
/// <param name="villagers">Data to dump from</param>
|
||||
/// <param name="path">Path to dump to</param>
|
||||
@@ -71,7 +119,7 @@ private static void DumpVillager(this Villager v, string path)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dumps all villagers in their decrypted state to the requested <see cref="path"/>.
|
||||
/// Dumps all designs to the requested <see cref="path"/>.
|
||||
/// </summary>
|
||||
/// <param name="sav">Save Data to dump from</param>
|
||||
/// <param name="path">Path to dump to</param>
|
||||
|
||||
21
NHSE.Core/Structures/Villager/GSaveItemName.cs
Normal file
21
NHSE.Core/Structures/Villager/GSaveItemName.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NHSE.Core
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, Size = SIZE, Pack = 1)]
|
||||
public struct GSaveItemName
|
||||
{
|
||||
public const int SIZE = 0x08;
|
||||
[field: FieldOffset(0x00)] public ushort UniqueID { get; set; }
|
||||
[field: FieldOffset(0x02)] public byte SystemParam { get; set; }
|
||||
[field: FieldOffset(0x03)] public byte AdditionalParam { get; set; }
|
||||
[field: FieldOffset(0x04)] public uint FreeParam { get; set; }
|
||||
|
||||
// ReSharper disable once NonReadonlyMemberInGetHashCode
|
||||
public override int GetHashCode() => UniqueID;
|
||||
public override bool Equals(object obj) => obj is GSaveItemName i && i.Equals(this);
|
||||
public bool Equals(GSaveItemName obj) => obj.UniqueID == UniqueID && obj.SystemParam == SystemParam && obj.AdditionalParam == AdditionalParam;
|
||||
public static bool operator ==(GSaveItemName left, GSaveItemName right) => left.Equals(right);
|
||||
public static bool operator !=(GSaveItemName left, GSaveItemName right) => !(left == right);
|
||||
}
|
||||
}
|
||||
29
NHSE.Core/Structures/Villager/IHouseInfo.cs
Normal file
29
NHSE.Core/Structures/Villager/IHouseInfo.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace NHSE.Core
|
||||
{
|
||||
public interface IHouseInfo
|
||||
{
|
||||
uint HouseLevel { get; set; }
|
||||
ushort WallUniqueID { get; set; }
|
||||
ushort RoofUniqueID { get; set; }
|
||||
ushort DoorUniqueID { get; set; }
|
||||
ushort OrderWallUniqueID { get; set; }
|
||||
ushort OrderRoofUniqueID { get; set; }
|
||||
ushort OrderDoorUniqueID { get; set; }
|
||||
GSaveItemName DoorDecoItemName { get; set; }
|
||||
}
|
||||
|
||||
public static class HouseInfoExtensions
|
||||
{
|
||||
public static void CopyFrom(this IHouseInfo dest, IHouseInfo src)
|
||||
{
|
||||
dest.HouseLevel = src.HouseLevel;
|
||||
dest.WallUniqueID = src.WallUniqueID;
|
||||
dest.RoofUniqueID = src.RoofUniqueID;
|
||||
dest.DoorUniqueID = src.DoorUniqueID;
|
||||
dest.OrderWallUniqueID = src.OrderWallUniqueID;
|
||||
dest.OrderRoofUniqueID = src.OrderRoofUniqueID;
|
||||
dest.OrderDoorUniqueID = src.OrderDoorUniqueID;
|
||||
dest.DoorDecoItemName = src.DoorDecoItemName;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
NHSE.Core/Structures/Villager/PlayerHouse.cs
Normal file
23
NHSE.Core/Structures/Villager/PlayerHouse.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace NHSE.Core
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, Size = SIZE, Pack = 4)]
|
||||
public class PlayerHouse : IHouseInfo
|
||||
{
|
||||
public const int SIZE = 0x26400;
|
||||
|
||||
[field: FieldOffset(0x000)] public uint HouseLevel { get; set; }
|
||||
[field: FieldOffset(0x004)] public ushort WallUniqueID { get; set; }
|
||||
[field: FieldOffset(0x006)] public ushort RoofUniqueID { get; set; }
|
||||
[field: FieldOffset(0x008)] public ushort DoorUniqueID { get; set; }
|
||||
[field: FieldOffset(0x00A)] public ushort OrderWallUniqueID { get; set; }
|
||||
[field: FieldOffset(0x00C)] public ushort OrderRoofUniqueID { get; set; }
|
||||
[field: FieldOffset(0x00E)] public ushort OrderDoorUniqueID { get; set; }
|
||||
|
||||
[field: FieldOffset(0x263D4)] public GSaveItemName DoorDecoItemName { get; set; }
|
||||
|
||||
[field: FieldOffset(0x263E0)] public GSaveItemName PostItemName { get; set; }
|
||||
[field: FieldOffset(0x263E8)] public GSaveItemName OrderPostItemName { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
namespace NHSE.Core
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, Size = SIZE, Pack = 4)]
|
||||
public class VillagerHouse
|
||||
{
|
||||
public class VillagerHouse : IHouseInfo
|
||||
{
|
||||
public const int SIZE = 0x1D4;
|
||||
public const int ItemCount = 36;
|
||||
|
||||
@@ -23,21 +23,4 @@ public class VillagerHouse
|
||||
[field: FieldOffset(0x1C8)] public GSaveItemName DoorDecoItemName { get; set; }
|
||||
[field: FieldOffset(0x1D0)] public sbyte BuildPlayer { get; set; }
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = SIZE, Pack = 1)]
|
||||
public struct GSaveItemName
|
||||
{
|
||||
public const int SIZE = 0x08;
|
||||
[field: FieldOffset(0x00)] public ushort UniqueID { get; set; }
|
||||
[field: FieldOffset(0x02)] public byte SystemParam { get; set; }
|
||||
[field: FieldOffset(0x03)] public byte AdditionalParam { get; set; }
|
||||
[field: FieldOffset(0x04)] public uint FreeParam { get; set; }
|
||||
|
||||
// ReSharper disable once NonReadonlyMemberInGetHashCode
|
||||
public override int GetHashCode() => UniqueID;
|
||||
public override bool Equals(object obj) => obj is GSaveItemName i && i.Equals(this);
|
||||
public bool Equals(GSaveItemName obj) => obj.UniqueID == UniqueID && obj.SystemParam == SystemParam && obj.AdditionalParam == AdditionalParam;
|
||||
public static bool operator ==(GSaveItemName left, GSaveItemName right) => left.Equals(right);
|
||||
public static bool operator !=(GSaveItemName left, GSaveItemName right) => !(left == right);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ public class MarshalTests
|
||||
[Fact] public void MarshalTurnip() => MarshalTest<TurnipStonk>(TurnipStonk.SIZE);
|
||||
[Fact] public void MarshalBuilding() => MarshalTest<Building>(Building.SIZE);
|
||||
[Fact] public void MarshalVillagerHouse() => MarshalTest<VillagerHouse>(VillagerHouse.SIZE);
|
||||
[Fact] public void MarshalPlayerHouse() => MarshalTest<PlayerHouse>(PlayerHouse.SIZE);
|
||||
|
||||
[Fact] public void MarshalVillagerHouseItem() => MarshalTestS<VillagerHouseItem>(VillagerHouseItem.SIZE);
|
||||
[Fact] public void MarshalGSaveItemName() => MarshalTestS<GSaveItemName>(GSaveItemName.SIZE);
|
||||
|
||||
30
NHSE.WinForms/Controls/VillagerEditor.Designer.cs
generated
30
NHSE.WinForms/Controls/VillagerEditor.Designer.cs
generated
@@ -46,6 +46,8 @@ private void InitializeComponent()
|
||||
this.PB_Villager = new System.Windows.Forms.PictureBox();
|
||||
this.L_VillagerID = new System.Windows.Forms.Label();
|
||||
this.NUD_Villager = new System.Windows.Forms.NumericUpDown();
|
||||
this.B_LoadHouse = new System.Windows.Forms.Button();
|
||||
this.B_DumpHouse = new System.Windows.Forms.Button();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_Variant)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_Species)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.PB_Villager)).BeginInit();
|
||||
@@ -54,7 +56,7 @@ private void InitializeComponent()
|
||||
//
|
||||
// B_EditVillagerFlags
|
||||
//
|
||||
this.B_EditVillagerFlags.Location = new System.Drawing.Point(297, 165);
|
||||
this.B_EditVillagerFlags.Location = new System.Drawing.Point(297, 119);
|
||||
this.B_EditVillagerFlags.Name = "B_EditVillagerFlags";
|
||||
this.B_EditVillagerFlags.Size = new System.Drawing.Size(92, 40);
|
||||
this.B_EditVillagerFlags.TabIndex = 46;
|
||||
@@ -74,7 +76,7 @@ private void InitializeComponent()
|
||||
//
|
||||
// B_EditFurniture
|
||||
//
|
||||
this.B_EditFurniture.Location = new System.Drawing.Point(199, 165);
|
||||
this.B_EditFurniture.Location = new System.Drawing.Point(199, 119);
|
||||
this.B_EditFurniture.Name = "B_EditFurniture";
|
||||
this.B_EditFurniture.Size = new System.Drawing.Size(92, 40);
|
||||
this.B_EditFurniture.TabIndex = 44;
|
||||
@@ -242,10 +244,32 @@ private void InitializeComponent()
|
||||
0});
|
||||
this.NUD_Villager.ValueChanged += new System.EventHandler(this.LoadVillager);
|
||||
//
|
||||
// B_LoadHouse
|
||||
//
|
||||
this.B_LoadHouse.Location = new System.Drawing.Point(297, 165);
|
||||
this.B_LoadHouse.Name = "B_LoadHouse";
|
||||
this.B_LoadHouse.Size = new System.Drawing.Size(92, 40);
|
||||
this.B_LoadHouse.TabIndex = 48;
|
||||
this.B_LoadHouse.Text = "Load House";
|
||||
this.B_LoadHouse.UseVisualStyleBackColor = true;
|
||||
this.B_LoadHouse.Click += new System.EventHandler(this.B_LoadHouse_Click);
|
||||
//
|
||||
// B_DumpHouse
|
||||
//
|
||||
this.B_DumpHouse.Location = new System.Drawing.Point(199, 165);
|
||||
this.B_DumpHouse.Name = "B_DumpHouse";
|
||||
this.B_DumpHouse.Size = new System.Drawing.Size(92, 40);
|
||||
this.B_DumpHouse.TabIndex = 47;
|
||||
this.B_DumpHouse.Text = "Dump House";
|
||||
this.B_DumpHouse.UseVisualStyleBackColor = true;
|
||||
this.B_DumpHouse.Click += new System.EventHandler(this.B_DumpHouse_Click);
|
||||
//
|
||||
// VillagerEditor
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.Controls.Add(this.B_LoadHouse);
|
||||
this.Controls.Add(this.B_DumpHouse);
|
||||
this.Controls.Add(this.B_EditVillagerFlags);
|
||||
this.Controls.Add(this.CHK_VillagerMovingOut);
|
||||
this.Controls.Add(this.B_EditFurniture);
|
||||
@@ -295,5 +319,7 @@ private void InitializeComponent()
|
||||
private System.Windows.Forms.PictureBox PB_Villager;
|
||||
private System.Windows.Forms.Label L_VillagerID;
|
||||
private System.Windows.Forms.NumericUpDown NUD_Villager;
|
||||
private System.Windows.Forms.Button B_LoadHouse;
|
||||
private System.Windows.Forms.Button B_DumpHouse;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,19 @@ public partial class VillagerEditor : UserControl
|
||||
{
|
||||
public Villager[] Villagers;
|
||||
public IVillagerOrigin Origin;
|
||||
private readonly MainSave SAV;
|
||||
private int VillagerIndex = -1;
|
||||
|
||||
public VillagerEditor(Villager[] villagers, IVillagerOrigin origin)
|
||||
public VillagerEditor(Villager[] villagers, IVillagerOrigin origin, MainSave sav, bool hasHouses)
|
||||
{
|
||||
Villagers = villagers;
|
||||
Origin = origin;
|
||||
SAV = sav;
|
||||
InitializeComponent();
|
||||
LoadVillagers();
|
||||
|
||||
if (!hasHouses)
|
||||
B_DumpHouse.Visible = B_LoadHouse.Visible = false;
|
||||
}
|
||||
|
||||
public void Save() => SaveVillager(VillagerIndex);
|
||||
@@ -161,5 +166,60 @@ private void ChangeVillager()
|
||||
L_ExternalName.Text = GameInfo.Strings.GetVillager(name);
|
||||
PB_Villager.Image = VillagerSprite.GetVillagerSprite(name);
|
||||
}
|
||||
|
||||
private void B_DumpHouse_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ModifierKeys == Keys.Shift)
|
||||
{
|
||||
using var fbd = new FolderBrowserDialog();
|
||||
if (fbd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var dir = Path.GetDirectoryName(fbd.SelectedPath);
|
||||
if (dir == null || !Directory.Exists(dir))
|
||||
return;
|
||||
SAV.DumpVillagerHouses(fbd.SelectedPath);
|
||||
return;
|
||||
}
|
||||
|
||||
var name = L_ExternalName.Text;
|
||||
using var sfd = new SaveFileDialog
|
||||
{
|
||||
Filter = "New Horizons Villager House (*.nhvh)|*.nhvh|All files (*.*)|*.*",
|
||||
FileName = $"{name}.nhvh",
|
||||
};
|
||||
if (sfd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var h = SAV.GetVillagerHouse(VillagerIndex);
|
||||
var data = h.ToBytesClass();
|
||||
File.WriteAllBytes(sfd.FileName, data);
|
||||
}
|
||||
|
||||
private void B_LoadHouse_Click(object sender, EventArgs e)
|
||||
{
|
||||
var name = L_ExternalName.Text;
|
||||
using var ofd = new OpenFileDialog
|
||||
{
|
||||
Filter = "New Horizons Villager House (*.nhvh)|*.nhvh|All files (*.*)|*.*",
|
||||
FileName = $"{name}.nhvh",
|
||||
};
|
||||
if (ofd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var file = ofd.FileName;
|
||||
var fi = new FileInfo(file);
|
||||
const int expectLength = VillagerHouse.SIZE;
|
||||
if (fi.Length != expectLength)
|
||||
{
|
||||
var msg = $"Imported villager house's data length (0x{fi.Length:X}) does not match the required length (0x{expectLength:X}).";
|
||||
WinFormsUtil.Error("Cancelling:", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
var data = File.ReadAllBytes(file);
|
||||
var h = data.ToClass<VillagerHouse>();
|
||||
SAV.SetVillagerHouse(h, VillagerIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
60
NHSE.WinForms/Editor.Designer.cs
generated
60
NHSE.WinForms/Editor.Designer.cs
generated
@@ -77,6 +77,10 @@ private void InitializeComponent()
|
||||
this.B_EditTurnipExchange = new System.Windows.Forms.Button();
|
||||
this.B_EditBuildings = new System.Windows.Forms.Button();
|
||||
this.B_RecycleBin = new System.Windows.Forms.Button();
|
||||
this.B_LoadHouse = new System.Windows.Forms.Button();
|
||||
this.B_DumpHouse = new System.Windows.Forms.Button();
|
||||
this.NUD_PlayerHouse = new System.Windows.Forms.NumericUpDown();
|
||||
this.L_PlayerHouse = new System.Windows.Forms.Label();
|
||||
this.Menu_Editor.SuspendLayout();
|
||||
this.TC_Editors.SuspendLayout();
|
||||
this.Tab_Players.SuspendLayout();
|
||||
@@ -90,6 +94,7 @@ private void InitializeComponent()
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_PatternIndex)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.PB_Pattern)).BeginInit();
|
||||
this.Tab_Map.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_PlayerHouse)).BeginInit();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// Menu_Editor
|
||||
@@ -518,6 +523,10 @@ private void InitializeComponent()
|
||||
//
|
||||
// Tab_Map
|
||||
//
|
||||
this.Tab_Map.Controls.Add(this.L_PlayerHouse);
|
||||
this.Tab_Map.Controls.Add(this.NUD_PlayerHouse);
|
||||
this.Tab_Map.Controls.Add(this.B_LoadHouse);
|
||||
this.Tab_Map.Controls.Add(this.B_DumpHouse);
|
||||
this.Tab_Map.Controls.Add(this.B_EditFieldItems);
|
||||
this.Tab_Map.Controls.Add(this.B_EditTerrain);
|
||||
this.Tab_Map.Controls.Add(this.B_EditAcres);
|
||||
@@ -592,6 +601,52 @@ private void InitializeComponent()
|
||||
this.B_RecycleBin.UseVisualStyleBackColor = true;
|
||||
this.B_RecycleBin.Click += new System.EventHandler(this.B_RecycleBin_Click);
|
||||
//
|
||||
// B_LoadHouse
|
||||
//
|
||||
this.B_LoadHouse.Location = new System.Drawing.Point(106, 29);
|
||||
this.B_LoadHouse.Name = "B_LoadHouse";
|
||||
this.B_LoadHouse.Size = new System.Drawing.Size(92, 40);
|
||||
this.B_LoadHouse.TabIndex = 50;
|
||||
this.B_LoadHouse.Text = "Load House";
|
||||
this.B_LoadHouse.UseVisualStyleBackColor = true;
|
||||
this.B_LoadHouse.Click += new System.EventHandler(this.B_LoadHouse_Click);
|
||||
//
|
||||
// B_DumpHouse
|
||||
//
|
||||
this.B_DumpHouse.Location = new System.Drawing.Point(8, 29);
|
||||
this.B_DumpHouse.Name = "B_DumpHouse";
|
||||
this.B_DumpHouse.Size = new System.Drawing.Size(92, 40);
|
||||
this.B_DumpHouse.TabIndex = 49;
|
||||
this.B_DumpHouse.Text = "Dump House";
|
||||
this.B_DumpHouse.UseVisualStyleBackColor = true;
|
||||
this.B_DumpHouse.Click += new System.EventHandler(this.B_DumpHouse_Click);
|
||||
//
|
||||
// numericUpDown1
|
||||
//
|
||||
this.NUD_PlayerHouse.Location = new System.Drawing.Point(106, 6);
|
||||
this.NUD_PlayerHouse.Minimum = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.NUD_PlayerHouse.Name = "NUD_PlayerHouse";
|
||||
this.NUD_PlayerHouse.Size = new System.Drawing.Size(45, 20);
|
||||
this.NUD_PlayerHouse.TabIndex = 51;
|
||||
this.NUD_PlayerHouse.Value = new decimal(new int[] {
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
//
|
||||
// L_PlayerHouse
|
||||
//
|
||||
this.L_PlayerHouse.Location = new System.Drawing.Point(16, 6);
|
||||
this.L_PlayerHouse.Name = "L_PlayerHouse";
|
||||
this.L_PlayerHouse.Size = new System.Drawing.Size(84, 20);
|
||||
this.L_PlayerHouse.TabIndex = 52;
|
||||
this.L_PlayerHouse.Text = "Player House:";
|
||||
this.L_PlayerHouse.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// Editor
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@@ -621,6 +676,7 @@ private void InitializeComponent()
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_PatternIndex)).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.PB_Pattern)).EndInit();
|
||||
this.Tab_Map.ResumeLayout(false);
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_PlayerHouse)).EndInit();
|
||||
this.ResumeLayout(false);
|
||||
this.PerformLayout();
|
||||
|
||||
@@ -675,6 +731,10 @@ private void InitializeComponent()
|
||||
private System.Windows.Forms.Button B_EditTerrain;
|
||||
private System.Windows.Forms.Button B_EditPlayerFlags;
|
||||
private System.Windows.Forms.Button B_EditFieldItems;
|
||||
private System.Windows.Forms.NumericUpDown NUD_PlayerHouse;
|
||||
private System.Windows.Forms.Button B_LoadHouse;
|
||||
private System.Windows.Forms.Button B_DumpHouse;
|
||||
private System.Windows.Forms.Label L_PlayerHouse;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ private VillagerEditor LoadVillagers()
|
||||
{
|
||||
var p0 = SAV.Players[0].Personal;
|
||||
var villagers = SAV.Main.GetVillagers();
|
||||
var v = new VillagerEditor(villagers, p0) {Dock = DockStyle.Fill};
|
||||
var v = new VillagerEditor(villagers, p0, SAV.Main, true) {Dock = DockStyle.Fill};
|
||||
Tab_Villagers.Controls.Add(v);
|
||||
return v;
|
||||
}
|
||||
@@ -146,6 +146,7 @@ private void LoadPlayers()
|
||||
|
||||
PlayerIndex = -1;
|
||||
CB_Players.SelectedIndex = 0;
|
||||
NUD_PlayerHouse.Maximum = CB_Players.Items.Count;
|
||||
}
|
||||
|
||||
private void LoadMain()
|
||||
@@ -439,5 +440,62 @@ private void B_EditFieldItems_Click(object sender, EventArgs e)
|
||||
using var editor = new FieldItemEditor(SAV.Main);
|
||||
editor.ShowDialog();
|
||||
}
|
||||
|
||||
private void B_DumpHouse_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ModifierKeys == Keys.Shift)
|
||||
{
|
||||
using var fbd = new FolderBrowserDialog();
|
||||
if (fbd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var dir = Path.GetDirectoryName(fbd.SelectedPath);
|
||||
if (dir == null || !Directory.Exists(dir))
|
||||
return;
|
||||
SAV.DumpPlayerHouses(fbd.SelectedPath);
|
||||
return;
|
||||
}
|
||||
|
||||
var index = (int)(NUD_PlayerHouse.Value - 1);
|
||||
var name = CB_Players.Items[index].ToString();
|
||||
using var sfd = new SaveFileDialog
|
||||
{
|
||||
Filter = "New Horizons Player House (*.nhph)|*.nhph|All files (*.*)|*.*",
|
||||
FileName = $"{name}.nhph",
|
||||
};
|
||||
if (sfd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var h = SAV.Main.GetPlayerHouse(index);
|
||||
var data = h.ToBytesClass();
|
||||
File.WriteAllBytes(sfd.FileName, data);
|
||||
}
|
||||
|
||||
private void B_LoadHouse_Click(object sender, EventArgs e)
|
||||
{
|
||||
var index = (int)(NUD_PlayerHouse.Value - 1);
|
||||
var name = CB_Players.Items[index].ToString();
|
||||
using var ofd = new OpenFileDialog
|
||||
{
|
||||
Filter = "New Horizons Player House (*.nhph)|*.nhph|All files (*.*)|*.*",
|
||||
FileName = $"{name}.nhph",
|
||||
};
|
||||
if (ofd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var file = ofd.FileName;
|
||||
var fi = new FileInfo(file);
|
||||
const int expectLength = PlayerHouse.SIZE;
|
||||
if (fi.Length != expectLength)
|
||||
{
|
||||
var msg = $"Imported player house's data length (0x{fi.Length:X}) does not match the required length (0x{expectLength:X}).";
|
||||
WinFormsUtil.Error("Cancelling:", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
var data = File.ReadAllBytes(file);
|
||||
var h = data.ToClass<PlayerHouse>();
|
||||
SAV.Main.SetPlayerHouse(h, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user