mirror of
https://github.com/kwsch/NHSE.git
synced 2026-09-13 05:35:32 -05:00
Add villager memory (per player) editor
Change friendship here. Can also cheat all friendships (of all villagers, for all saved players) to 255 by shift clicking the drop-down button instead.
This commit is contained in:
169
NHSE.Core/Structures/Records/EventFlagVillagerMemoryPlayer.cs
Normal file
169
NHSE.Core/Structures/Records/EventFlagVillagerMemoryPlayer.cs
Normal file
@@ -0,0 +1,169 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NHSE.Core
|
||||
{
|
||||
public class EventFlagVillagerMemoryPlayer : INamedValue
|
||||
{
|
||||
public readonly byte Initial;
|
||||
public readonly byte Maximum;
|
||||
|
||||
public ushort Index { get; }
|
||||
public string Name { get; }
|
||||
|
||||
public EventFlagVillagerMemoryPlayer(byte init, byte max, ushort index, string name)
|
||||
{
|
||||
Name = name;
|
||||
Index = index;
|
||||
Initial = init;
|
||||
Maximum = max;
|
||||
}
|
||||
|
||||
public static readonly IReadOnlyDictionary<ushort, EventFlagVillagerMemoryPlayer> List = new Dictionary<ushort, EventFlagVillagerMemoryPlayer>
|
||||
{
|
||||
{0x00, new EventFlagVillagerMemoryPlayer(0 , 1 , 000, "TalkFreeMultiDayEventNow" )}, // (ボツ)今、期間型イベント用のFreeFを聞いたか?
|
||||
{0x01, new EventFlagVillagerMemoryPlayer(0 , 7 , 001, "ContinuousTalkDays" )}, // 何日連続で話しかけられたか
|
||||
{0x02, new EventFlagVillagerMemoryPlayer(0 , 1 , 002, "SameLand" )}, // 同じ村に住んでいたことがあるか
|
||||
{0x03, new EventFlagVillagerMemoryPlayer(0 , 1 , 003, "SetGreeting" )}, // 挨拶を設定したことがある
|
||||
{0x04, new EventFlagVillagerMemoryPlayer(0 , 1 , 004, "EasterGetRecipeFlag" )}, // イースター|このNPCからリアクション会話でレシピを受け取った
|
||||
{0x05, new EventFlagVillagerMemoryPlayer(0 , 1 , 005, "TalkProgressMuseumBuilt2" )}, // 博物館2への拡張に関するFreeH_Progressを聞いたか?
|
||||
{0x06, new EventFlagVillagerMemoryPlayer(0 , 1 , 006, "NextMoveOutTalk" )}, // 引越ししたい会話したか
|
||||
{0x07, new EventFlagVillagerMemoryPlayer(0 , 1 , 007, "TalkMoveOut" )}, // 引越していく状態で会話したか
|
||||
{0x08, new EventFlagVillagerMemoryPlayer(0 , 7 , 008, "VisitCount" )}, // そのプレイヤーの家に行った回数
|
||||
{0x09, new EventFlagVillagerMemoryPlayer(0 , 7 , 009, "VisitedCount" )}, // そのプレイヤーが家に来た回数
|
||||
{0x0A, new EventFlagVillagerMemoryPlayer(25, 255, 010, "Friendship" )}, // 親密度
|
||||
{0x0B, new EventFlagVillagerMemoryPlayer(0 , 7 , 011, "TalkCountToday" )}, // 今日の会話回数(通算)
|
||||
{0x0C, new EventFlagVillagerMemoryPlayer(0 , 7 , 012, "TalkCountInNpcHouseToday" )}, // 今日NPCの家での会話回数
|
||||
{0x0D, new EventFlagVillagerMemoryPlayer(0 , 1 , 013, "HasAcquaintanceship" )}, // 面識ありか
|
||||
{0x0E, new EventFlagVillagerMemoryPlayer(0 , 1 , 014, "SitBenchFlag" )}, // NPCをベンチに座らせる
|
||||
{0x12, new EventFlagVillagerMemoryPlayer(0 , 1 , 018, "TalkedAsSameVillageResident" )}, // 同じ村の住人として会話した
|
||||
{0x13, new EventFlagVillagerMemoryPlayer(0 , 1 , 019, "InputGreeting" )}, // 挨拶を設定した
|
||||
{0x14, new EventFlagVillagerMemoryPlayer(0 , 1 , 020, "InputPhraseMemory" )}, // 口癖を設定した
|
||||
{0x15, new EventFlagVillagerMemoryPlayer(0 , 1 , 021, "InputNickname" )}, // ニックネームを設定した
|
||||
{0x16, new EventFlagVillagerMemoryPlayer(0 , 1 , 022, "GEventTalkBeforeFlag" )}, // イベント共通|イベント前に会話した?
|
||||
{0x17, new EventFlagVillagerMemoryPlayer(0 , 1 , 023, "GEventTalkProgressFlag" )}, // イベント共通|イベント中に会話した?
|
||||
{0x18, new EventFlagVillagerMemoryPlayer(0 , 1 , 024, "GEventTalkAfterFlag" )}, // イベント共通|イベント後に会話した?
|
||||
{0x19, new EventFlagVillagerMemoryPlayer(0 , 1 , 025, "InduceFailFlag" )}, // 勧誘失敗フラグ
|
||||
{0x1A, new EventFlagVillagerMemoryPlayer(0 , 1 , 026, "InduceFailAlreadyInduced" )}, // 勧誘失敗理由|既に転入枠に勧誘されたNPCがいる
|
||||
{0x1B, new EventFlagVillagerMemoryPlayer(0 , 1 , 027, "InduceFailSameNpcLiving" )}, // 勧誘失敗理由|同名NPCが村に住んでいる
|
||||
{0x1C, new EventFlagVillagerMemoryPlayer(0 , 1 , 028, "InduceFailSameNpcMoveIn" )}, // 勧誘失敗理由|同名NPCが転入確定状態
|
||||
{0x1D, new EventFlagVillagerMemoryPlayer(0 , 1 , 029, "IsReceiptWrappingItem" )}, // プレゼントできるアイテムを受け取った
|
||||
{0x1E, new EventFlagVillagerMemoryPlayer(0 , 1 , 030, "BirhdayNPresentFlag" )}, // NPC誕生日|プレゼント渡した?
|
||||
{0x1F, new EventFlagVillagerMemoryPlayer(0 , 1 , 031, "NicknameOriginal" )}, // ニックネーム設定本人
|
||||
{0x20, new EventFlagVillagerMemoryPlayer(0 , 1 , 032, "BirhdayNTalkInFlag" )}, // NPC誕生日|家に入ったときの会話した?
|
||||
{0x21, new EventFlagVillagerMemoryPlayer(0 , 1 , 033, "BirhdayNTalkFlag" )}, // NPC誕生日|誕生会で会話した?
|
||||
{0x22, new EventFlagVillagerMemoryPlayer(0 , 1 , 034, "BirhdayNTalkOutFlag" )}, // NPC誕生日|家から出たときの会話した?
|
||||
{0x23, new EventFlagVillagerMemoryPlayer(0 , 1 , 035, "BirhdayPTalkFlag" )}, // プレイヤ誕生日|おめでとう会話した?
|
||||
{0x24, new EventFlagVillagerMemoryPlayer(0 , 1 , 036, "BirhdayPCupcakeFlag" )}, // プレイヤ誕生日|カップケーキ渡した?
|
||||
{0x25, new EventFlagVillagerMemoryPlayer(0 , 1 , 037, "FriendOfHostPC" )}, // ホストPCのフレンドとして訪問した
|
||||
{0x26, new EventFlagVillagerMemoryPlayer(0 , 1 , 038, "TalkClothesPToday" )}, // 今日ClothesPを見たか?
|
||||
{0x27, new EventFlagVillagerMemoryPlayer(0 , 1 , 039, "TalkedDuringSick" )}, // 病気中に会話した
|
||||
{0x28, new EventFlagVillagerMemoryPlayer(0 , 1 , 040, "InduceFailVillagerMax" )}, // 勧誘失敗理由|住人数が既に上限
|
||||
{0x29, new EventFlagVillagerMemoryPlayer(0 , 1 , 041, "FirstMeetGreetAtThisVillage" )}, // この村で初対面の挨拶をした
|
||||
{0x2A, new EventFlagVillagerMemoryPlayer(0 , 1 , 042, "MoveCancelTalk" )}, // 引越し中止の報告したか
|
||||
{0x2B, new EventFlagVillagerMemoryPlayer(0 , 1 , 043, "BirthdayPAttendance" )}, // プレイヤ誕生日|出席していた
|
||||
{0x2C, new EventFlagVillagerMemoryPlayer(0 , 255, 044, "TalkCountInHouseToday" )}, // 室内で会話した回数 (訪問クエスト中)
|
||||
{0x2D, new EventFlagVillagerMemoryPlayer(0 , 1 , 045, "TalkClothesNToday" )}, // 今日ClothesNを見たか?
|
||||
{0x2E, new EventFlagVillagerMemoryPlayer(0 , 1 , 046, "TalkWantToday" )}, // 今日Wantを聞いたか?
|
||||
{0x2F, new EventFlagVillagerMemoryPlayer(0 , 1 , 047, "InduceFailSellPlaceNothing" )}, // 勧誘失敗理由|売り土地が無い
|
||||
{0x30, new EventFlagVillagerMemoryPlayer(0 , 1 , 048, "IsPlayedQuestVisitN" )}, // 訪問Nをクリアした事ある?
|
||||
{0x31, new EventFlagVillagerMemoryPlayer(0 , 1 , 049, "AcquaintanceshipFlagOff" )}, // 面識フラグを立てない
|
||||
{0x32, new EventFlagVillagerMemoryPlayer(0 , 1 , 050, "InducementAtMovingDay" )}, // 転出当日に勧誘された
|
||||
{0x33, new EventFlagVillagerMemoryPlayer(0 , 1 , 051, "ChokeOffMoveOut" )}, // 引越を引き止められた
|
||||
{0x34, new EventFlagVillagerMemoryPlayer(0 , 1 , 052, "InducementFlag" )}, // 勧誘されて来たか
|
||||
{0x35, new EventFlagVillagerMemoryPlayer(0 , 1 , 053, "ApproachQuestOrdered" )}, // アプローチ経由でのクエスト発注か?
|
||||
{0x37, new EventFlagVillagerMemoryPlayer(0 , 255, 055, "ContinuousTalkCount" )}, // 連続会話回数
|
||||
{0x38, new EventFlagVillagerMemoryPlayer(0 , 255, 056, "Again2Count" )}, // XX_Again2を聞いた回数
|
||||
{0x39, new EventFlagVillagerMemoryPlayer(0 , 1 , 057, "TalkDIY" )}, // DIY会話をした
|
||||
{0x3B, new EventFlagVillagerMemoryPlayer(0 , 1 , 059, "NewYearGreetingFlag" )}, // 新年(1月1日)のあいさつをした
|
||||
{0x3C, new EventFlagVillagerMemoryPlayer(0 , 1 , 060, "GotRecipeorMaterial" )}, // DIYレシピか素材をもらった
|
||||
{0x3D, new EventFlagVillagerMemoryPlayer(0 , 1 , 061, "GotMaterialItemFull" )}, // 素材をもらうときもちものがいっぱいだった
|
||||
{0x3E, new EventFlagVillagerMemoryPlayer(0 , 1 , 062, "MailedVisitPLayout" )}, // 訪問Pで手紙を投函した
|
||||
{0x3F, new EventFlagVillagerMemoryPlayer(0 , 1 , 063, "FirstMeetGreetAtThisVillageToday" )}, // この村で初対面の挨拶をした当日
|
||||
{0x40, new EventFlagVillagerMemoryPlayer(0 , 1 , 064, "ReceivedFirstPresent" )}, // NPCから初めてPresentを貰った
|
||||
{0x41, new EventFlagVillagerMemoryPlayer(0 , 1 , 065, "BanClothesN1Today" )}, // ClothesN1:今日は禁止
|
||||
{0x42, new EventFlagVillagerMemoryPlayer(0 , 1 , 066, "BanClothesN2Now" )}, // ClothesN2:今は禁止
|
||||
{0x43, new EventFlagVillagerMemoryPlayer(0 , 1 , 067, "BanClothesN1Now" )}, // ClothesN1:今は禁止
|
||||
{0x44, new EventFlagVillagerMemoryPlayer(0 , 1 , 068, "TalkWeekNow" )}, // 今、Weekを聞いたか?
|
||||
{0x45, new EventFlagVillagerMemoryPlayer(0 , 1 , 069, "TalkQuestionsNow" )}, // 今、Questionsを聞いたか?
|
||||
{0x46, new EventFlagVillagerMemoryPlayer(0 , 1 , 070, "TalkAlwaysNow" )}, // 今、Alwaysを聞いたか?
|
||||
{0x47, new EventFlagVillagerMemoryPlayer(0 , 1 , 071, "TalkAlwaysABNow" )}, // 今、AlwaysABを聞いたか?
|
||||
{0x48, new EventFlagVillagerMemoryPlayer(0 , 1 , 072, "TalkWeatherSPNow" )}, // 今、WeatherSPを聞いたか?
|
||||
{0x49, new EventFlagVillagerMemoryPlayer(0 , 1 , 073, "TalkWeatherNow" )}, // 今、Weatherを聞いたか?
|
||||
{0x4A, new EventFlagVillagerMemoryPlayer(0 , 1 , 074, "TalkSeasonsNow" )}, // 今、Seasonsを聞いたか?
|
||||
{0x4B, new EventFlagVillagerMemoryPlayer(0 , 1 , 075, "TalkSpotSPNow" )}, // 今、SpotSPを聞いたか?
|
||||
{0x4C, new EventFlagVillagerMemoryPlayer(0 , 1 , 076, "TalkSpotNow" )}, // 今、Spotを聞いたか?
|
||||
{0x4E, new EventFlagVillagerMemoryPlayer(0 , 1 , 078, "TalkItemNNow" )}, // 今、ItemNを聞いたか?
|
||||
{0x4F, new EventFlagVillagerMemoryPlayer(0 , 1 , 079, "TalkItemPNow" )}, // 今、ItemPを聞いたか?
|
||||
{0x50, new EventFlagVillagerMemoryPlayer(0 , 1 , 080, "TalkRumorOActionToday" )}, // 今日RumorOP_Action(同じ島の住人P)を聞いたか?
|
||||
{0x51, new EventFlagVillagerMemoryPlayer(0 , 1 , 081, "TalkRumorVActionToday" )}, // 今日RumorOP_Action(ビジター)を聞いたか?
|
||||
{0x52, new EventFlagVillagerMemoryPlayer(0 , 1 , 082, "TalkRumorOFavoriteToday" )}, // 今日RumorO_Favoriteを聞いたか?
|
||||
{0x53, new EventFlagVillagerMemoryPlayer(0 , 1 , 083, "TalkRumorNToday" )}, // 今日このNPCからRumorN1を聞いたか?
|
||||
{0x54, new EventFlagVillagerMemoryPlayer(0 , 1 , 084, "TalkFreeMovingNow" )}, // 今、FreeD_Movingを聞いたか?
|
||||
{0x55, new EventFlagVillagerMemoryPlayer(0 , 1 , 085, "TalkFreeEventNow" )}, // 今日FreeE_Eventを聞いたか?
|
||||
{0x56, new EventFlagVillagerMemoryPlayer(0 , 1 , 086, "TalkSnpcNow" )}, // 今日Snpcを聞いたか?
|
||||
{0x57, new EventFlagVillagerMemoryPlayer(0 , 1 , 087, "TalkFreeFNow" )}, // 今、FreeFを聞いたか?
|
||||
{0x58, new EventFlagVillagerMemoryPlayer(0 , 1 , 088, "TalkFreeGNow" )}, // 今、FreeGを聞いたか?
|
||||
{0x5A, new EventFlagVillagerMemoryPlayer(0 , 1 , 090, "TalkHHAToday" )}, // 今日FreeE_HHAを聞いたか?
|
||||
{0x5B, new EventFlagVillagerMemoryPlayer(0 , 5 , 091, "TalkReSelectLast" )}, // 再抽選前に聞いたファイル識別番号
|
||||
{0x5C, new EventFlagVillagerMemoryPlayer(0 , 1 , 092, "HHABuildCelebraition" )}, // 増築祝いの手紙を出した
|
||||
{0x5D, new EventFlagVillagerMemoryPlayer(0 , 1 , 093, "ChineseNewYearGreetingFlag" )}, // 旧正月のあいさつをした
|
||||
{0x5E, new EventFlagVillagerMemoryPlayer(0 , 1 , 094, "TalkFreeZodiacNow" )}, // 今、FreeF_NewYear_Zodiacを聞いたか?
|
||||
{0x5F, new EventFlagVillagerMemoryPlayer(0 , 1 , 095, "TalkProgressNpcHouseBuilt" )}, // 初期NPCの家に関するFreeH_Progressを聞いたか?
|
||||
{0x60, new EventFlagVillagerMemoryPlayer(0 , 1 , 096, "TalkProgressMyHouseBuilt" )}, // 現在プレイヤーの家に関するFreeH_Progressを聞いたか?
|
||||
{0x61, new EventFlagVillagerMemoryPlayer(0 , 1 , 097, "TalkProgressMyHouseBuilt2" )}, // 現在プレイヤーの家(地下室完成)に関するFreeH_Progressを聞いたか?
|
||||
{0x62, new EventFlagVillagerMemoryPlayer(0 , 1 , 098, "TalkProgressMigrantsQuest" )}, // 移住クエストに関するFreeH_Progressを聞いたか?
|
||||
{0x63, new EventFlagVillagerMemoryPlayer(0 , 1 , 099, "TalkProgressHelpBuildShop" )}, // 商店の木材集めに関するFreeH_Progressを聞いたか?
|
||||
{0x64, new EventFlagVillagerMemoryPlayer(0 , 1 , 100, "TalkProgressOfficeBuilt" )}, // 案内所の完成に関するFreeH_Progressを聞いたか?
|
||||
{0x65, new EventFlagVillagerMemoryPlayer(0 , 1 , 101, "TalkProgressShopBuilt" )}, // 商店の完成に関するFreeH_Progressを聞いたか?
|
||||
{0x66, new EventFlagVillagerMemoryPlayer(0 , 1 , 102, "TalkProgressShopBuilt2" )}, // 商店の拡張に関するFreeH_Progressを聞いたか?
|
||||
{0x67, new EventFlagVillagerMemoryPlayer(0 , 1 , 103, "TalkProgressMuseumTent" )}, // フータのテントに関するFreeH_Progressを聞いたか?
|
||||
{0x68, new EventFlagVillagerMemoryPlayer(0 , 1 , 104, "TalkProgressMuseumBuilt" )}, // 博物館の完成に関するFreeH_Progressを聞いたか?
|
||||
{0x69, new EventFlagVillagerMemoryPlayer(0 , 1 , 105, "TalkProgressTailorBuilt" )}, // 仕立て屋の完成に関するFreeH_Progressを聞いたか?
|
||||
{0x6A, new EventFlagVillagerMemoryPlayer(0 , 1 , 106, "TalkProgressBridgeBuilt" )}, // 初めての橋の完成に関するFreeH_Progressを聞いたか?
|
||||
{0x6B, new EventFlagVillagerMemoryPlayer(0 , 1 , 107, "TalkProgressSlopeBuilt" )}, // 初めての坂の完成に関するFreeH_Progressを聞いたか?
|
||||
{0x6C, new EventFlagVillagerMemoryPlayer(0 , 1 , 108, "TalkProgressOtherPlayerMoveIn" )}, // 他プレイヤーの移住に関するFreeH_Progressを聞いたか?
|
||||
{0x6D, new EventFlagVillagerMemoryPlayer(0 , 1 , 109, "TalkRumorPActionToday" )}, // 今日RumorP_Action(現在プレイヤー)を聞いたか?
|
||||
{0x6E, new EventFlagVillagerMemoryPlayer(0 , 1 , 110, "FirstNpcEarlyAcquaintanceFlag" )}, // NPC宅がテントだった頃からの知り合い?
|
||||
{0x6F, new EventFlagVillagerMemoryPlayer(0 , 1 , 111, "TalkSickCured" )}, // Curedを聞いたか?
|
||||
{0x70, new EventFlagVillagerMemoryPlayer(0 , 1 , 112, "StandingUpFlag" )}, // NPCを立たせる
|
||||
{0x71, new EventFlagVillagerMemoryPlayer(0 , 1 , 113, "StoodUpFlag" )}, // NPCが立った
|
||||
{0x72, new EventFlagVillagerMemoryPlayer(0 , 1 , 114, "TalkBeefaceToday" )}, // 今日BeeFaceを聞いたか?
|
||||
{0x73, new EventFlagVillagerMemoryPlayer(0 , 1 , 115, "TalkItchingToday" )}, // 今日Itchingを聞いたか?
|
||||
{0x74, new EventFlagVillagerMemoryPlayer(0 , 1 , 116, "TalkEarlyLateToday" )}, // 今日EarlyLateを聞いたか?
|
||||
{0x75, new EventFlagVillagerMemoryPlayer(0 , 1 , 117, "FinishVisitPToday" )}, // 今日訪問Pクエストをしたか?
|
||||
{0x76, new EventFlagVillagerMemoryPlayer(0 , 1 , 118, "FinishVisitNToday" )}, // 今日訪問Nクエストをしたか?
|
||||
{0x77, new EventFlagVillagerMemoryPlayer(0 , 1 , 119, "OrderQuest" )}, // クエストを発注or達成した
|
||||
{0x78, new EventFlagVillagerMemoryPlayer(0 , 1 , 120, "FirstGreetingAtNpcHome" )}, // 引越し当日のダンボール自宅でNPCと初対面会話をした(自分の村)
|
||||
{0x79, new EventFlagVillagerMemoryPlayer(0 , 1 , 121, "AppF_MoveinGiftOccured" )}, // 引越し挨拶アプローチ会話発生済か?
|
||||
{0x7A, new EventFlagVillagerMemoryPlayer(0 , 1 , 122, "UncollectedFishishTreasureHunt" )}, // 宝未回収でクエスト終了した
|
||||
{0x7B, new EventFlagVillagerMemoryPlayer(0 , 7 , 123, "TalkCountInFacilityToday" )}, // 今日の会話回数(施設用)
|
||||
{0x7C, new EventFlagVillagerMemoryPlayer(0 , 1 , 124, "FriendshipBecomeAcqHToday" )}, // 今日親密度が知人(高)に到達した
|
||||
{0x7D, new EventFlagVillagerMemoryPlayer(0 , 1 , 125, "FriendshipBecomeAcqH" )}, // 親密度が知人(高)に到達済み
|
||||
{0x7E, new EventFlagVillagerMemoryPlayer(0 , 3 , 126, "DC_NPCBirthdayFlag" )}, // NPC誕生日|おでかけ先の村でもらうお返しの種類
|
||||
{0x7F, new EventFlagVillagerMemoryPlayer(0 , 1 , 127, "EasterCannotGetNnpcRecipeFlag" )}, // イースター|このNPCから受け取り損ねたレシピがある?
|
||||
};
|
||||
|
||||
private const string Unknown = "???";
|
||||
|
||||
public static string GetName(ushort index, uint count, IReadOnlyDictionary<string, string> str)
|
||||
{
|
||||
var dict = List;
|
||||
if (dict.TryGetValue(index, out var val))
|
||||
{
|
||||
string name = val.Name;
|
||||
if (str.TryGetValue(name, out var translated))
|
||||
name = translated;
|
||||
return $"{index:00} - {name} = {count}";
|
||||
}
|
||||
return $"{index:00} - {Unknown} = {count}";
|
||||
}
|
||||
|
||||
public static string GetName(ushort index, uint count)
|
||||
{
|
||||
var dict = List;
|
||||
if (dict.TryGetValue(index, out var val))
|
||||
return $"{index:00} - {val.Name} = {count}";
|
||||
return $"{index:00} - {Unknown} = {count}";
|
||||
}
|
||||
}
|
||||
}
|
||||
47
NHSE.Core/Structures/Villager/GSaveMemory.cs
Normal file
47
NHSE.Core/Structures/Villager/GSaveMemory.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
namespace NHSE.Core
|
||||
{
|
||||
public class GSaveMemory : IVillagerOrigin
|
||||
{
|
||||
public const int SIZE = 0x5F0;
|
||||
|
||||
public readonly byte[] Data;
|
||||
|
||||
public GSaveMemory(byte[] data) => Data = data;
|
||||
|
||||
public GSavePlayerId PlayerId => Data.Slice(0, GSavePlayerId.SIZE).ToStructure<GSavePlayerId>();
|
||||
|
||||
public uint TownID
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, 0x00);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, 0x00);
|
||||
}
|
||||
|
||||
public string TownName
|
||||
{
|
||||
get => StringUtil.GetString(Data, 0x04, 10);
|
||||
set => StringUtil.GetBytes(value, 10).CopyTo(Data, 0x04);
|
||||
}
|
||||
public byte[] GetTownIdentity() => Data.Slice(0x00, 20);
|
||||
|
||||
public uint PlayerID
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, 0x1C);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, 0x1C);
|
||||
}
|
||||
|
||||
public string PlayerName
|
||||
{
|
||||
get => StringUtil.GetString(Data, 0x20, 10);
|
||||
set => StringUtil.GetBytes(value, 10).CopyTo(Data, 0x20);
|
||||
}
|
||||
|
||||
public byte[] GetPlayerIdentity() => Data.Slice(0x1C, 20);
|
||||
|
||||
public byte[] GetEventFlags() => Data.Slice(0x38, 0x100);
|
||||
public void SetEventFlags(byte[] value) => value.CopyTo(Data, 0x38);
|
||||
|
||||
public byte Friendship { get => Data[0x38 + 10]; set => Data[0x38 + 10] = value; }
|
||||
};
|
||||
}
|
||||
@@ -28,37 +28,42 @@ public VillagerPersonality Personality
|
||||
set => Data[2] = (byte)value;
|
||||
}
|
||||
|
||||
public uint TownID
|
||||
public string TownName => GetMemory(0).TownName;
|
||||
public byte[] GetTownIdentity() => GetMemory(0).GetTownIdentity();
|
||||
public string PlayerName => GetMemory(0).PlayerName;
|
||||
public byte[] GetPlayerIdentity() => GetMemory(0).GetPlayerIdentity();
|
||||
|
||||
public const int PlayerMemoryCount = 8;
|
||||
|
||||
public GSaveMemory GetMemory(int index)
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, 0x04);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, 0x04);
|
||||
if ((uint) index >= PlayerMemoryCount)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
var bytes = Data.Slice(0x4 + (index * GSaveMemory.SIZE), GSaveMemory.SIZE);
|
||||
return new GSaveMemory(bytes);
|
||||
}
|
||||
|
||||
public string TownName
|
||||
public GSaveMemory[] GetMemories()
|
||||
{
|
||||
get => StringUtil.GetString(Data, 0x08, 10);
|
||||
set => StringUtil.GetBytes(value, 10).CopyTo(Data, 0x08);
|
||||
}
|
||||
public byte[] GetTownIdentity() => Data.Slice(0x04, 4 + 20);
|
||||
|
||||
public uint PlayerID
|
||||
{
|
||||
get => BitConverter.ToUInt32(Data, 0x20);
|
||||
set => BitConverter.GetBytes(value).CopyTo(Data, 0x20);
|
||||
var memories = new GSaveMemory[PlayerMemoryCount];
|
||||
for (int i = 0; i < memories.Length; i++)
|
||||
memories[i] = GetMemory(i);
|
||||
return memories;
|
||||
}
|
||||
|
||||
public string PlayerName
|
||||
public void SetMemory(GSaveMemory memory, int index)
|
||||
{
|
||||
get => StringUtil.GetString(Data, 0x24, 10);
|
||||
set => StringUtil.GetBytes(value, 10).CopyTo(Data, 0x24);
|
||||
if ((uint)index >= PlayerMemoryCount)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
|
||||
memory.Data.CopyTo(Data, 0x4 + (index * GSaveMemory.SIZE));
|
||||
}
|
||||
|
||||
public byte[] GetPlayerIdentity() => Data.Slice(0x20, 4 + 20);
|
||||
|
||||
public string TownName2
|
||||
public void SetMemories(IReadOnlyList<GSaveMemory> memories)
|
||||
{
|
||||
get => StringUtil.GetString(Data, 0x5CC, 10);
|
||||
set => StringUtil.GetBytes(value, 10).CopyTo(Data, 0x5CC);
|
||||
for (int i = 0; i < memories.Count; i++)
|
||||
SetMemory(memories[i], i);
|
||||
}
|
||||
|
||||
public string CatchPhrase
|
||||
@@ -109,5 +114,17 @@ public DesignPatternPRO Design
|
||||
get => new DesignPatternPRO(Data.Slice(0x12128, DesignPatternPRO.SIZE));
|
||||
set => value.Data.CopyTo(Data, 0x12128);
|
||||
}
|
||||
|
||||
public void SetFriendshipAll(byte value = byte.MaxValue)
|
||||
{
|
||||
for (int i = 0; i < PlayerMemoryCount; i++)
|
||||
{
|
||||
var m = GetMemory(i);
|
||||
if (string.IsNullOrEmpty(m.PlayerName))
|
||||
continue;
|
||||
m.Friendship = value;
|
||||
SetMemory(m, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ void DumpB(string fn, byte[] bytes, string dir = "bin")
|
||||
DumpS("eventFlagPlayer.txt", GetEventFlagNames(pathBCSV));
|
||||
DumpS("eventFlagHouse.txt", GetEventFlagHouse(pathBCSV));
|
||||
DumpS("eventFlagVillager.txt", GetVillagerEventFlagNames(pathBCSV));
|
||||
DumpS("eventFlagVillagerMemoryPlayer.txt", GetVillagerEventFlagNamesMemoryPlayer(pathBCSV));
|
||||
DumpS("eventFlagLand.txt", GetLandEventFlagNames(pathBCSV));
|
||||
|
||||
DumpS("ItemKind.txt", GetPossibleEnum(pathBCSV, "ItemParam.bcsv", 0xFC275E86));
|
||||
@@ -527,6 +528,41 @@ private static IEnumerable<string> GetVillagerEventFlagNames(string pathBCSV, st
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetVillagerEventFlagNamesMemoryPlayer(string pathBCSV, string fn = "EventFlagsNpcMemoryParam.bcsv")
|
||||
{
|
||||
var bcsv = BCSVConverter.GetBCSV(pathBCSV, fn);
|
||||
var dict = bcsv.GetFieldDictionary();
|
||||
var finit = dict[0xD55938BD];
|
||||
var fmax = dict[0xBD7682F5];
|
||||
var fname = dict[0x45F320F2];
|
||||
var findex = dict[0x54706054];
|
||||
var fcomment = dict[0x85CF1615];
|
||||
|
||||
var result = new List<string>();
|
||||
for (int i = 0; i < bcsv.EntryCount; i++)
|
||||
{
|
||||
var isinit = bcsv.ReadValue(i, finit);
|
||||
var iinit = short.Parse(isinit);
|
||||
|
||||
var ismax = bcsv.ReadValue(i, fmax);
|
||||
var imax = short.Parse(ismax);
|
||||
|
||||
var iid = bcsv.ReadValue(i, findex);
|
||||
var index = (ushort)short.Parse(iid);
|
||||
|
||||
var name = bcsv.ReadValue(i, fname).TrimEnd('\0');
|
||||
var comment = bcsv.ReadValue(i, fcomment).TrimEnd('\0');
|
||||
|
||||
var paddedName = $"\"{name}\"".PadRight(45, ' ');
|
||||
var v = $"new {nameof(EventFlagVillagerMemoryPlayer)}({iinit,-2}, {imax,-3}, {index:000}, {paddedName})";
|
||||
var kvp = $"{{0x{index:X2}, {v}}}, // {comment}";
|
||||
result.Add(kvp);
|
||||
}
|
||||
|
||||
result.Sort();
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetLandEventFlagNames(string pathBCSV, string fn = "EventFlagsLandParam.bcsv")
|
||||
{
|
||||
var bcsv = BCSVConverter.GetBCSV(pathBCSV, fn);
|
||||
|
||||
20
NHSE.WinForms/Controls/VillagerEditor.Designer.cs
generated
20
NHSE.WinForms/Controls/VillagerEditor.Designer.cs
generated
@@ -52,6 +52,7 @@ private void InitializeComponent()
|
||||
this.B_EditFurniture = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.B_EditVillagerRoom = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.B_EditVillagerDesign = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.B_EditVillagerPlayerMemories = new System.Windows.Forms.ToolStripMenuItem();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_Variant)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_Species)).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)(this.PB_Villager)).BeginInit();
|
||||
@@ -255,31 +256,39 @@ private void InitializeComponent()
|
||||
this.CM_EditVillager.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.B_EditFurniture,
|
||||
this.B_EditVillagerRoom,
|
||||
this.B_EditVillagerDesign});
|
||||
this.B_EditVillagerDesign,
|
||||
this.B_EditVillagerPlayerMemories});
|
||||
this.CM_EditVillager.Name = "CM_EditPlayer";
|
||||
this.CM_EditVillager.Size = new System.Drawing.Size(175, 70);
|
||||
this.CM_EditVillager.Size = new System.Drawing.Size(186, 114);
|
||||
//
|
||||
// B_EditFurniture
|
||||
//
|
||||
this.B_EditFurniture.Name = "B_EditFurniture";
|
||||
this.B_EditFurniture.Size = new System.Drawing.Size(180, 22);
|
||||
this.B_EditFurniture.Size = new System.Drawing.Size(185, 22);
|
||||
this.B_EditFurniture.Text = "Edit Furniture";
|
||||
this.B_EditFurniture.Click += new System.EventHandler(this.B_EditFurniture_Click);
|
||||
//
|
||||
// B_EditVillagerRoom
|
||||
//
|
||||
this.B_EditVillagerRoom.Name = "B_EditVillagerRoom";
|
||||
this.B_EditVillagerRoom.Size = new System.Drawing.Size(180, 22);
|
||||
this.B_EditVillagerRoom.Size = new System.Drawing.Size(185, 22);
|
||||
this.B_EditVillagerRoom.Text = "Edit Room";
|
||||
this.B_EditVillagerRoom.Click += new System.EventHandler(this.B_EditVillagerRoom_Click);
|
||||
//
|
||||
// B_EditVillagerDesign
|
||||
//
|
||||
this.B_EditVillagerDesign.Name = "B_EditVillagerDesign";
|
||||
this.B_EditVillagerDesign.Size = new System.Drawing.Size(180, 22);
|
||||
this.B_EditVillagerDesign.Size = new System.Drawing.Size(185, 22);
|
||||
this.B_EditVillagerDesign.Text = "Edit Design Pattern";
|
||||
this.B_EditVillagerDesign.Click += new System.EventHandler(this.B_EditVillagerDesign_Click);
|
||||
//
|
||||
// B_EditVillagerPlayerMemories
|
||||
//
|
||||
this.B_EditVillagerPlayerMemories.Name = "B_EditVillagerPlayerMemories";
|
||||
this.B_EditVillagerPlayerMemories.Size = new System.Drawing.Size(185, 22);
|
||||
this.B_EditVillagerPlayerMemories.Text = "Edit Player Memories";
|
||||
this.B_EditVillagerPlayerMemories.Click += new System.EventHandler(this.B_EditVillagerPlayerMemories_Click);
|
||||
//
|
||||
// VillagerEditor
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
@@ -340,5 +349,6 @@ private void InitializeComponent()
|
||||
private System.Windows.Forms.ToolStripMenuItem B_EditFurniture;
|
||||
private System.Windows.Forms.ToolStripMenuItem B_EditVillagerRoom;
|
||||
private System.Windows.Forms.ToolStripMenuItem B_EditVillagerDesign;
|
||||
private System.Windows.Forms.ToolStripMenuItem B_EditVillagerPlayerMemories;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,5 +208,24 @@ private void B_EditVillagerDesign_Click(object sender, EventArgs e)
|
||||
if (editor.ShowDialog() == DialogResult.OK)
|
||||
v.Design = tmp[0];
|
||||
}
|
||||
|
||||
private void B_EditVillagerPlayerMemories_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (ModifierKeys == Keys.Shift)
|
||||
{
|
||||
var prompt = WinFormsUtil.Prompt(MessageBoxButtons.YesNo, MessageStrings.MsgVillagerFriendshipMax);
|
||||
if (prompt != DialogResult.Yes)
|
||||
return;
|
||||
foreach (var villager in Villagers)
|
||||
villager.SetFriendshipAll();
|
||||
System.Media.SystemSounds.Asterisk.Play();
|
||||
return;
|
||||
}
|
||||
|
||||
var v = Villagers[VillagerIndex];
|
||||
using var editor = new VillagerMemoryEditor(v);
|
||||
if (editor.ShowDialog() == DialogResult.OK)
|
||||
{ } // editor saves our changes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,9 @@
|
||||
<Compile Update="Subforms\Villager\SaveRoomFloorWallEditor.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Subforms\Villager\VillagerMemoryEditor.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Subforms\Villager\VillagerFlagEditor.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
||||
@@ -7,6 +7,57 @@ namespace NHSE.WinForms
|
||||
{
|
||||
public static class MiscDumpHelper
|
||||
{
|
||||
public static void DumpVillagerMemoryPlayer(Villager v, GSaveMemory memory)
|
||||
{
|
||||
using var sfd = new SaveFileDialog
|
||||
{
|
||||
Filter = "New Horizons Villager Player Memory (*.nhvpm)|*.nhvpm|All files (*.*)|*.*",
|
||||
FileName = $"{v.InternalName}.nhvpm",
|
||||
};
|
||||
if (sfd.ShowDialog() != DialogResult.OK)
|
||||
return;
|
||||
|
||||
var data = memory.Data;
|
||||
File.WriteAllBytes(sfd.FileName, data);
|
||||
}
|
||||
|
||||
public static bool LoadVillagerMemoryPlayer(Villager v, GSaveMemory[] memories, int index)
|
||||
{
|
||||
using var ofd = new OpenFileDialog
|
||||
{
|
||||
Filter = "New Horizons Villager Player Memory (*.nhvpm)|*.nhvpm|All files (*.*)|*.*",
|
||||
FileName = $"{v.InternalName}.nhvpm",
|
||||
};
|
||||
if (ofd.ShowDialog() != DialogResult.OK)
|
||||
return false;
|
||||
|
||||
var file = ofd.FileName;
|
||||
var fi = new FileInfo(file);
|
||||
const int expectLength = GSaveMemory.SIZE;
|
||||
if (fi.Length != expectLength)
|
||||
{
|
||||
WinFormsUtil.Error(MessageStrings.MsgCanceling, string.Format(MessageStrings.MsgDataSizeMismatchImport, fi.Length, expectLength));
|
||||
return false;
|
||||
}
|
||||
|
||||
var data = File.ReadAllBytes(file);
|
||||
var memory = new GSaveMemory(data);
|
||||
var old = memories[index];
|
||||
|
||||
if (!memory.IsOriginatedFrom(old))
|
||||
{
|
||||
string msg = string.Format(MessageStrings.MsgDataDidNotOriginateFromHost_0, old.PlayerName);
|
||||
var result = WinFormsUtil.Prompt(MessageBoxButtons.YesNoCancel, msg, MessageStrings.MsgAskUpdateValues);
|
||||
if (result == DialogResult.Cancel)
|
||||
return false;
|
||||
if (result == DialogResult.Yes)
|
||||
memory.ChangeOrigins(old, memory.Data);
|
||||
}
|
||||
|
||||
memories[index] = memory;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void DumpMuseum(Museum museum)
|
||||
{
|
||||
using var sfd = new SaveFileDialog
|
||||
|
||||
181
NHSE.WinForms/Subforms/Villager/VillagerMemoryEditor.Designer.cs
generated
Normal file
181
NHSE.WinForms/Subforms/Villager/VillagerMemoryEditor.Designer.cs
generated
Normal file
@@ -0,0 +1,181 @@
|
||||
namespace NHSE.WinForms
|
||||
{
|
||||
partial class VillagerMemoryEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.B_Cancel = new System.Windows.Forms.Button();
|
||||
this.B_Save = new System.Windows.Forms.Button();
|
||||
this.LB_Counts = new System.Windows.Forms.ListBox();
|
||||
this.NUD_Count = new System.Windows.Forms.NumericUpDown();
|
||||
this.L_Count = new System.Windows.Forms.Label();
|
||||
this.LB_Players = new System.Windows.Forms.ListBox();
|
||||
this.B_Dump = new System.Windows.Forms.Button();
|
||||
this.B_Load = new System.Windows.Forms.Button();
|
||||
this.GB_Flags = new System.Windows.Forms.GroupBox();
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_Count)).BeginInit();
|
||||
this.GB_Flags.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// B_Cancel
|
||||
//
|
||||
this.B_Cancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.B_Cancel.Location = new System.Drawing.Point(321, 268);
|
||||
this.B_Cancel.Name = "B_Cancel";
|
||||
this.B_Cancel.Size = new System.Drawing.Size(72, 23);
|
||||
this.B_Cancel.TabIndex = 7;
|
||||
this.B_Cancel.Text = "Cancel";
|
||||
this.B_Cancel.UseVisualStyleBackColor = true;
|
||||
this.B_Cancel.Click += new System.EventHandler(this.B_Cancel_Click);
|
||||
//
|
||||
// B_Save
|
||||
//
|
||||
this.B_Save.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.B_Save.Location = new System.Drawing.Point(399, 268);
|
||||
this.B_Save.Name = "B_Save";
|
||||
this.B_Save.Size = new System.Drawing.Size(72, 23);
|
||||
this.B_Save.TabIndex = 6;
|
||||
this.B_Save.Text = "Save";
|
||||
this.B_Save.UseVisualStyleBackColor = true;
|
||||
this.B_Save.Click += new System.EventHandler(this.B_Save_Click);
|
||||
//
|
||||
// LB_Counts
|
||||
//
|
||||
this.LB_Counts.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.LB_Counts.FormattingEnabled = true;
|
||||
this.LB_Counts.Location = new System.Drawing.Point(6, 39);
|
||||
this.LB_Counts.Name = "LB_Counts";
|
||||
this.LB_Counts.Size = new System.Drawing.Size(278, 199);
|
||||
this.LB_Counts.TabIndex = 8;
|
||||
this.LB_Counts.SelectedIndexChanged += new System.EventHandler(this.LB_Counts_SelectedIndexChanged);
|
||||
//
|
||||
// NUD_Count
|
||||
//
|
||||
this.NUD_Count.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.NUD_Count.Location = new System.Drawing.Point(212, 13);
|
||||
this.NUD_Count.Maximum = new decimal(new int[] {
|
||||
255,
|
||||
0,
|
||||
0,
|
||||
0});
|
||||
this.NUD_Count.Name = "NUD_Count";
|
||||
this.NUD_Count.Size = new System.Drawing.Size(72, 20);
|
||||
this.NUD_Count.TabIndex = 9;
|
||||
this.NUD_Count.ValueChanged += new System.EventHandler(this.NUD_Count_ValueChanged);
|
||||
//
|
||||
// L_Count
|
||||
//
|
||||
this.L_Count.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.L_Count.Location = new System.Drawing.Point(126, 13);
|
||||
this.L_Count.Name = "L_Count";
|
||||
this.L_Count.Size = new System.Drawing.Size(80, 20);
|
||||
this.L_Count.TabIndex = 10;
|
||||
this.L_Count.Text = "Value:";
|
||||
this.L_Count.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// LB_Players
|
||||
//
|
||||
this.LB_Players.FormattingEnabled = true;
|
||||
this.LB_Players.Location = new System.Drawing.Point(12, 12);
|
||||
this.LB_Players.Name = "LB_Players";
|
||||
this.LB_Players.Size = new System.Drawing.Size(163, 108);
|
||||
this.LB_Players.TabIndex = 11;
|
||||
this.LB_Players.SelectedIndexChanged += new System.EventHandler(this.LB_Players_SelectedIndexChanged);
|
||||
//
|
||||
// B_Dump
|
||||
//
|
||||
this.B_Dump.Location = new System.Drawing.Point(12, 126);
|
||||
this.B_Dump.Name = "B_Dump";
|
||||
this.B_Dump.Size = new System.Drawing.Size(79, 23);
|
||||
this.B_Dump.TabIndex = 13;
|
||||
this.B_Dump.Text = "Dump";
|
||||
this.B_Dump.UseVisualStyleBackColor = true;
|
||||
this.B_Dump.Click += new System.EventHandler(this.B_Dump_Click);
|
||||
//
|
||||
// B_Load
|
||||
//
|
||||
this.B_Load.Location = new System.Drawing.Point(96, 126);
|
||||
this.B_Load.Name = "B_Load";
|
||||
this.B_Load.Size = new System.Drawing.Size(79, 23);
|
||||
this.B_Load.TabIndex = 12;
|
||||
this.B_Load.Text = "Load";
|
||||
this.B_Load.UseVisualStyleBackColor = true;
|
||||
this.B_Load.Click += new System.EventHandler(this.B_Load_Click);
|
||||
//
|
||||
// GB_Flags
|
||||
//
|
||||
this.GB_Flags.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
|
||||
| System.Windows.Forms.AnchorStyles.Left)
|
||||
| System.Windows.Forms.AnchorStyles.Right)));
|
||||
this.GB_Flags.Controls.Add(this.LB_Counts);
|
||||
this.GB_Flags.Controls.Add(this.L_Count);
|
||||
this.GB_Flags.Controls.Add(this.NUD_Count);
|
||||
this.GB_Flags.Location = new System.Drawing.Point(181, 12);
|
||||
this.GB_Flags.Name = "GB_Flags";
|
||||
this.GB_Flags.Size = new System.Drawing.Size(290, 245);
|
||||
this.GB_Flags.TabIndex = 14;
|
||||
this.GB_Flags.TabStop = false;
|
||||
this.GB_Flags.Text = "Flags";
|
||||
//
|
||||
// VillagerMemoryEditor
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(483, 303);
|
||||
this.Controls.Add(this.GB_Flags);
|
||||
this.Controls.Add(this.B_Dump);
|
||||
this.Controls.Add(this.B_Load);
|
||||
this.Controls.Add(this.LB_Players);
|
||||
this.Controls.Add(this.B_Cancel);
|
||||
this.Controls.Add(this.B_Save);
|
||||
this.Icon = global::NHSE.WinForms.Properties.Resources.icon;
|
||||
this.MaximizeBox = false;
|
||||
this.MinimizeBox = false;
|
||||
this.Name = "VillagerMemoryEditor";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Villager Player Memory Editor";
|
||||
((System.ComponentModel.ISupportInitialize)(this.NUD_Count)).EndInit();
|
||||
this.GB_Flags.ResumeLayout(false);
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Button B_Cancel;
|
||||
private System.Windows.Forms.Button B_Save;
|
||||
private System.Windows.Forms.ListBox LB_Counts;
|
||||
private System.Windows.Forms.NumericUpDown NUD_Count;
|
||||
private System.Windows.Forms.Label L_Count;
|
||||
private System.Windows.Forms.ListBox LB_Players;
|
||||
private System.Windows.Forms.Button B_Dump;
|
||||
private System.Windows.Forms.Button B_Load;
|
||||
private System.Windows.Forms.GroupBox GB_Flags;
|
||||
}
|
||||
}
|
||||
113
NHSE.WinForms/Subforms/Villager/VillagerMemoryEditor.cs
Normal file
113
NHSE.WinForms/Subforms/Villager/VillagerMemoryEditor.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
using NHSE.Core;
|
||||
|
||||
namespace NHSE.WinForms
|
||||
{
|
||||
public partial class VillagerMemoryEditor : Form
|
||||
{
|
||||
private readonly Villager Villager;
|
||||
private readonly GSaveMemory[] Memories;
|
||||
|
||||
private int PlayerIndex = -1;
|
||||
private int FlagIndex = -1;
|
||||
private byte[] Flags = Array.Empty<byte>();
|
||||
|
||||
public VillagerMemoryEditor(Villager villager)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.TranslateInterface(GameInfo.CurrentLanguage);
|
||||
|
||||
Villager = villager;
|
||||
Memories = villager.GetMemories();
|
||||
|
||||
for (int i = 0; i < Memories.Length; i++)
|
||||
LB_Players.Items.Add($"{i} - {Memories[i].PlayerName} ({Memories[i].TownName})");
|
||||
|
||||
LB_Players.SelectedIndex = 0;
|
||||
|
||||
DialogResult = DialogResult.Cancel;
|
||||
LB_Counts.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
private void B_Cancel_Click(object sender, EventArgs e) => Close();
|
||||
|
||||
private void B_Save_Click(object sender, EventArgs e)
|
||||
{
|
||||
SavePlayer(PlayerIndex);
|
||||
Villager.SetMemories(Memories);
|
||||
DialogResult = DialogResult.OK;
|
||||
Close();
|
||||
}
|
||||
|
||||
private static string GetFlagDescription(int index, IReadOnlyList<byte> flags, IReadOnlyDictionary<string, string> str)
|
||||
{
|
||||
return EventFlagVillagerMemoryPlayer.GetName((ushort)index, flags[index], str);
|
||||
}
|
||||
|
||||
private void NUD_Count_ValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
var flagIndex = FlagIndex;
|
||||
if (flagIndex < 0)
|
||||
return;
|
||||
|
||||
Flags[FlagIndex] = (byte) NUD_Count.Value;
|
||||
LB_Counts.Items[FlagIndex] = GetFlagDescription(flagIndex, Flags, GameInfo.Strings.InternalNameTranslation);
|
||||
}
|
||||
|
||||
private void LB_Counts_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (LB_Counts.SelectedIndex < 0)
|
||||
return;
|
||||
|
||||
NUD_Count.Value = Flags[FlagIndex = LB_Counts.SelectedIndex];
|
||||
}
|
||||
|
||||
private void LB_Players_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
SavePlayer(PlayerIndex);
|
||||
PlayerIndex = LB_Players.SelectedIndex;
|
||||
LoadPlayer(PlayerIndex);
|
||||
}
|
||||
|
||||
private void LoadPlayer(in int playerIndex)
|
||||
{
|
||||
FlagIndex = -1;
|
||||
var index = LB_Counts.SelectedIndex;
|
||||
var memory = Memories[playerIndex];
|
||||
var flags = memory.GetEventFlags();
|
||||
|
||||
var str = GameInfo.Strings.InternalNameTranslation;
|
||||
LB_Counts.Items.Clear();
|
||||
for (int i = 0; i < flags.Length; i++)
|
||||
LB_Counts.Items.Add(GetFlagDescription((byte)i, flags, str));
|
||||
|
||||
Flags = flags;
|
||||
LB_Counts.SelectedIndex = FlagIndex = index;
|
||||
}
|
||||
|
||||
private void SavePlayer(in int playerIndex)
|
||||
{
|
||||
if (playerIndex < 0)
|
||||
return;
|
||||
|
||||
var memory = Memories[playerIndex];
|
||||
memory.SetEventFlags(Flags);
|
||||
}
|
||||
|
||||
private void B_Dump_Click(object sender, EventArgs e)
|
||||
{
|
||||
SavePlayer(PlayerIndex);
|
||||
MiscDumpHelper.DumpVillagerMemoryPlayer(Villager, Memories[PlayerIndex]);
|
||||
}
|
||||
|
||||
private void B_Load_Click(object sender, EventArgs e)
|
||||
{
|
||||
if (!MiscDumpHelper.LoadVillagerMemoryPlayer(Villager, Memories, PlayerIndex))
|
||||
return;
|
||||
LoadPlayer(PlayerIndex);
|
||||
System.Media.SystemSounds.Asterisk.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
120
NHSE.WinForms/Subforms/Villager/VillagerMemoryEditor.resx
Normal file
120
NHSE.WinForms/Subforms/Villager/VillagerMemoryEditor.resx
Normal file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -40,5 +40,7 @@ public static class MessageStrings
|
||||
public static string MsgTerrainSetElevation0 { get; set; } = "Set the elevation of all tiles on the map to 0?";
|
||||
public static string MsgTerrainSetAll { get; set; } = "Set the tile from the Tile Editor to all tiles on the map?";
|
||||
public static string MsgTerrainSetAllSkipExterior { get; set; } = "Do you want to skip the tiles in exterior acres (beach/rocks)?";
|
||||
|
||||
public static string MsgVillagerFriendshipMax { get; set; } = "Do you want to set all Villager Friendship memories to 255?";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user