diff --git a/pkNX.Structures.FlatBuffers/Arceus/Event/Trigger8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Event/Trigger8a.cs index 68d06b93..a80f8e39 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Event/Trigger8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Event/Trigger8a.cs @@ -22,35 +22,38 @@ public class TriggerTable8a : IFlatBufferArchive [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class Trigger8a { - [FlatBufferItem(00)] public Trigger8a_F00 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public Trigger8a_F01[] Field_01 { get; set; } = Array.Empty(); - [FlatBufferItem(02)] public Trigger8a_F02[] Field_02 { get; set; } = Array.Empty(); + [FlatBufferItem(00)] public TriggerMeta8a Meta { get; set; } = new(); + [FlatBufferItem(01)] public TriggerCondition8a[] Conditions { get; set; } = Array.Empty(); + [FlatBufferItem(02)] public TriggerCommand8a[] Commands { get; set; } = Array.Empty(); } [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] -public class Trigger8a_F00 +public class TriggerMeta8a { - [FlatBufferItem(00)] public ulong Field_00 { get; set; } - [FlatBufferItem(01)] public ulong Field_01 { get; set; } - [FlatBufferItem(02)] public string Field_02 { get; set; } = string.Empty; - [FlatBufferItem(03)] public string Field_03 { get; set; } = string.Empty; - [FlatBufferItem(04)] public string Field_04 { get; set; } = string.Empty; // assumed + [FlatBufferItem(00)] public TriggerType8a TriggerTypeID { get; set; } + [FlatBufferItem(01)] public ulong Unused_01 { get; set; } + [FlatBufferItem(02)] public string TriggerMetaArg1 { get; set; } = string.Empty; + [FlatBufferItem(03)] public string TriggerMetaArg2 { get; set; } = string.Empty; + [FlatBufferItem(04)] public string TriggerMetaArg3 { get; set; } = string.Empty; } [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] -public class Trigger8a_F01 +public class TriggerCondition8a : IHasCondition8a { - [FlatBufferItem(00)] public ulong Field_00 { get; set; } - [FlatBufferItem(01)] public byte Field_01 { get; set; } // unk - [FlatBufferItem(02)] public string Field_02 { get; set; } = string.Empty; - [FlatBufferItem(03)] public string Field_03 { get; set; } = string.Empty; // assumed - [FlatBufferItem(04)] public string Field_04 { get; set; } = string.Empty; // assumed + [FlatBufferItem(0)] public ConditionType8a ConditionTypeID { get; set; } + [FlatBufferItem(1)] public Condition8a ConditionID { get; set; } + [FlatBufferItem(2)] public string ConditionArg1 { get; set; } = string.Empty; + [FlatBufferItem(3)] public string ConditionArg2 { get; set; } = string.Empty; + [FlatBufferItem(4)] public string ConditionArg3 { get; set; } = string.Empty; + + // For interface compat + public string ConditionArg4 { get; set; } = string.Empty; + public string ConditionArg5 { get; set; } = string.Empty; } [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] -public class Trigger8a_F02 +public class TriggerCommand8a { - [FlatBufferItem(00)] public ulong Field_00 { get; set; } - [FlatBufferItem(01)] public string[] Field_01 { get; set; } = Array.Empty(); - [FlatBufferItem(02)] public string[] Field_02 { get; set; } = Array.Empty(); + [FlatBufferItem(00)] public TriggerCommandType8a CommandTypeID { get; set; } + [FlatBufferItem(01)] public string[] Arguments { get; set; } = Array.Empty(); } diff --git a/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerCommandType8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerCommandType8a.cs new file mode 100644 index 00000000..0934c023 --- /dev/null +++ b/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerCommandType8a.cs @@ -0,0 +1,69 @@ +using FlatSharp.Attributes; + +// ReSharper disable UnusedMember.Global +#pragma warning disable RCS1154 // Sort enum members. + +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferEnum(typeof(ulong))] +public enum TriggerCommandType8a : ulong +{ + AllPokeRecover = 0x35AE11B202B33FAB, // "all_poke_recover" + AutoSaveNg = 0x396A9D10B0C06938, // "auto_save_ng" + AutoSaveNgReset = 0x5A23A70C90B2E3C0, // "auto_save_ng_reset" + BagLostCall = 0x8CF3D91B280B82C9, // "bag_lost_call" + BoutiqueCall = 0x8212CBCB399C7F54, // "boutique_call" + CallBattle = 0xB54D19CA9F2B27A8, // "call_battle" + CallEvent = 0x466C5DFFFA6047DE, // "call_event" + CallRealTimeEvent = 0x1608695374913BA9, // "call_real_time_event" + CallTrainerBattle = 0x81FE18C0B68BFC12, // "call_trainer_battle" + CallTriggerBoot = 0xA6C73C7E028A667B, // "call_trigger_boot" + DemoPlay = 0xC68C92A921029B81, // "demo_play" + EndNushiBattle = 0xF4F2BE33D270D1F7, // "end_nushi_battle" + FinishRealTimeEvent = 0x6C0A8D2940D8F34A, // "finish_real_time_event" + FlagReset = 0x861AC906050FBC07, // "flag_reset" + FlagSet = 0x2719CB6B0BCC8398, // "flag_set" + ForceReport = 0x949ED0E99A38A7AF, // "force_report" + HugeOutbreakClear = 0x5B3F92D4849AB3AE, // "huge_outbreak_clear" + HugeOutbreakLottery = 0x1D29BC9A7BA7D242, // "huge_outbreak_lottery" + ItemAdd = 0x6D35E2EAB45C0F6E, // "item_add" + ItemBoxCall = 0x2D01C6B3EE7EC58D, // "item_box_call" + ItemDelete = 0xC59A0CC763D2A7A8, // "item_delete" + ItemSub = 0xD20CF4EA5CB0BEEF, // "item_sub" + LeaveWildPokemon = 0x635B9BF9C7B6BEA3, // "leave_wild_pokemon" + MapChange = 0x1223758E1F82495E, // "map_change" + MapChangeGameOver = 0xA93595533A427B98, // "map_change_game_over" + MoneyAdd = 0x5195731EE2BCA693, // "money_add" + PlayerAnimationStateReset = 0x3221105676A499B3, // "player_animation_state_reset" + PokeAdd = 0x82E032DE25CE78E0, // "poke_add" + PokeBoxCall = 0x1F24A4FCF859527B, // "poke_box_call" + PokePassEvolution = 0x36C4EA8E0C07226A, // "poke_pass_evolution" + PokeSelectMenuCall = 0xE75986350917856A, // "poke_select_menu_call" + QuestAdvance = 0x1F9C392CEFBB1B58, // "quest_advance" + QuestEnd = 0x7F22B0CAFA5DFD63, // "quest_end" + QuestProgressSet = 0x8F4ECBA903BE3CD2, // "quest_progress_set" + QuestStart = 0xACDCFB9B749A3D26, // "quest_start" + ResetWormhole = 0xEEE8243BDF3948B0, // "reset_wormhole" + ResidentWorkClear = 0x908FC6969AB5250D, // "resident_work_clear" + SelectAreaCall = 0xDA71107BF9807C04, // "select_area_call" + SetDressupItem = 0x2D7A8BD9982C8840, // "set_dressup_item" + SetFocusItem = 0x3F669C91AF847B32, // "set_focus_item" + ShopCall = 0x9E3A5EB597D7F7A6, // "shop_call" + ShowExpResult = 0x6C9C2C4BF7EC3138, // "show_exp_result" + SimpleMessageChara = 0xEA08F03627CA535F, // "simple_message_chara" + SimpleMessageSystem = 0x388689E19B68D6F9, // "simple_message_system" + SleepWormhole = 0x6C50ACC5A3018C28, // "sleep_wormhole" + SoundEventPost = 0x53D11252A6F42576, // "sound_event_post" + SoundSituationMixer = 0x82EBFDB54C8107A5, // "sound_situation_mixer" + SpawnWildPokemon = 0x39A6CB761A05967B, // "spawn_wild_pokemon" + StartNushiBattle = 0x081BF500D5709C9C, // "start_nushi_battle" + StartWormhole = 0x2156F9E8ED44730D, // "start_wormhole" + TimeChange = 0x48D69D8788B2FE61, // "time_change" + TimeLock = 0xF7911B293C7F980E, // "time_lock" + TimeRelease = 0x6A28CB95A4BBFF62, // "time_release" + TriggerCommandPreset = 0x8CD4CD78EA36EF55, // "trigger_command_preset" + WorkAdd = 0xB956CAA67E5EB58C, // "work_add" + WorkSet = 0x555FCEA6D6C83ADB, // "work_set" + + None = 0xCBF29CE484222645, // "" +} diff --git a/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerType8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerType8a.cs new file mode 100644 index 00000000..ced0fa26 --- /dev/null +++ b/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerType8a.cs @@ -0,0 +1,44 @@ +using FlatSharp.Attributes; + +// ReSharper disable UnusedMember.Global +#pragma warning disable RCS1154 // Sort enum members. + +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferEnum(typeof(ulong))] +public enum TriggerType8a : ulong +{ + AreaChange = 0x7E23ECD43CE201A1, // "area_change" + BattleLose = 0x054B378194CDEB91, // "battle_lose" + BattleWin = 0xB2EE750DBCD8FFD6, // "battle_win" + BgEvent = 0x64224581923358E9, // "bg_event" + BootUrankUpgrade = 0x77E1D0135FEDD0E0, // "boot_urank_upgrade" + CaptureFailedPoke = 0xC09BBA82558CCB11, // "capture_failed_poke" + CapturedEventPoke = 0x82DCDEC11E4B902C, // "captured_event_poke" + CapturedPoke = 0xF9DCAFF7B9A4A1B5, // "captured_poke" + DigHit = 0xDEDAFE9CD0903841, // "dig_hit" + DoorEvent = 0xF8026805B0390A1E, // "door_event" + EventBattleLose = 0x956AB57BCBE24AC2, // "event_battle_lose" + EventBattleWin = 0x78891EA1EB1719B7, // "event_battle_win" + FinishEventKisekaeHome = 0xEC5C94E0F6AF0025, // "finish_event_kisekae_home" + FinishEventScript = 0x2E632ED350D2BC4D, // "finish_event_script" + FinishNushiBattle = 0x3B78EA5ACF12B68F, // "finish_nushi_battle" + FinishRideMiniGame = 0x43264D2AEB95F420, // "finish_ride_mini_game" + FinishSelectArea = 0xAB29E81B22E196F1, // "finish_select_area" + FinishThrowMiniGame = 0x474D107BF9969EDC, // "finish_throw_mini_game" + GameOver = 0x57BA8020944AD222, // "game_over" + GameOverAfterward = 0x5F2F50327A48756D, // "game_over_afterward" + GetMkrg = 0x9FE3F0D2163599C7, // "get_mkrg" + NpcTalk = 0xAB00E1A6F5D27687, // "npc_talk" + PosEnter = 0xBD5314EC693575D4, // "pos_enter" + PosExit = 0xC01E67CA2AAD4DFA, // "pos_exit" + PosStay = 0xDB75191D739E26DF, // "pos_stay" + ThrowNg = 0x63CFDE902FA005E7, // "throw_ng" + TrainerBanditLose = 0xA4E0055DFAB6E157, // "trainer_bandit_lose" + TrainerBanditWin = 0x2E11B56C5A55E9E8, // "trainer_bandit_win" + TrainerBattleLose = 0x7DACDFC0F3964597, // "trainer_battle_lose" + TrainerBattleWin = 0xB7942BC60882A228, // "trainer_battle_win" + WildPokeEscape = 0xE22F524AAE64337F, // "wild_poke_escape" + + None = 0xCBF29CE484222645, // "" +} diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/Trigger8aUtil.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/Trigger8aUtil.cs new file mode 100644 index 00000000..dc0d00d7 --- /dev/null +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/Trigger8aUtil.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace pkNX.Structures.FlatBuffers +{ + public static class Trigger8aUtil + { + public static IEnumerable GetTriggerTableSummary(TriggerTable8a tab) + { + foreach (var trg in tab.Table) + { + yield return "Trigger:"; + foreach (var line in GetTriggerSummary(trg)) + yield return $"\t{line}"; + } + } + + public static IEnumerable GetTriggerSummary(Trigger8a trg) + { + yield return "Meta:"; + yield return $"\t{GetTriggerMetaSummary(trg.Meta)}"; + yield return "Conditions:"; + foreach (var line in GetTriggerConditionsSummary(trg.Conditions)) + yield return $"\t{line}"; + yield return "Commands:"; + foreach (var line in GetTriggerCommandsSummary(trg.Commands)) + yield return $"\t{line}"; + } + + public static string GetTriggerMetaSummary(TriggerMeta8a meta) + { + if (meta.Unused_01 != 0) + throw new ArgumentException("TriggerMeta has unused field set?"); + + var argsSummary = GetTriggerArgsSummary(meta.TriggerMetaArg1, meta.TriggerMetaArg2, meta.TriggerMetaArg3); + + if (Enum.IsDefined(typeof(TriggerType8a), meta.TriggerTypeID)) + return $"{meta.TriggerTypeID}({argsSummary})"; + else + return $"0x{(ulong)meta.TriggerTypeID:X16}({argsSummary})"; + } + + public static IEnumerable GetTriggerConditionsSummary(IEnumerable conds) + { + foreach (var cond in conds) + yield return $"{Condition8aUtil.GetConditionTypeSummary(cond)}: {Condition8aUtil.GetConditionSummary(cond)}"; + } + + public static IEnumerable GetTriggerCommandsSummary(IEnumerable cmds) + { + foreach (var cmd in cmds) + yield return GetTriggerCommandSummary(cmd); + } + + public static string GetTriggerCommandSummary(TriggerCommand8a cmd) + { + var argsSummary = GetTriggerArgsSummary(cmd.Arguments); + + if (Enum.IsDefined(typeof(TriggerCommandType8a), cmd.CommandTypeID)) + return $"{cmd.CommandTypeID}({argsSummary})"; + else + return $"0x{(ulong)cmd.CommandTypeID:X16}({argsSummary})"; + } + + public static string GetTriggerArgsSummary(params string[] args) + { + var firstEmpty = -1; + for (var i = 0; i < args.Length; i++) + { + if (firstEmpty >= 0 && !string.IsNullOrEmpty(args[i])) + throw new ArgumentException($"Invalid TriggerArg at index {i}!"); + else if (firstEmpty < 0 && string.IsNullOrEmpty(args[i])) + firstEmpty = i; + } + + return string.Join(", ", args.Select(s => $"\"{s}\"").Take(firstEmpty >= 0 ? firstEmpty : args.Length)); + } + } +} diff --git a/pkNX.WinForms/Dumping/DumperPLA.Designer.cs b/pkNX.WinForms/Dumping/DumperPLA.Designer.cs index bf657ed3..9b635628 100644 --- a/pkNX.WinForms/Dumping/DumperPLA.Designer.cs +++ b/pkNX.WinForms/Dumping/DumperPLA.Designer.cs @@ -59,6 +59,7 @@ private void InitializeComponent() this.Tab_Future = new System.Windows.Forms.TabPage(); this.flowLayoutPanel4 = new System.Windows.Forms.FlowLayoutPanel(); this.B_OpenFolder = new System.Windows.Forms.Button(); + this.B_EventTriggers = new System.Windows.Forms.Button(); this.TC_Options.SuspendLayout(); this.Tab_General.SuspendLayout(); this.flowLayoutPanel1.SuspendLayout(); @@ -294,6 +295,7 @@ private void InitializeComponent() this.flowLayoutPanel3.Controls.Add(this.B_Outbreak); this.flowLayoutPanel3.Controls.Add(this.B_MoveShop); this.flowLayoutPanel3.Controls.Add(this.B_ScriptCommandNames); + this.flowLayoutPanel3.Controls.Add(this.B_EventTriggers); this.flowLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; this.flowLayoutPanel3.Location = new System.Drawing.Point(3, 3); this.flowLayoutPanel3.Name = "flowLayoutPanel3"; @@ -399,6 +401,16 @@ private void InitializeComponent() this.B_OpenFolder.UseVisualStyleBackColor = true; this.B_OpenFolder.Click += new System.EventHandler(this.B_OpenFolder_Click); // + // B_EventTriggers + // + this.B_EventTriggers.Location = new System.Drawing.Point(132, 125); + this.B_EventTriggers.Name = "B_EventTriggers"; + this.B_EventTriggers.Size = new System.Drawing.Size(123, 55); + this.B_EventTriggers.TabIndex = 22; + this.B_EventTriggers.Text = "Event Triggers"; + this.B_EventTriggers.UseVisualStyleBackColor = true; + this.B_EventTriggers.Click += new System.EventHandler(this.B_EventTriggers_Click); + // // DumperPLA // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -455,5 +467,6 @@ private void InitializeComponent() private System.Windows.Forms.Button B_Placement; private System.Windows.Forms.Button B_Resident; private System.Windows.Forms.Button B_DumpDrops; + private System.Windows.Forms.Button B_EventTriggers; } } \ No newline at end of file diff --git a/pkNX.WinForms/Dumping/DumperPLA.cs b/pkNX.WinForms/Dumping/DumperPLA.cs index 3dd36df5..5cc1790f 100644 --- a/pkNX.WinForms/Dumping/DumperPLA.cs +++ b/pkNX.WinForms/Dumping/DumperPLA.cs @@ -117,6 +117,12 @@ private void B_DumpScriptCommands(object sender, EventArgs e) System.Media.SystemSounds.Asterisk.Play(); } + private void B_EventTriggers_Click(object sender, EventArgs e) + { + Dumper.DumpEventTriggers(); + System.Media.SystemSounds.Asterisk.Play(); + } + private void B_GetDex_Click(object sender, EventArgs e) { Dumper.DumpDex(); @@ -147,6 +153,5 @@ private void B_EggMove_Click(object sender, EventArgs e) System.Media.SystemSounds.Asterisk.Play(); } #endregion - } } diff --git a/pkNX.WinForms/Dumping/DumperPLA.resx b/pkNX.WinForms/Dumping/DumperPLA.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/pkNX.WinForms/Dumping/DumperPLA.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/pkNX.WinForms/Dumping/GameDumperPLA.cs b/pkNX.WinForms/Dumping/GameDumperPLA.cs index 79cbc6e0..d87e383d 100644 --- a/pkNX.WinForms/Dumping/GameDumperPLA.cs +++ b/pkNX.WinForms/Dumping/GameDumperPLA.cs @@ -1079,6 +1079,39 @@ public void DumpScriptID() File.WriteAllText(path, text); } + public void DumpEventTriggers() + { + var eventTriggerDir = Path.Combine(ROM.PathRomFS, "bin", "event", "event_progress", "trigger"); + var eventTriggerFiles = Directory.EnumerateFiles(eventTriggerDir, "*", SearchOption.AllDirectories).Where(p => Path.GetExtension(p) == ".bin"); + + + const string outFolder = "event_trigger"; + Directory.CreateDirectory(GetPath(outFolder)); + + var allLines = new List(); + + foreach (var f in eventTriggerFiles) + { + if (Path.GetFileName(f) == "trigger_preset.bin") + continue; + + var table = FlatBufferConverter.DeserializeFrom(f); + + var curLines = new List(); + curLines.Add($"File: {Path.GetFileName(f)}"); + + foreach (var line in Trigger8aUtil.GetTriggerTableSummary(table)) + curLines.Add($"\t{line}"); + + File.WriteAllLines(GetPath(outFolder, $"trigger_{Path.GetFileNameWithoutExtension(f).Replace("trigger_", string.Empty)}.txt"), curLines); + + allLines.AddRange(curLines); + allLines.Add(string.Empty); + } + + File.WriteAllLines(GetPath(outFolder, "triggerAll.txt"), allLines); + } + public void DumpMoveShop() { var file = ROM.GetFile(GameFile.MoveShop).FilePath;