diff --git a/NHSE.Core/Hashing/FileHashRevision.cs b/NHSE.Core/Hashing/FileHashRevision.cs index eba8fcb..e418864 100644 --- a/NHSE.Core/Hashing/FileHashRevision.cs +++ b/NHSE.Core/Hashing/FileHashRevision.cs @@ -10,6 +10,7 @@ public static class FileHashRevision private const string FN_POSTBOX = "postbox.dat"; private const string FN_PHOTO = "photo_studio_island.dat"; private const string FN_PROFILE = "profile.dat"; + private const string FN_WHEREAREN = "wherearen.dat"; #region REVISION 1.0.0 @@ -572,6 +573,7 @@ public static class FileHashRevision internal const int REV_200_POSTBOX = REV_170_POSTBOX; internal const int REV_200_PHOTO = 0x2F650; internal const int REV_200_PROFILE = REV_110_PROFILE; + internal const int REV_200_WHEREAREN = 0xB8A4E0; public static readonly FileHashInfo REV_200 = new(new FileHashDetails[] { @@ -614,7 +616,11 @@ public static class FileHashRevision { new(0x100, 0x6945c), }), - }); + new(FN_WHEREAREN, REV_200_WHEREAREN, new FileHashRegion[] + { + new(0x100, 0xB8A3DC), + }), + } ); #endregion } diff --git a/NHSE.Core/Save/Files/WhereAreN.cs b/NHSE.Core/Save/Files/WhereAreN.cs new file mode 100644 index 0000000..e03705f --- /dev/null +++ b/NHSE.Core/Save/Files/WhereAreN.cs @@ -0,0 +1,18 @@ +namespace NHSE.Core +{ + /// + /// + public sealed class WhereAreN : EncryptedFilePair + { + public const string FileName = "wherearen"; + + public readonly WhereAreNOffsets Offsets; + public WhereAreN(string folder) : base(folder, FileName) => Offsets = WhereAreNOffsets.GetOffsets(Info); + + public EncryptedInt32 Poki + { + get => EncryptedInt32.ReadVerify(Data, Offsets.Poki); + set => value.Write(Data, Offsets.Poki); + } + } +} diff --git a/NHSE.Core/Save/Meta/EncryptedFilePair.cs b/NHSE.Core/Save/Meta/EncryptedFilePair.cs index b851131..8b78ff5 100644 --- a/NHSE.Core/Save/Meta/EncryptedFilePair.cs +++ b/NHSE.Core/Save/Meta/EncryptedFilePair.cs @@ -19,6 +19,15 @@ public abstract class EncryptedFilePair public readonly string NameData; public readonly string NameHeader; + public static bool Exists(string folder, string name) + { + var NameData = $"{name}.dat"; + var NameHeader = $"{name}Header.dat"; + var hdr = Path.Combine(folder, NameHeader); + var dat = Path.Combine(folder, NameData); + return File.Exists(hdr) && File.Exists(dat); + } + protected EncryptedFilePair(string folder, string name) { NameData = $"{name}.dat"; diff --git a/NHSE.Core/Save/Meta/HorizonSave.cs b/NHSE.Core/Save/Meta/HorizonSave.cs index ac4258a..573ca0f 100644 --- a/NHSE.Core/Save/Meta/HorizonSave.cs +++ b/NHSE.Core/Save/Meta/HorizonSave.cs @@ -78,6 +78,8 @@ public bool ValidateSizes() return false; if (p.Profile.Data.Length != sizes.Profile) return false; + if (p.WhereAreN is { } x && x.Data.Length != sizes.WhereAreN) + return false; } return true; } diff --git a/NHSE.Core/Save/Meta/Player.cs b/NHSE.Core/Save/Meta/Player.cs index 40c7173..5df8394 100644 --- a/NHSE.Core/Save/Meta/Player.cs +++ b/NHSE.Core/Save/Meta/Player.cs @@ -14,6 +14,7 @@ public sealed class Player : IEnumerable public readonly PhotoStudioIsland Photo; public readonly PostBox PostBox; public readonly Profile Profile; + public readonly WhereAreN? WhereAreN; /// /// Directory Name where the player data was loaded from. Not the full path. @@ -21,7 +22,14 @@ public sealed class Player : IEnumerable public readonly string DirectoryName; #region Override Implementations - public IEnumerator GetEnumerator() => new EncryptedFilePair[] {Personal, Photo, PostBox, Profile}.AsEnumerable().GetEnumerator(); + public IEnumerator GetEnumerator() + { + IEnumerable baseFiles = new EncryptedFilePair[] { Personal, Photo, PostBox, Profile }; + if (WhereAreN is not null) + baseFiles = baseFiles.Concat(new EncryptedFilePair[] { WhereAreN }); + return baseFiles.AsEnumerable().GetEnumerator(); + } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public override string ToString() => Personal.PlayerName; @@ -49,6 +57,9 @@ private Player(string folder) Photo = new PhotoStudioIsland(folder); PostBox = new PostBox(folder); Profile = new Profile(folder); + + if (EncryptedFilePair.Exists(folder, WhereAreN.FileName)) + WhereAreN = new WhereAreN(folder); } } } diff --git a/NHSE.Core/Save/Meta/RevisionChecker.cs b/NHSE.Core/Save/Meta/RevisionChecker.cs index b3418d5..c2e23de 100644 --- a/NHSE.Core/Save/Meta/RevisionChecker.cs +++ b/NHSE.Core/Save/Meta/RevisionChecker.cs @@ -26,7 +26,7 @@ public static class RevisionChecker new(REV_190_MAIN, REV_190_PERSONAL, REV_190_PHOTO, REV_190_POSTBOX, REV_190_PROFILE), // 1.9.0 new(REV_1100_MAIN,REV_1100_PERSONAL,REV_1100_PHOTO,REV_1100_POSTBOX,REV_1100_PROFILE),// 1.10.0 new(REV_1110_MAIN,REV_1110_PERSONAL,REV_1110_PHOTO,REV_1110_POSTBOX,REV_1110_PROFILE),// 1.11.0 - new(REV_200_MAIN, REV_200_PERSONAL, REV_200_PHOTO, REV_200_POSTBOX, REV_200_PROFILE), // 2.0.0 + new(REV_200_MAIN, REV_200_PERSONAL, REV_200_PHOTO, REV_200_POSTBOX, REV_200_PROFILE, REV_200_WHEREAREN), // 2.0.0 }; private static readonly FileHeaderInfo[] RevisionInfo = diff --git a/NHSE.Core/Save/Meta/SaveFileSizes.cs b/NHSE.Core/Save/Meta/SaveFileSizes.cs index f03d640..2eaadb0 100644 --- a/NHSE.Core/Save/Meta/SaveFileSizes.cs +++ b/NHSE.Core/Save/Meta/SaveFileSizes.cs @@ -10,14 +10,16 @@ public class SaveFileSizes public readonly uint PhotoStudioIsland; public readonly uint PostBox; public readonly uint Profile; + public readonly uint WhereAreN; - public SaveFileSizes(uint main, uint personal, uint photo, uint postbox, uint profile) + public SaveFileSizes(uint main, uint personal, uint photo, uint postbox, uint profile, uint wherearen = 0) { Main = main; Personal = personal; PhotoStudioIsland = photo; PostBox = postbox; Profile = profile; + WhereAreN = wherearen; } } -} \ No newline at end of file +} diff --git a/NHSE.Core/Save/Offsets/WhereAreNOffsets.cs b/NHSE.Core/Save/Offsets/WhereAreNOffsets.cs new file mode 100644 index 0000000..e63932c --- /dev/null +++ b/NHSE.Core/Save/Offsets/WhereAreNOffsets.cs @@ -0,0 +1,25 @@ +using System; + +namespace NHSE.Core +{ + /// + /// Offset info and object retrieval logic for + /// + public abstract class WhereAreNOffsets + { + public abstract int Poki { get; } + + public static WhereAreNOffsets GetOffsets(FileHeaderInfo Info) + { + var rev = Info.GetKnownRevisionIndex(); + return rev switch + { + 22 => new WhereAreNOffsets20(), + 23 => new WhereAreNOffsets20(), + 24 => new WhereAreNOffsets20(), + 25 => new WhereAreNOffsets20(), + _ => throw new IndexOutOfRangeException("Unknown revision!" + Environment.NewLine + Info), + }; + } + } +} \ No newline at end of file diff --git a/NHSE.Core/Save/Offsets/WhereAreNOffsets20.cs b/NHSE.Core/Save/Offsets/WhereAreNOffsets20.cs new file mode 100644 index 0000000..90cc233 --- /dev/null +++ b/NHSE.Core/Save/Offsets/WhereAreNOffsets20.cs @@ -0,0 +1,10 @@ +namespace NHSE.Core +{ + /// + /// + /// + public sealed class WhereAreNOffsets20 : WhereAreNOffsets + { + public override int Poki => 0xB84228; + } +} diff --git a/NHSE.WinForms/Editor.Designer.cs b/NHSE.WinForms/Editor.Designer.cs index 5149f63..751ef9d 100644 --- a/NHSE.WinForms/Editor.Designer.cs +++ b/NHSE.WinForms/Editor.Designer.cs @@ -38,6 +38,7 @@ private void InitializeComponent() this.Menu_VerifyHashes = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_LoadDecrypted = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_RAMEdit = new System.Windows.Forms.ToolStripMenuItem(); + this.Menu_ItemImages = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_Options = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_Language = new System.Windows.Forms.ToolStripComboBox(); this.Menu_Settings = new System.Windows.Forms.ToolStripMenuItem(); @@ -67,6 +68,8 @@ private void InitializeComponent() this.B_RecycleBin = new System.Windows.Forms.Button(); this.Tab_Villagers = new System.Windows.Forms.TabPage(); this.Tab_Players = new System.Windows.Forms.TabPage(); + this.L_Poki = new System.Windows.Forms.Label(); + this.NUD_Poki = new System.Windows.Forms.NumericUpDown(); this.L_EarnedMiles = new System.Windows.Forms.Label(); this.NUD_TotalNookMiles = new System.Windows.Forms.NumericUpDown(); this.L_StorageCount = new System.Windows.Forms.Label(); @@ -98,13 +101,13 @@ private void InitializeComponent() this.CB_Players = new System.Windows.Forms.ComboBox(); this.PB_Player = new System.Windows.Forms.PictureBox(); this.TC_Editors = new System.Windows.Forms.TabControl(); - this.Menu_ItemImages = new System.Windows.Forms.ToolStripMenuItem(); this.Menu_Editor.SuspendLayout(); this.CM_Picture.SuspendLayout(); this.Tab_Map.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.NUD_WeatherSeed)).BeginInit(); this.CM_EditMap.SuspendLayout(); this.Tab_Players.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.NUD_Poki)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.NUD_TotalNookMiles)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.NUD_StorageCount)).BeginInit(); ((System.ComponentModel.ISupportInitialize)(this.NUD_PocketCount2)).BeginInit(); @@ -191,6 +194,14 @@ private void InitializeComponent() this.Menu_RAMEdit.Text = "RAM Edit"; this.Menu_RAMEdit.Click += new System.EventHandler(this.Menu_RAMEdit_Click); // + // Menu_ItemImages + // + this.Menu_ItemImages.Name = "Menu_ItemImages"; + this.Menu_ItemImages.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.M))); + this.Menu_ItemImages.Size = new System.Drawing.Size(206, 22); + this.Menu_ItemImages.Text = "Item Images"; + this.Menu_ItemImages.Click += new System.EventHandler(this.Menu_ItemImages_Click); + // // Menu_Options // this.Menu_Options.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { @@ -259,8 +270,8 @@ private void InitializeComponent() this.Tab_Map.Controls.Add(this.B_RecycleBin); this.Tab_Map.Location = new System.Drawing.Point(4, 22); this.Tab_Map.Name = "Tab_Map"; - this.Tab_Map.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3); - this.Tab_Map.Size = new System.Drawing.Size(396, 212); + this.Tab_Map.Padding = new System.Windows.Forms.Padding(3); + this.Tab_Map.Size = new System.Drawing.Size(396, 261); this.Tab_Map.TabIndex = 2; this.Tab_Map.Text = "Map"; this.Tab_Map.UseVisualStyleBackColor = true; @@ -469,14 +480,16 @@ private void InitializeComponent() // this.Tab_Villagers.Location = new System.Drawing.Point(4, 22); this.Tab_Villagers.Name = "Tab_Villagers"; - this.Tab_Villagers.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3); - this.Tab_Villagers.Size = new System.Drawing.Size(396, 212); + this.Tab_Villagers.Padding = new System.Windows.Forms.Padding(3); + this.Tab_Villagers.Size = new System.Drawing.Size(396, 261); this.Tab_Villagers.TabIndex = 0; this.Tab_Villagers.Text = "Villagers"; this.Tab_Villagers.UseVisualStyleBackColor = true; // // Tab_Players // + this.Tab_Players.Controls.Add(this.L_Poki); + this.Tab_Players.Controls.Add(this.NUD_Poki); this.Tab_Players.Controls.Add(this.L_EarnedMiles); this.Tab_Players.Controls.Add(this.NUD_TotalNookMiles); this.Tab_Players.Controls.Add(this.L_StorageCount); @@ -501,12 +514,33 @@ private void InitializeComponent() this.Tab_Players.Controls.Add(this.PB_Player); this.Tab_Players.Location = new System.Drawing.Point(4, 22); this.Tab_Players.Name = "Tab_Players"; - this.Tab_Players.Padding = new System.Windows.Forms.Padding(3, 3, 3, 3); - this.Tab_Players.Size = new System.Drawing.Size(396, 211); + this.Tab_Players.Padding = new System.Windows.Forms.Padding(3); + this.Tab_Players.Size = new System.Drawing.Size(396, 261); this.Tab_Players.TabIndex = 1; this.Tab_Players.Text = "Players"; this.Tab_Players.UseVisualStyleBackColor = true; // + // L_Poki + // + this.L_Poki.Location = new System.Drawing.Point(142, 224); + this.L_Poki.Name = "L_Poki"; + this.L_Poki.Size = new System.Drawing.Size(84, 20); + this.L_Poki.TabIndex = 28; + this.L_Poki.Text = "Poki:"; + this.L_Poki.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // NUD_Poki + // + this.NUD_Poki.Location = new System.Drawing.Point(232, 224); + this.NUD_Poki.Maximum = new decimal(new int[] { + 2147483647, + 0, + 0, + 0}); + this.NUD_Poki.Name = "NUD_Poki"; + this.NUD_Poki.Size = new System.Drawing.Size(100, 20); + this.NUD_Poki.TabIndex = 27; + // // L_EarnedMiles // this.L_EarnedMiles.Location = new System.Drawing.Point(142, 117); @@ -558,7 +592,7 @@ private void InitializeComponent() // L_PocketCount2 // this.L_PocketCount2.AutoSize = true; - this.L_PocketCount2.Location = new System.Drawing.Point(148, 191); + this.L_PocketCount2.Location = new System.Drawing.Point(200, 192); this.L_PocketCount2.Name = "L_PocketCount2"; this.L_PocketCount2.Size = new System.Drawing.Size(81, 13); this.L_PocketCount2.TabIndex = 22; @@ -568,7 +602,7 @@ private void InitializeComponent() // L_PocketCount1 // this.L_PocketCount1.AutoSize = true; - this.L_PocketCount1.Location = new System.Drawing.Point(148, 170); + this.L_PocketCount1.Location = new System.Drawing.Point(200, 171); this.L_PocketCount1.Name = "L_PocketCount1"; this.L_PocketCount1.Size = new System.Drawing.Size(81, 13); this.L_PocketCount1.TabIndex = 21; @@ -577,14 +611,14 @@ private void InitializeComponent() // // NUD_PocketCount2 // - this.NUD_PocketCount2.Location = new System.Drawing.Point(104, 188); + this.NUD_PocketCount2.Location = new System.Drawing.Point(151, 189); this.NUD_PocketCount2.Maximum = new decimal(new int[] { 2147483647, 0, 0, 0}); this.NUD_PocketCount2.Name = "NUD_PocketCount2"; - this.NUD_PocketCount2.Size = new System.Drawing.Size(41, 20); + this.NUD_PocketCount2.Size = new System.Drawing.Size(46, 20); this.NUD_PocketCount2.TabIndex = 20; this.NUD_PocketCount2.Value = new decimal(new int[] { 20, @@ -595,14 +629,14 @@ private void InitializeComponent() // // NUD_PocketCount1 // - this.NUD_PocketCount1.Location = new System.Drawing.Point(104, 167); + this.NUD_PocketCount1.Location = new System.Drawing.Point(151, 168); this.NUD_PocketCount1.Maximum = new decimal(new int[] { 2147483647, 0, 0, 0}); this.NUD_PocketCount1.Name = "NUD_PocketCount1"; - this.NUD_PocketCount1.Size = new System.Drawing.Size(41, 20); + this.NUD_PocketCount1.Size = new System.Drawing.Size(46, 20); this.NUD_PocketCount1.TabIndex = 19; this.NUD_PocketCount1.Value = new decimal(new int[] { 20, @@ -614,9 +648,9 @@ private void InitializeComponent() // B_EditPlayer // this.B_EditPlayer.ContextMenuStrip = this.CM_EditPlayer; - this.B_EditPlayer.Location = new System.Drawing.Point(300, 168); + this.B_EditPlayer.Location = new System.Drawing.Point(6, 214); this.B_EditPlayer.Name = "B_EditPlayer"; - this.B_EditPlayer.Size = new System.Drawing.Size(92, 40); + this.B_EditPlayer.Size = new System.Drawing.Size(130, 40); this.B_EditPlayer.TabIndex = 18; this.B_EditPlayer.Text = "Edit Player..."; this.B_EditPlayer.UseVisualStyleBackColor = true; @@ -689,7 +723,7 @@ private void InitializeComponent() // this.B_EditPlayerItems.Location = new System.Drawing.Point(6, 168); this.B_EditPlayerItems.Name = "B_EditPlayerItems"; - this.B_EditPlayerItems.Size = new System.Drawing.Size(92, 40); + this.B_EditPlayerItems.Size = new System.Drawing.Size(130, 40); this.B_EditPlayerItems.TabIndex = 12; this.B_EditPlayerItems.Text = "Edit Items"; this.B_EditPlayerItems.UseVisualStyleBackColor = true; @@ -817,26 +851,17 @@ private void InitializeComponent() this.TC_Editors.Controls.Add(this.Tab_Players); this.TC_Editors.Controls.Add(this.Tab_Villagers); this.TC_Editors.Controls.Add(this.Tab_Map); - this.TC_Editors.Dock = System.Windows.Forms.DockStyle.Fill; this.TC_Editors.Location = new System.Drawing.Point(0, 24); this.TC_Editors.Name = "TC_Editors"; this.TC_Editors.SelectedIndex = 0; - this.TC_Editors.Size = new System.Drawing.Size(404, 237); + this.TC_Editors.Size = new System.Drawing.Size(404, 287); this.TC_Editors.TabIndex = 1; // - // Menu_ItemImages - // - this.Menu_ItemImages.Name = "Menu_ItemImages"; - this.Menu_ItemImages.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.M))); - this.Menu_ItemImages.Size = new System.Drawing.Size(206, 22); - this.Menu_ItemImages.Text = "Item Images"; - this.Menu_ItemImages.Click += new System.EventHandler(this.Menu_ItemImages_Click); - // // Editor // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(404, 261); + this.ClientSize = new System.Drawing.Size(404, 311); this.Controls.Add(this.TC_Editors); this.Controls.Add(this.Menu_Editor); this.Icon = global::NHSE.WinForms.Properties.Resources.icon; @@ -854,6 +879,7 @@ private void InitializeComponent() this.CM_EditMap.ResumeLayout(false); this.Tab_Players.ResumeLayout(false); this.Tab_Players.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.NUD_Poki)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.NUD_TotalNookMiles)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.NUD_StorageCount)).EndInit(); ((System.ComponentModel.ISupportInitialize)(this.NUD_PocketCount2)).EndInit(); @@ -940,6 +966,8 @@ private void InitializeComponent() private System.Windows.Forms.Label L_WeatherSeed; private System.Windows.Forms.NumericUpDown NUD_WeatherSeed; private System.Windows.Forms.ToolStripMenuItem Menu_ItemImages; + private System.Windows.Forms.Label L_Poki; + private System.Windows.Forms.NumericUpDown NUD_Poki; } } diff --git a/NHSE.WinForms/Editor.cs b/NHSE.WinForms/Editor.cs index fd844f3..7dcd619 100644 --- a/NHSE.WinForms/Editor.cs +++ b/NHSE.WinForms/Editor.cs @@ -308,6 +308,15 @@ private void LoadPlayer(int index) NUD_PocketCount2.Value = Math.Min(int.MaxValue, pers.BagCount); NUD_StorageCount.Value = Math.Min(int.MaxValue, pers.ItemChestCount); + if (player.WhereAreN is not null) + { + NUD_Poki.Value = Math.Min(int.MaxValue, player.WhereAreN.Poki.Value); + } + else + { + L_Poki.Visible = NUD_Poki.Visible = false; + } + try { var photo = pers.GetPhotoData(); @@ -367,6 +376,11 @@ private void SavePlayer(int index) pers.BagCount = (uint)NUD_PocketCount2.Value; pers.ItemChestCount = (uint)NUD_StorageCount.Value; + + if (player.WhereAreN is not null) + { + player.WhereAreN.Poki.Value = (uint)NUD_Poki.Value; + } } private void B_EditAchievements_Click(object sender, EventArgs e)