using System; using System.IO; using System.Windows.Forms; using NHSE.Core; using NHSE.Sprites; namespace NHSE.WinForms { public partial class VillagerEditor : UserControl { public Villager[] Villagers; public IVillagerOrigin Origin; private readonly MainSave SAV; private int VillagerIndex = -1; private bool Loading; 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); private void LoadVillagers() { CB_Personality.Items.Clear(); var personalities = Enum.GetNames(typeof(VillagerPersonality)); foreach (var p in personalities) CB_Personality.Items.Add(p); VillagerIndex = -1; LoadVillager(0); } private void LoadVillager(object sender, EventArgs e) => LoadVillager((int)NUD_Villager.Value - 1); private void LoadVillager(int index) { if (VillagerIndex >= 0) SaveVillager(VillagerIndex); if (index < 0) return; LoadVillager(Villagers[index]); VillagerIndex = index; } private void LoadVillager(Villager v) { Loading = true; NUD_Species.Value = v.Species; NUD_Variant.Value = v.Variant; CB_Personality.SelectedIndex = (int)v.Personality; TB_Catchphrase.Text = v.CatchPhrase; CHK_VillagerMovingOut.Checked = v.MovingOut; Loading = false; } private void SaveVillager(int index) { var v = Villagers[index]; v.Species = (byte)NUD_Species.Value; v.Variant = (byte)NUD_Variant.Value; v.Personality = (VillagerPersonality)CB_Personality.SelectedIndex; v.CatchPhrase = TB_Catchphrase.Text; v.MovingOut = CHK_VillagerMovingOut.Checked; } private void CHK_VillagerMovingOut_CheckedChanged(object sender, EventArgs e) { if (Loading) return; if (!CHK_VillagerMovingOut.Checked) return; const string question = "Are you trying to make the Villager move out?"; const string reply = "If so, set the Event Flag (024 - ForceMoveOut) to 1 so that the Villager is removed by the game."; WinFormsUtil.Alert(question, reply); } private void B_DumpVillager_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; Villagers.DumpVillagers(fbd.SelectedPath); return; } var name = L_ExternalName.Text; using var sfd = new SaveFileDialog { Filter = "New Horizons Villager (*.nhv)|*.nhv|All files (*.*)|*.*", FileName = $"{name}.nhv", }; if (sfd.ShowDialog() != DialogResult.OK) return; SaveVillager(VillagerIndex); var v = Villagers[VillagerIndex]; File.WriteAllBytes(sfd.FileName, v.Data); } private void B_LoadVillager_Click(object sender, EventArgs e) { var name = L_ExternalName.Text; using var ofd = new OpenFileDialog { Filter = "New Horizons Villager (*.nhv)|*.nhv|All files (*.*)|*.*", FileName = $"{name}.nhv", }; if (ofd.ShowDialog() != DialogResult.OK) return; var file = ofd.FileName; var original = Villagers[VillagerIndex]; var expectLength = original.Data.Length; var fi = new FileInfo(file); if (fi.Length != expectLength) { var msg = $"Imported villager'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(ofd.FileName); var v = new Villager(data); var player0 = Origin; if (!v.IsOriginatedFrom(player0)) { const string msg = "Imported Villager did not originate from Resident Rep's data."; var result = WinFormsUtil.Prompt(MessageBoxButtons.YesNoCancel, msg, "Update values?"); if (result == DialogResult.Cancel) return; if (result == DialogResult.Yes) v.ChangeOrigins(player0, v.Data); } LoadVillager(Villagers[VillagerIndex] = v); } private void B_EditFurniture_Click(object sender, EventArgs e) { var v = Villagers[VillagerIndex]; var items = v.Furniture; using var editor = new PlayerItemEditor(items, 8, 2); if (editor.ShowDialog() == DialogResult.OK) v.Furniture = items; } private void B_EditVillagerFlags_Click(object sender, EventArgs e) { var v = Villagers[VillagerIndex]; var flags = v.GetEventFlagsSave(); using var editor = new VillagerFlagEditor(flags); if (editor.ShowDialog() == DialogResult.OK) v.SetEventFlagsSave(flags); } private string GetCurrentVillagerInternalName() => VillagerUtil.GetInternalVillagerName((VillagerSpecies)NUD_Species.Value, (int)NUD_Variant.Value); private void ChangeVillager(object sender, EventArgs e) => ChangeVillager(); private void ChangeVillager() { var name = GetCurrentVillagerInternalName(); L_InternalName.Text = name; 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(); SAV.SetVillagerHouse(h, VillagerIndex); } } }