diff --git a/Fahrenheit.Modules.ArchipelagoFFX.csproj b/Fahrenheit.Modules.ArchipelagoFFX.csproj index 6366003..9578b5c 100644 --- a/Fahrenheit.Modules.ArchipelagoFFX.csproj +++ b/Fahrenheit.Modules.ArchipelagoFFX.csproj @@ -1,9 +1,9 @@ - + 0.8.1-alpha - v1.0.0-alpha10 + v1.0.0-alpha11 @@ -18,11 +18,11 @@ - + - + @@ -129,5 +129,5 @@ - + diff --git a/src/archipelago.cs b/src/archipelago.cs index 50395df..a083c6f 100644 --- a/src/archipelago.cs +++ b/src/archipelago.cs @@ -1,7 +1,9 @@ using Archipelago.MultiClient.Net.Enums; +using ArchipelagoFFX.Client; +using ArchipelagoFFX.GUI; +using Fahrenheit; using Fahrenheit.Atel; using Fahrenheit.Events; -using Fahrenheit.FFX; using Fahrenheit.FFX.Ids; //using Fahrenheit.ImGuiNET; using System; @@ -12,27 +14,19 @@ using System.Linq; using System.Numerics; using System.Reflection; -using System.Runtime.InteropServices; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; - -using ArchipelagoFFX.Client; -using ArchipelagoFFX.GUI; - -using Fahrenheit; - -using static Fahrenheit.FFX.Globals; //using Fahrenheit.Modules.ArchipelagoFFX.GUI; using static ArchipelagoFFX.ArchipelagoData; -using static ArchipelagoFFX.Client.FFXArchipelagoClient; +using static Fahrenheit.FFX.Globals; using Color = Archipelago.MultiClient.Net.Models.Color; +using FhXCall = Fahrenheit.FFX.FhCall; namespace ArchipelagoFFX; [FhLoad(FhGameId.FFX)] public unsafe partial class ArchipelagoFFXModule : FhModule { - public static FhModContext mod_context; private static FileStream global_state_file; @@ -41,9 +35,9 @@ public unsafe partial class ArchipelagoFFXModule : FhModule { private static ushort last_room_id = 0; private static ushort last_entrance_id = 0; - public static ArchipelagoData.RegionEnum current_region = ArchipelagoData.RegionEnum.None; - public static Dictionary region_is_unlocked = []; - public static Dictionary region_states = []; + public static RegionEnum current_region = RegionEnum.None; + public static Dictionary region_is_unlocked = []; + public static Dictionary region_states = []; public static SortedDictionary excess_inventory = []; public static SortedDictionary other_inventory = []; @@ -63,16 +57,62 @@ public unsafe partial class ArchipelagoFFXModule : FhModule { public static nint prev_length = 0; public static nint prev_bank = 0; - public static FhLogger logger; + private FhModuleHandle _client_handle; + private ArchipelagoClientModule? _client; + + private FhModuleHandle _gui_handle; + private ArchipelagoGuiModule? _gui; + + private FhModuleHandle _overdrives_handle; + private OverdriveModule? _overdrives; + + private FhModuleHandle _deathlink_handle; + private DeathLinkModule? _deathlink; + + private FhModuleHandle _hardcore_dreams_end_handle; + private HardcoreDreamsEndModule? _hardcore_dreams_end; public ArchipelagoFFXModule() { init_hooks(); + init_custom_atel(); + + _client_handle = new(this); + _gui_handle = new(this); + _hardcore_dreams_end_handle = new(this); + _deathlink_handle = new(this); + } + + public override bool init(FhModContext mod_context, FileStream global_state_file) { + ArchipelagoFFXModule.mod_context = mod_context; + ArchipelagoFFXModule.global_state_file = global_state_file; + + FhApi.Events.Common.GameLoop.PreUpdate.subscribe(pre_update); + + return hook() + && _client_handle.try_get_module(out _client) + && _gui_handle.try_get_module(out _gui) + && _hardcore_dreams_end_handle.try_get_module(out _hardcore_dreams_end) + && _deathlink_handle.try_get_module(out _deathlink) + && post_init(); + } + + private bool post_init() { + // Initialize Archipelago Client + initalize_states(); + + //loadSeed(); + loadSeedList(); + load_global_state(); + + return true; } public static FhLangId? VoiceLanguage; public static FhLangId? TextLanguage; public static string LastSeed = ""; public static Dictionary SeedToServer = new(); + + //TODO: Transfer this to another file private class ArchipelagoGlobalState { public string LastVersion { get; set; } public FhLangId? VoiceLanguage { get; set; } @@ -82,66 +122,75 @@ private class ArchipelagoGlobalState { public Dictionary SeedToServer { get; set; } public bool ShowRecentItems { get; set; } - public ArchipelagoGlobalState() { - this.LastVersion = ArchipelagoFFXModule.Version.ToString(); - this.VoiceLanguage = ArchipelagoFFXModule.VoiceLanguage; - this.TextLanguage = ArchipelagoFFXModule.TextLanguage; - this.FontSize = ArchipelagoGUI.font_size; - this.LastSeed = ArchipelagoFFXModule.LastSeed; - this.SeedToServer = ArchipelagoFFXModule.SeedToServer; - this.ShowRecentItems = RecentItemsModule.show_recent_items; + public ArchipelagoGlobalState(ArchipelagoFFXModule module) { + LastVersion = ArchipelagoFFXModule.Version.ToString(); + VoiceLanguage = ArchipelagoFFXModule.VoiceLanguage; + TextLanguage = ArchipelagoFFXModule.TextLanguage; + FontSize = module._gui!.font_size; + LastSeed = ArchipelagoFFXModule.LastSeed; + SeedToServer = ArchipelagoFFXModule.SeedToServer; + ShowRecentItems = RecentItemsModule.show_recent_items; } } + //TODO: Transfer this to another file private class ArchipelagoState { - public string SeedId { get; set; } - public Dictionary region_states { get; set; } - public Dictionary region_is_unlocked { get; set; } - public Dictionary unlocked_characters { get; set; } - public SortedDictionary excess_inventory { get; set; } - public SortedDictionary other_inventory { get; set; } - public int[] celestial_level { get; set; } - public HashSet local_checked_locations { get; set; } - public int received_items { get; set; } - public bool enable_hardcore_dreams_end { get; set; } - public bool enable_deathlink { get; set; } - public string deathlink_send_type { get; set; } - public string deathlink_receive_type { get; set; } + public string SeedId { get; set; } + + public Dictionary region_states { get; set; } + public Dictionary region_is_unlocked { get; set; } + + public Dictionary unlocked_characters { get; set; } + + public SortedDictionary excess_inventory { get; set; } + public SortedDictionary other_inventory { get; set; } + + public int[] celestial_level { get; set; } + + public HashSet local_checked_locations { get; set; } + public int received_items { get; set; } + + public bool enable_hardcore_dreams_end { get; set; } + + public bool enable_deathlink { get; set; } + public string deathlink_send_type { get; set; } + public string deathlink_receive_type { get; set; } public bool skip_state_updates { get; set; } - public ArchipelagoState() { - this.SeedId = ArchipelagoFFXModule.seed.Options.SeedId; - this.region_states = ArchipelagoFFXModule.region_states; - this.region_is_unlocked = ArchipelagoFFXModule.region_is_unlocked; - this.unlocked_characters = ArchipelagoFFXModule.unlocked_characters; - this.excess_inventory = ArchipelagoFFXModule.excess_inventory; - this.other_inventory = ArchipelagoFFXModule.other_inventory; - this.celestial_level = ArchipelagoFFXModule.celestial_level; - this.skip_state_updates = ArchipelagoFFXModule.skip_state_updates; - this.local_checked_locations = FFXArchipelagoClient.local_checked_locations; - this.received_items = FFXArchipelagoClient.received_items; - this.enable_hardcore_dreams_end = HardcoreDreamsEndModule.get_enabled(); - this.enable_deathlink = DeathLinkModule.get_enabled(); - this.deathlink_send_type = DeathLinkModule.get_send_type(); - this.deathlink_receive_type = DeathLinkModule.get_receive_type(); + public ArchipelagoState(ArchipelagoFFXModule module) { + SeedId = ArchipelagoFFXModule.seed.Options.SeedId; + region_states = ArchipelagoFFXModule.region_states; + region_is_unlocked = ArchipelagoFFXModule.region_is_unlocked; + unlocked_characters = ArchipelagoFFXModule.unlocked_characters; + excess_inventory = ArchipelagoFFXModule.excess_inventory; + other_inventory = ArchipelagoFFXModule.other_inventory; + celestial_level = ArchipelagoFFXModule.celestial_level; + skip_state_updates = ArchipelagoFFXModule.skip_state_updates; + local_checked_locations = module._client!.local_checked_locations; + received_items = module._client!.received_items; + enable_hardcore_dreams_end = module._hardcore_dreams_end!.get_enabled(); + enable_deathlink = module._deathlink!.get_enabled(); + deathlink_send_type = module._deathlink!.get_send_type(); + deathlink_receive_type = module._deathlink!.get_receive_type(); } } + //TODO: Transfer this to another file public record Location(string location_name, int location_id, uint item_id, string item_name, string player_name); public struct ArchipelagoSeedOptions { [JsonInclude] public string PlayerName; [JsonInclude] public string SeedId; - [JsonInclude] public ArchipelagoData.Goal Goal; - [JsonInclude] public ArchipelagoData.GoalRequirement GoalRequirement; + [JsonInclude] public Goal Goal; + [JsonInclude] public GoalRequirement GoalRequirement; [JsonInclude] public int RequiredPartyMembers; [JsonInclude] public int RequiredPrimers; [JsonInclude] public int APMultiplier; [JsonInclude] public int AlwaysSensor; - [JsonInclude] public ArchipelagoData.CaptureRequirement CaptureRequirement; + [JsonInclude] public CaptureRequirement CaptureRequirement; [JsonInclude] public int AlwaysCapture; [JsonInclude] public int CaptureDamage; [JsonInclude] public int EncounterWeighting; @@ -155,15 +204,15 @@ public ArchipelagoSeedOptions() { PlayerName = ""; SeedId = ""; - Goal = ArchipelagoData.Goal.YuYevon; - GoalRequirement = ArchipelagoData.GoalRequirement.None; + Goal = Goal.YuYevon; + GoalRequirement = GoalRequirement.None; RequiredPartyMembers = 1; RequiredPrimers = 0; APMultiplier = 1; AlwaysSensor = 0; - CaptureRequirement = ArchipelagoData.CaptureRequirement.None; + CaptureRequirement = CaptureRequirement.None; AlwaysCapture = 0; CaptureDamage = 0; EncounterWeighting = 0; @@ -206,16 +255,17 @@ public struct ArchipelagoSeed { public Dictionary Gear { get; set; } public ArchipelagoSeed() { - this.Name = ArchipelagoFFXModule.seed.Name; - this.Options = ArchipelagoFFXModule.seed.Options; - this.Locations = ArchipelagoFFXModule.seed.Locations; - this.Gear = ArchipelagoFFXModule.seed.Gear; + Name = ArchipelagoFFXModule.seed.Name; + Options = ArchipelagoFFXModule.seed.Options; + Locations = ArchipelagoFFXModule.seed.Locations; + Gear = ArchipelagoFFXModule.seed.Gear; } } public record ArchipelagoItem(uint id, string name, string player) { //public GCHandle name_handle = GCHandle.Alloc(FhEncoding.Us.to_bytes(name), GCHandleType.Pinned); } + //TODO: Transfer this to another file public static List cached_strings = []; public record ArchipelagoLocations(ArchipelagoSeedLocations seed) { public Dictionary treasure = seed.Treasure.ToDictionary( x => x.location_id, x => new ArchipelagoItem(x.item_id, x.item_name, x.player_name)); @@ -230,15 +280,15 @@ public record ArchipelagoLocations(ArchipelagoSeedLocations seed) { public bool location_to_item(int location, [MaybeNullWhen(false)] out ArchipelagoItem item) { var dict = (location & 0xF000) switch { - (int)FFXArchipelagoClient.ArchipelagoLocationType.Treasure => treasure, - (int)FFXArchipelagoClient.ArchipelagoLocationType.Boss => boss, - (int)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember => party_member, - (int)FFXArchipelagoClient.ArchipelagoLocationType.Overdrive => overdrive, - (int)FFXArchipelagoClient.ArchipelagoLocationType.OverdriveMode => overdrive_mode, - (int)FFXArchipelagoClient.ArchipelagoLocationType.Other => other, - (int)FFXArchipelagoClient.ArchipelagoLocationType.Recruit => recruit, - (int)FFXArchipelagoClient.ArchipelagoLocationType.SphereGrid => sphere_grid, - (int)FFXArchipelagoClient.ArchipelagoLocationType.Capture => capture, + (int)ArchipelagoClientModule.ArchipelagoLocationType.Treasure => treasure, + (int)ArchipelagoClientModule.ArchipelagoLocationType.Boss => boss, + (int)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember => party_member, + (int)ArchipelagoClientModule.ArchipelagoLocationType.Overdrive => overdrive, + (int)ArchipelagoClientModule.ArchipelagoLocationType.OverdriveMode => overdrive_mode, + (int)ArchipelagoClientModule.ArchipelagoLocationType.Other => other, + (int)ArchipelagoClientModule.ArchipelagoLocationType.Recruit => recruit, + (int)ArchipelagoClientModule.ArchipelagoLocationType.SphereGrid => sphere_grid, + (int)ArchipelagoClientModule.ArchipelagoLocationType.Capture => capture, _ => null, }; item = dict?.GetValueOrDefault(location & 0xFFF); @@ -253,21 +303,21 @@ public record ArchipelagoGear(int id, byte flags, byte owner, byte type, byte dm public static ArchipelagoLocations item_locations = new(new()); public static List loaded_seeds = []; - public static void loadSeedList() { + public void loadSeedList() { var seeds = mod_context.Paths.ResourcesDir.GetDirectories("seeds").FirstOrDefault()?.GetFiles("*.apffx"); if (seeds is null || seeds.Length == 0) { - logger.Warning("No seeds found"); + _logger.Warning("No seeds found"); return; } foreach (FileInfo file in seeds) { try { using ZipArchive apffx = ZipFile.OpenRead(file.FullName); - ZipArchiveEntry zippedOptions = apffx.GetEntry("options.json")!; - ZipArchiveEntry zippedLocations = apffx.GetEntry("locations.json")!; - ZipArchiveEntry zippedGear = apffx.GetEntry("gear.json")!; + ZipArchiveEntry? zippedOptions = apffx.GetEntry("options.json")!; + ZipArchiveEntry? zippedLocations = apffx.GetEntry("locations.json")!; + ZipArchiveEntry? zippedGear = apffx.GetEntry("gear.json")!; - if (zippedOptions != null && zippedLocations != null) { + if (zippedOptions is not null && zippedLocations is not null) { using Stream optionsStream = zippedOptions.Open(); using StreamReader optionsReader = new StreamReader(optionsStream); string optionsContents = optionsReader.ReadToEnd(); @@ -289,81 +339,65 @@ public static void loadSeedList() { Locations = loaded_locations, Gear = loaded_gear.ToDictionary(gear => gear.id), }); - } - else { + } else { throw new ArgumentNullException("apffx file is null"); } - } - catch (Exception e) { - logger.Warning($"Failed to load {file.Name} - {e.Message}"); + } catch (Exception e) { + _logger.Warning($"Failed to load {file.Name} - {e.Message}"); } } } - public static bool loadSeed() { + public bool loadSeed() { string message; - if (FFXArchipelagoClient.SeedId is not null) { - ArchipelagoSeed seed = loaded_seeds.FirstOrDefault(seed => seed.Options.SeedId == FFXArchipelagoClient.SeedId)!; + if (_client!.SeedId is not null) { + ArchipelagoSeed seed = loaded_seeds.FirstOrDefault(seed => seed.Options.SeedId == _client!.SeedId)!; if (seed.Options.SeedId is not null) return loadSeed(seed); message = "Seed for connected slot not found"; - ArchipelagoGUI.add_log_message([(message, Color.Red)]); - logger.Error($"Seed for connected slot not found"); + _gui!.add_log_message([(message, Color.Red)]); + _logger.Error(message); return false; - } else if (ArchipelagoGUI.selected_seed < loaded_seeds.Count) { - return loadSeed(loaded_seeds[ArchipelagoGUI.selected_seed]); } + + if (_gui!.selected_seed < loaded_seeds.Count) { + return loadSeed(loaded_seeds[_gui!.selected_seed]); + } + message = "No seeds found"; - ArchipelagoGUI.add_log_message([(message, Color.Red)]); - logger.Error(message); + _gui!.add_log_message([(message, Color.Red)]); + _logger.Error(message); return false; } - public static bool loadSeed(ArchipelagoSeed loaded_seed) { - lock (client_lock) { - if (FFXArchipelagoClient.is_connected) { - if (FFXArchipelagoClient.SeedId != loaded_seed.Options.SeedId) { + public bool loadSeed(ArchipelagoSeed loaded_seed) { + lock (_client!.client_lock) { + if (_client!.is_connected) { + if (_client!.SeedId != loaded_seed.Options.SeedId) { string message = "Seed doesn't match connected slot"; - ArchipelagoGUI.add_log_message([(message, Color.Red)]); - logger.Error(message); + _gui!.add_log_message([(message, Color.Red)]); + _logger.Error(message); return false; - } else { - if (FFXArchipelagoClient.current_server != null) { - SeedToServer[SeedId] = FFXArchipelagoClient.current_server; - } + } + + if (_client!.current_server != null) { + SeedToServer[_client!.SeedId] = _client!.current_server; } } } + initalize_states(); seed = loaded_seed; ap_multiplier = seed.Options.APMultiplier; - HardcoreDreamsEndModule.set_enabled(seed.Options.HardcoreDreamsEnd != 0); + _hardcore_dreams_end!.set_enabled(seed.Options.HardcoreDreamsEnd != 0); item_locations = new ArchipelagoLocations(seed.Locations); - ArchipelagoGUI.selected_seed = loaded_seeds.FindIndex(x => x.Options.SeedId == seed.Options.SeedId); + _gui!.selected_seed = loaded_seeds.FindIndex(x => x.Options.SeedId == seed.Options.SeedId); LastSeed = seed.Options.SeedId; save_global_state(); return true; } - public override bool init(FhModContext mod_context, FileStream global_state_file) { - ArchipelagoFFXModule.mod_context = mod_context; - ArchipelagoFFXModule.global_state_file = global_state_file; - - FhApi.Events.Common.GameLoop.PreUpdate.subscribe(pre_update); - - // Initialize Archipelago Client - - ArchipelagoGUI.shiori_file = ArchipelagoFFXModule.mod_context.Paths.ResourcesDir.GetFiles("shiori.png").FirstOrDefault(); - logger = _logger; - initalize_states(); - //loadSeed(); - loadSeedList(); - load_global_state(); - - return hook(); - } - public static void initalize_states() { region_is_unlocked.Clear(); foreach (var region in region_to_ids) { @@ -387,19 +421,22 @@ public static void initalize_states() { } + //TODO: Transfer to another file [GeneratedRegex("^(?0|[1-9]\\d*)\\.(?0|[1-9]\\d*)\\.(?0|[1-9]\\d*)(?:-(?(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+(?[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$")] private static partial Regex RegexSemVer(); - private static readonly string VersionString = Assembly.GetExecutingAssembly().GetCustomAttribute().InformationalVersion; + private static readonly string VersionString = Assembly.GetExecutingAssembly().GetCustomAttribute()!.InformationalVersion; private static readonly SemVer FullVersion = new(VersionString); private static readonly SemVer Version = FullVersion.WithoutMetadata(); - private record SemVer(int major, - int minor, - int patch, - string prerelease = "", - string buildmetadata = "") : IComparable, IEquatable { - public SemVer(string versionString) : this(0, 0, 0, "", "") { + private record SemVer( + int major, + int minor, + int patch, + string prerelease = "", + string buildmetadata = "" + ) : IComparable, IEquatable { + public SemVer(string versionString) : this(0, 0, 0) { try { var version_match = RegexSemVer().Match(versionString); major = int.Parse(version_match.Groups["major"].Value); @@ -414,7 +451,9 @@ public SemVer(string versionString) : this(0, 0, 0, "", "") { } public SemVer WithoutMetadata() { - return new SemVer(major, minor, patch, prerelease, ""); + return this with { + buildmetadata = "", + }; } public override string ToString() { @@ -484,24 +523,27 @@ public int CompareTo(SemVer? other) { } public override void save_local_state(FileStream local_state_file) { - ArchipelagoState state = new(); + ArchipelagoState state = new(this); JsonSerializer.Serialize(local_state_file, state); local_state_file.SetLength(local_state_file.Position); } + public override void load_local_state(FileStream local_state_file, FhLocalStateInfo local_state_info) { SemVer save_version = new(local_state_info.Version); if (save_version != Version) { - logger.Warning($"Saved with different AP version: current:{Version} save:{save_version}"); + _logger.Warning($"Saved with different AP version! Current is {Version} but save is {save_version}"); if (save_version == new SemVer(0, 0, 0)) { string message = "Invalid save version. Returning to main menu"; - ArchipelagoGUI.add_log_message([(message, Color.Red)]); - logger.Error(message); + _gui!.add_log_message([(message, Color.Red)]); + _logger.Error(message); return; - } else if (save_version < new SemVer(0, 8, 0, "alpha")) { + } + + if (save_version < new SemVer(0, 8, 0, "alpha")) { string message = "Incompatible version. Returning to main menu"; - ArchipelagoGUI.add_log_message([(message, Color.Red)]); - logger.Info(message); + _gui!.add_log_message([(message, Color.Red)]); + _logger.Info(message); return; } } @@ -509,19 +551,19 @@ public override void load_local_state(FileStream local_state_file, FhLocalStateI var loaded_state = JsonSerializer.Deserialize(local_state_file); if (loaded_state != null) { // Don't let client sync remote locations until seed is fully loaded - lock (FFXArchipelagoClient.client_lock) { + lock (_client!.client_lock) { ArchipelagoSeed seed = loaded_seeds.FirstOrDefault(s => s.Options.SeedId == loaded_state.SeedId)!; if (seed.Options.SeedId is not null) { if (!loadSeed(seed)) { - FFXArchipelagoClient.disconnect(); + _client!.disconnect(); return; } } else { string message = "Seed for loaded state not found"; - ArchipelagoGUI.add_log_message([(message, Color.Red)]); - logger.Error(message); - FFXArchipelagoClient.disconnect(); + _gui!.add_log_message([(message, Color.Red)]); + _logger.Error(message); + _client!.disconnect(); return; } foreach (var region in loaded_state.region_states) { @@ -546,35 +588,36 @@ public override void load_local_state(FileStream local_state_file, FhLocalStateI other_inventory[item_id] = amount; } - if (FFXArchipelagoClient.is_connected) + if (_client!.is_connected) { for (int i = 0; i <= 103; i++) { int qty = save_data->monsters_captured[i]; if (qty > 0) - FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_CAPTURE_" + i] = qty; + _client!.current_session!.DataStorage[Scope.Slot, "FFX_CAPTURE_" + i] = qty; else - FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_CAPTURE_" + i] = 0; + _client!.current_session!.DataStorage[Scope.Slot, "FFX_CAPTURE_" + i] = 0; } - FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_TIDUS_OVERDRIVE"] = save_data->tidus_limit_uses; + _client!.current_session!.DataStorage[Scope.Slot, "FFX_TIDUS_OVERDRIVE"] = save_data->tidus_limit_uses; } loaded_state.celestial_level.CopyTo(celestial_level, 0); - FFXArchipelagoClient.local_checked_locations.Clear(); - FFXArchipelagoClient.local_checked_locations.UnionWith(loaded_state.local_checked_locations); - FFXArchipelagoClient.local_locations_updated = true; - FFXArchipelagoClient.remote_locations_updated = true; - FFXArchipelagoClient.received_items = loaded_state.received_items; + _client!.local_checked_locations.Clear(); + _client!.local_checked_locations.UnionWith(loaded_state.local_checked_locations); + _client!.local_locations_updated = true; + _client!.remote_locations_updated = true; + _client!.received_items = loaded_state.received_items; skip_state_updates = loaded_state.skip_state_updates; } - HardcoreDreamsEndModule.set_enabled(loaded_state.enable_hardcore_dreams_end); + _hardcore_dreams_end!.set_enabled(loaded_state.enable_hardcore_dreams_end); - DeathLinkModule.set_enabled(loaded_state.enable_deathlink); - DeathLinkModule.set_send_type(loaded_state.deathlink_send_type); - DeathLinkModule.set_receive_type(loaded_state.deathlink_receive_type); + _deathlink!.set_enabled(loaded_state.enable_deathlink); + _deathlink!.set_send_type(loaded_state.deathlink_send_type); + _deathlink!.set_receive_type(loaded_state.deathlink_receive_type); } } - public static bool load_global_state() { + + public bool load_global_state() { try { global_state_file.Position = 0; var loaded_state = JsonSerializer.Deserialize(global_state_file); @@ -582,9 +625,9 @@ public static bool load_global_state() { VoiceLanguage = loaded_state.VoiceLanguage; TextLanguage = loaded_state.TextLanguage; - ArchipelagoGUI.voice_lang = VoiceLanguage.HasValue ? (byte)VoiceLanguage.Value : (byte)0xFF; - ArchipelagoGUI.text_lang = TextLanguage.HasValue ? (byte)TextLanguage.Value : (byte)0xFF; - ArchipelagoGUI.font_size = loaded_state.FontSize; + _gui!.voice_lang = VoiceLanguage.HasValue ? (byte)VoiceLanguage.Value : (byte)0xFF; + _gui!.text_lang = TextLanguage.HasValue ? (byte)TextLanguage.Value : (byte)0xFF; + _gui!.font_size = loaded_state.FontSize; LastSeed = loaded_state.LastSeed; RecentItemsModule.show_recent_items = loaded_state.ShowRecentItems; @@ -596,23 +639,24 @@ public static bool load_global_state() { if (loaded_seeds.Count > 0) { int selected_seed = loaded_seeds.FindIndex(x => x.Options.SeedId == LastSeed); if (selected_seed == -1) selected_seed = 0; - ArchipelagoGUI.selected_seed = selected_seed; - ArchipelagoGUI.client_input_name = loaded_seeds[selected_seed].Options.PlayerName; + _gui!.selected_seed = selected_seed; + _gui!.client_input_name = loaded_seeds[selected_seed].Options.PlayerName; if (SeedToServer.TryGetValue(LastSeed, out string? server)) { - ArchipelagoGUI.client_input_address = server; + _gui!.client_input_address = server; } else { - ArchipelagoGUI.client_input_address = ArchipelagoGUI.DEFAULT_CLIENT_ADDRESS; + _gui!.client_input_address = ArchipelagoGuiModule.DEFAULT_CLIENT_ADDRESS; } } return true; - } - catch (Exception) { + } catch (Exception e) { + _logger.Error($"Could not load global state: {e.Message}"); return false; } } - public static bool save_global_state() { - ArchipelagoGlobalState state = new(); + + public bool save_global_state() { + ArchipelagoGlobalState state = new(this); global_state_file.Position = 0; JsonSerializer.Serialize(global_state_file, state); global_state_file.SetLength(global_state_file.Position); @@ -622,15 +666,15 @@ public static bool save_global_state() { public void pre_update(UpdateLoopEventArgs args) { // Update Archipelago Client - FFXArchipelagoClient.update(); - if (last_story_progress != Globals.save_data->story_progress) { - ushort story_progress = Globals.save_data->story_progress; + _client!.update(); + if (last_story_progress != save_data->story_progress) { + ushort story_progress = save_data->story_progress; _logger.Info($"story_progress changed: {last_story_progress} -> {story_progress}"); - if (current_region != ArchipelagoData.RegionEnum.None) { - ArchipelagoData.ArchipelagoRegion region = region_states[current_region]; + if (current_region != RegionEnum.None) { + ArchipelagoRegion region = region_states[current_region]; if (region.story_checks.TryGetValue(story_progress, out var storyCheck)) { - storyCheck.check_delegate?.Invoke(region); + storyCheck.check_delegate?.Invoke(region, _client!, this); if (storyCheck.return_to_airship) { call_warp_to_map(382, 0); } @@ -649,23 +693,22 @@ public void pre_update(UpdateLoopEventArgs args) { if (completedPilgrimages >= pilgrimageStoryChecks.Length) { color = Color.Green; } - ArchipelagoGUI.add_log_message([(message, color)]); + _gui!.add_log_message([(message, color)]); } } } last_story_progress = story_progress; } - if (last_room_id != Globals.save_data->current_room_id && Globals.save_data->current_room_id != 0xFFFF) { - _logger.Info($"Room changed: Entered {Globals.save_data->current_room_id} at entrance {Globals.save_data->current_spawnpoint}"); + if (last_room_id != save_data->current_room_id && save_data->current_room_id != 0xFFFF) { + _logger.Info($"Room changed: Entered {save_data->current_room_id} at entrance {save_data->current_spawnpoint}"); on_map_change(); - last_room_id = Globals.save_data->current_room_id; - last_entrance_id = Globals.save_data->current_spawnpoint; + last_room_id = save_data->current_room_id; + last_entrance_id = save_data->current_spawnpoint; - lock (client_lock) { - if (FFXArchipelagoClient.is_connected) - { - FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_ROOM"] = last_room_id; + lock (_client!.client_lock) { + if (_client!.is_connected) { + _client!.current_session!.DataStorage[Scope.Slot, "FFX_ROOM"] = last_room_id; } } } @@ -676,7 +719,7 @@ public void pre_update(UpdateLoopEventArgs args) { } } - public override void handle_input() { + public void handle_input(UpdateLoopEventArgs e) { /* if (Globals.Input.select.held) { if (Globals.Input.l1.just_pressed) { @@ -685,34 +728,35 @@ public override void handle_input() { } } */ - if (Globals.Input.l1.held && Globals.Input.r1.held && Globals.Input.start.just_pressed) { + if (Input.l1.is_pressed && Input.r1.is_pressed && Input.start.is_pressed) { _logger.Debug("Soft Reset"); //Globals.save_data->current_room_id = 23; - if (Globals.Battle.btl->battle_state != 0) { - Globals.Battle.btl->battle_end_type = 1; + if (Battle.btl->battle_state != 0) { + Battle.btl->battle_end_type = 1; } else { call_warp_to_map(23, 0); } } - if (Input.select.held && Input.l1.just_pressed) { + + if (Input.select.is_pressed && Input.l1.is_pressed) { #if DEBUG - AtelBasicWorker* worker0 = Globals.Atel.controllers[0].worker(0); + AtelBasicWorker* worker0 = Atel.controllers[0].worker(0); float minDistance = -1; int closestEntranceIndex = -1; for (int i = 0; i < worker0->script_chunk->map_entrances.Length; i++) { MapEntrance entrance = worker0->script_chunk->map_entrances[i]; Vector4 pos = new(entrance.x, entrance.y, entrance.z, 0); - float distance = (Globals.actors->chr_pos_vec - pos).Length(); - logger.Debug($"Entrance: pos:({entrance.x}, {entrance.y}, {entrance.z}) distance:{distance}"); + float distance = (actors->chr_pos_vec - pos).Length(); + _logger.Debug($"Entrance: pos:({entrance.x}, {entrance.y}, {entrance.z}) distance:{distance}"); if (closestEntranceIndex == -1 || distance < minDistance) { minDistance = distance; closestEntranceIndex = i; } } MapEntrance closestEntrance = worker0->script_chunk->map_entrances[closestEntranceIndex]; - logger.Debug($"Closest Entrance: pos:({closestEntrance.x}, {closestEntrance.y}, {closestEntrance.z}) distance:{minDistance}"); + _logger.Debug($"Closest Entrance: pos:({closestEntrance.x}, {closestEntrance.y}, {closestEntrance.z}) distance:{minDistance}"); #endif @@ -782,12 +826,14 @@ public override void handle_input() { //_ChN_ReadSystemMGRP(2, 2); // Load Swimming motion group } - if (Globals.Input.select.held && Globals.Input.r1.just_pressed) { - _logger.Info($"Resetting party"); + + if (Input.select.is_pressed && Input.r1.is_pressed) { + _logger.Info("Resetting party"); save_party(); reset_party(); } - if (Globals.Input.select.held && Globals.Input.l2.just_pressed) { + + if (Input.select.is_pressed && Input.l2.is_pressed) { //foreach (var state in region_states) { // _logger.Debug($"{state.Key}: story_progress={state.Value.Story_progress}, room_id={state.Value.room_id}, entrance={state.Value.entrance}"); //} @@ -801,15 +847,15 @@ public override void handle_input() { _logger.Debug($"bank: {bank[0]} {bank[1]} {bank[2]} {bank[3]}"); */ //get_party_frontline(); - } - if (Globals.Input.select.held && Globals.Input.r2.just_pressed) { + + if (Input.select.is_pressed && Input.r2.is_pressed) { //_logger.Debug("Warp to Airship"); //call_warp_to_map(382, 0); } } - public static void call_warp_to_map(int map_id, int entrance_id) { + public void call_warp_to_map(int map_id, int entrance_id) { AtelStack stack = new AtelStack(); stack.push_int(map_id); stack.push_int(entrance_id); @@ -817,30 +863,31 @@ public static void call_warp_to_map(int map_id, int entrance_id) { int work = 0; int storage = 0; - h_Common_warpToMap((AtelBasicWorker*)&work, &storage, &stack); + Common_warpToMap((AtelBasicWorker*)&work, &storage, &stack); } - public static void call_remove_party_member(int character_id, bool long_term = false) { + + public void call_remove_party_member(int character_id, bool long_term = false) { AtelStack stack = new AtelStack(); stack.push_int(character_id); int work = 0; int storage = 0; - if (!long_term) h_Common_removePartyMember((AtelBasicWorker*)&work, &storage, &stack); - else h_Common_removePartyMemberLongTerm((AtelBasicWorker*)&work, &storage, &stack); + if (!long_term) Common_removePartyMember((AtelBasicWorker*)&work, &storage, &stack); + else Common_removePartyMemberLongTerm((AtelBasicWorker*)&work, &storage, &stack); } - public static void call_add_party_member(int character_id) { + public void call_add_party_member(int character_id) { AtelStack stack = new AtelStack(); stack.push_int(character_id); int work = 0; int storage = 0; - h_Common_addPartyMember((AtelBasicWorker*)&work, &storage, &stack); + Common_addPartyMember((AtelBasicWorker*)&work, &storage, &stack); } - public static void call_put_party_member_in_slot(int slot, int character_id) { + public void call_put_party_member_in_slot(int slot, int character_id) { AtelStack stack = new AtelStack(); stack.push_int(slot); stack.push_int(character_id); @@ -848,10 +895,10 @@ public static void call_put_party_member_in_slot(int slot, int character_id) { int work = 0; int storage = 0; - h_Common_putPartyMemberInSlot((AtelBasicWorker*)&work, &storage, &stack); + Common_putPartyMemberInSlot((AtelBasicWorker*)&work, &storage, &stack); } - public static uint[] get_party_frontline() { + public uint[] get_party_frontline() { uint slot1 = 0; uint slot2 = 0; uint slot3 = 0; @@ -861,24 +908,24 @@ public static uint[] get_party_frontline() { return [slot1, slot2, slot3]; } - public static void save_party() { + public void save_party() { //Globals.save_data->atel_is_push_member = 1; for (int character = 0; character < NUM_CHARACTERS; character++) { if (is_character_unlocked(character)) { - Globals.save_data->atel_push_party |= (byte)(1 << (byte)character); + save_data->atel_push_party |= (byte)(1 << (byte)character); } else { - Globals.save_data->atel_push_party &= (byte)(0xff ^ (1 << (byte)character)); + save_data->atel_push_party &= (byte)(0xff ^ (1 << (byte)character)); } } var party_formation = get_party_frontline(); for (int i = 0; i < 3; i++) { - Globals.save_data->atel_push_frontline[i] = (byte)party_formation[i]; + save_data->atel_push_frontline[i] = (byte)party_formation[i]; } } - public static void reset_party() { + public void reset_party() { //call_put_party_member_in_slot(0, (PlySaveId)0xff); //call_put_party_member_in_slot(1, (PlySaveId)0xff); //call_put_party_member_in_slot(2, (PlySaveId)0xff); @@ -899,10 +946,11 @@ public static void reset_party() { call_remove_party_member(character, !locked_characters[character]); } } + slot = 0; List frontline = []; for (int i = 0; i < 3; i++) { - byte character = Globals.save_data->atel_push_frontline[i]; + byte character = save_data->atel_push_frontline[i]; if (character == 0xff || !is_character_unlocked(character) || frontline.Contains(character)) { while (slot < 3 && (frontline.Contains(unlocked[slot]) || unlocked[slot] > 7)) slot++; if (slot < 3) character = unlocked[slot++]; @@ -914,8 +962,8 @@ public static void reset_party() { //Globals.save_data->atel_is_push_member = 0; } - public static void set_party(List characters, bool saveParty = true, bool onlyUnlocked = true) { - logger.Debug($"Setting party to: {String.Join(", ", characters.Select(i => id_to_character[i]))}"); + public void set_party(List characters, bool saveParty = true, bool onlyUnlocked = true) { + _logger.Debug($"Setting party to: {String.Join(", ", characters.Select(i => id_to_character[i]))}"); party_overridden = true; if (saveParty) { save_party(); @@ -943,66 +991,44 @@ public static void set_party(List characters, bool saveParty = true, bool o } } - public static void set_underwater_party(bool saveParty = true, bool onlyUnlocked = true) { + public void set_underwater_party(bool saveParty = true, bool onlyUnlocked = true) { set_party([PlySaveId.PC_TIDUS, PlySaveId.PC_WAKKA, PlySaveId.PC_RIKKU], saveParty, onlyUnlocked); } - public static void set_summon_party(bool saveParty = true, bool onlyUnlocked = true) { + public void set_summon_party(bool saveParty = true, bool onlyUnlocked = true) { set_party([ PlySaveId.PC_YUNA, PlySaveId.PC_VALEFOR, PlySaveId.PC_IFRIT, PlySaveId.PC_IXION, PlySaveId.PC_SHIVA, PlySaveId.PC_BAHAMUT, PlySaveId.PC_ANIMA, PlySaveId.PC_YOJIMBO, PlySaveId.PC_MAGUS1, PlySaveId.PC_MAGUS2, PlySaveId.PC_MAGUS3 ], saveParty, onlyUnlocked); } - public static void set_character_model(int chr_id) { + public void set_character_model(int chr_id) { AtelStack stack = new AtelStack(); stack.push_int(chr_id + 1); - AtelBasicWorker* worker0 = Globals.Atel.controllers[0].worker(0); + AtelBasicWorker* worker0 = Atel.controllers[0].worker(0); int storage = 0; - _Common_loadModel(worker0, &storage, &stack); + h_Common_loadModel.fnptr!(worker0, &storage, &stack); stack.push_int(0); - _Common_linkFieldToBattleActor(worker0, &storage, &stack); + h_Common_linkFieldToBattleActor.fnptr!(worker0, &storage, &stack); } - public static uint allocate_file(string filename, out nint file_ptr) { - int[] fileStream = [0,0]; - uint readBytes = 0; - file_ptr = 0; - - fixed (int* fs = fileStream) { - nint pFilename = Marshal.StringToHGlobalAnsi(filename); - h_openFile((nint)fs, pFilename, true, 0, 0, 1); - Marshal.FreeHGlobal(pFilename); - logger.Debug($"file_handle={fileStream[0]}, file_length={*(long*)(*(int*)(fileStream[1] + 0xc) + 8)}"); - if (fileStream[1] == 0) return 0; - var file_length = *(long*)(*(int*)(fileStream[1] + 0xc) + 8); - file_ptr = Marshal.AllocHGlobal((int)file_length); - uint max_len = (uint)file_length; - readBytes = _readFile((nint)fs, file_ptr, max_len); - } - logger.Debug($"read {readBytes}, beginning={((byte*)file_ptr)[0]} {((byte*)file_ptr)[1]} {((byte*)file_ptr)[2]} {((byte*)file_ptr)[3]}"); - return readBytes; - } - - public override void render_imgui() { - ArchipelagoGUI.render(); - } - - public struct CustomStringDrawInfo(ManagedCustomString customString, Vector2 pos, float scale = 0.65f, byte color = 0, bool persistent = false) { - public ManagedCustomString customString = customString; - public Vector2 pos = pos; - public float scale = scale; - public byte color = color; - public bool persistent = persistent; - } - - public static Dictionary customStringDrawInfos = []; - - public override void render_game() { - foreach ((string key, CustomStringDrawInfo drawInfo) in customStringDrawInfos) { - fixed (byte* text = drawInfo.customString.encoded) { - _TOMkpCrossExtMesFontLClutTypeRGBA(0, text, drawInfo.pos.X, drawInfo.pos.Y, drawInfo.color, 0, 0x80, 0x80, 0x80, 0x80, drawInfo.scale, 0); - } - } - } + //public uint allocate_file(string filename, out nint file_ptr) { + // int[] fileStream = [0,0]; + // uint readBytes = 0; + // file_ptr = 0; + + // fixed (int* fs = fileStream) { + // nint pFilename = Marshal.StringToHGlobalAnsi(filename); + // h_openFile((nint)fs, pFilename, true, 0, 0, 1); + // Marshal.FreeHGlobal(pFilename); + // _logger.Debug($"file_handle={fileStream[0]}, file_length={*(long*)(*(int*)(fileStream[1] + 0xc) + 8)}"); + // if (fileStream[1] == 0) return 0; + // var file_length = *(long*)(*(int*)(fileStream[1] + 0xc) + 8); + // file_ptr = Marshal.AllocHGlobal((int)file_length); + // uint max_len = (uint)file_length; + // readBytes = FhXCall.Phyre_PSerialization_PStreamFileWin32_Read.fnptr!((nint)fs, file_ptr, max_len); + // } + // _logger.Debug($"read {readBytes}, beginning={((byte*)file_ptr)[0]} {((byte*)file_ptr)[1]} {((byte*)file_ptr)[2]} {((byte*)file_ptr)[3]}"); + // return readBytes; + //} } diff --git a/src/client/client.cs b/src/client/client.cs index 859c6f7..6b98de7 100644 --- a/src/client/client.cs +++ b/src/client/client.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading.Tasks; @@ -15,94 +16,138 @@ using ArchipelagoFFX.GUI; +using Fahrenheit; + namespace ArchipelagoFFX.Client; -public static class FFXArchipelagoClient { - public static readonly System.Threading.Lock client_lock = new(); - public static ArchipelagoSession? current_session; - public static string? current_server; - public static int received_items = 0; - public static readonly HashSet local_checked_locations = []; - public static bool local_locations_updated = false; - public static bool remote_locations_updated = false; - public static string? SeedId = null; - - public static DeathLinkService? current_death_link; - - public static PlayerInfo? active_player => current_session?.Players.ActivePlayer; - private static bool is_disconnecting = false; - public static bool is_connected => current_session is not null && !is_disconnecting; - - public static async Task Connect(string server, string user, string password) { - ArchipelagoFFXModule.logger.Debug("Connect"); + +[FhLoad(FhGameId.FFX)] +public class ArchipelagoClientModule : FhModule { + public readonly System.Threading.Lock client_lock = new(); + public ArchipelagoSession? current_session; + public string? current_server; + public int received_items = 0; + public readonly HashSet local_checked_locations = []; + public bool local_locations_updated = false; + public bool remote_locations_updated = false; + public string? SeedId = null; + + public DeathLinkService? current_death_link_service; + + public PlayerInfo? active_player => current_session?.Players.ActivePlayer; + private bool is_disconnecting = false; + public bool is_connected => current_session is not null && !is_disconnecting; + + private FhModuleHandle _ffx_interop_handle; + private ArchipelagoFFXModule? _ffx_interop; + + private FhModuleHandle _gui_handle; + private ArchipelagoGuiModule? _gui; + + private FhModuleHandle _recent_items_handle; + private RecentItemsModule? _recent_items; + + private FhModuleHandle _death_link_handle; + private DeathLinkModule? _death_link; + + public ArchipelagoClientModule() { + _ffx_interop_handle = new(this); + _gui_handle = new(this); + _recent_items_handle = new(this); + _death_link_handle = new(this); + } + + public override bool init(FhModContext mod_context, FileStream global_state_file) { + return _ffx_interop_handle.try_get_module(out _ffx_interop) + && _gui_handle.try_get_module(out _gui) + && _recent_items_handle.try_get_module(out _recent_items) + && _death_link_handle.try_get_module(out _death_link); + } + + public async Task Connect(string server, string user, string password) { + _logger.Debug("Connect"); LoginResult? login_result = new LoginFailure(""); ArchipelagoSession? session = null; DeathLinkService? death_link = null; if (is_disconnecting) return; - try { - session = ArchipelagoSessionFactory.CreateSession(server); - death_link = session.CreateDeathLinkService(); - connectHandlers(session, death_link); - var roomInfoPacket = await session.ConnectAsync(); - - login_result = await session.LoginAsync("Final Fantasy X", user, ItemsHandlingFlags.RemoteItems, Version.Parse("0.6.0"), password: password, requestSlotData: true); - } - catch (Exception e) { - login_result = new LoginFailure(e.GetBaseException().Message); - } + lock (client_lock) { - if (!login_result.Successful) { - LoginFailure failure = (LoginFailure)login_result; - string errorMessage = $"Failed to Connect to {server} as {user}:"; - foreach (string error in failure.Errors) { - errorMessage += $"\n {error}"; + // Already connecting, so don't attempt to connect twice at the same time + if (current_session is not null) return; + + try { + session = ArchipelagoSessionFactory.CreateSession(server); + death_link = session.CreateDeathLinkService(); + connectHandlers(session, death_link); + var roomInfoPacket = session.ConnectAsync(); + + login_result = session.TryConnectAndLogin( + "Final Fantasy X", + user, + ItemsHandlingFlags.RemoteItems, + Version.Parse("0.6.0"), + password: password, + requestSlotData: true + ); + } catch (Exception e) { + login_result = new LoginFailure(e.GetBaseException().Message); } - foreach (ConnectionRefusedError error in failure.ErrorCodes) { - errorMessage += $"\n {error}"; - } - current_session = null; - ArchipelagoFFXModule.logger.Error(errorMessage); - return; // Did not connect, show the user the contents of `errorMessage` - } - var loginSuccess = (LoginSuccessful)login_result; - - if (ArchipelagoFFXModule.seed.Options.SeedId is not null) { - if (ArchipelagoFFXModule.seed.Options.SeedId != (string)loginSuccess.SlotData["SeedId"]) { - string message = "Loaded seed doesn't match connected slot"; - ArchipelagoGUI.add_log_message([(message, Color.Red)]); - ArchipelagoFFXModule.logger.Error(message); - disconnect(session); - return; + + if (!login_result.Successful) { + LoginFailure failure = (LoginFailure)login_result; + string errorMessage = $"Failed to Connect to {server} as {user}:"; + foreach (string error in failure.Errors) { + errorMessage += $"\n {error}"; + } + foreach (ConnectionRefusedError error in failure.ErrorCodes) { + errorMessage += $"\n {error}"; + } + current_session = null; + _logger.Error(errorMessage); + return; // Did not connect, show the user the contents of `errorMessage` } - ArchipelagoFFXModule.SeedToServer[ArchipelagoFFXModule.seed.Options.SeedId] = server; - ArchipelagoFFXModule.save_global_state(); - } else { - SeedId = (string)loginSuccess.SlotData["SeedId"]; - int selected_seed = ArchipelagoFFXModule.loaded_seeds.FindIndex(x => x.Options.SeedId == SeedId); - if (selected_seed != -1) { - ArchipelagoGUI.selected_seed = selected_seed; - ArchipelagoFFXModule.SeedToServer[SeedId] = server; - ArchipelagoFFXModule.save_global_state(); + var loginSuccess = (LoginSuccessful)login_result; + + if (ArchipelagoFFXModule.seed.Options.SeedId is not null) { + if (ArchipelagoFFXModule.seed.Options.SeedId != (string)loginSuccess.SlotData["SeedId"]) { + string message = "Loaded seed doesn't match connected slot"; + _gui!.add_log_message([(message, Color.Red)]); + _logger.Error(message); + disconnect(session); + return; + } + ArchipelagoFFXModule.SeedToServer[ArchipelagoFFXModule.seed.Options.SeedId] = server; + _ffx_interop!.save_global_state(); + } else { + SeedId = (string)loginSuccess.SlotData["SeedId"]; + int selected_seed = ArchipelagoFFXModule.loaded_seeds.FindIndex(x => x.Options.SeedId == SeedId); + if (selected_seed != -1) { + _gui!.selected_seed = selected_seed; + ArchipelagoFFXModule.SeedToServer[SeedId] = server; + _ffx_interop!.save_global_state(); + } } + current_server = server; + current_session = session; + current_death_link_service = death_link; } - current_server = server; - current_session = session; - current_death_link = death_link; } - public static void disconnect(ArchipelagoSession? session = null) { - ArchipelagoFFXModule.logger.Debug("disconnect"); + public void disconnect(ArchipelagoSession? session = null) { + _logger.Debug("disconnect"); lock (client_lock) { session ??= current_session; if (session is null || is_disconnecting) return; is_disconnecting = true; + disconnectHandlers(session, current_death_link_service); session.Socket.DisconnectAsync(); } } - private static void connectHandlers(ArchipelagoSession session, DeathLinkService death_link) { - ArchipelagoFFXModule.logger.Debug("connectHandlers"); + private void connectHandlers(ArchipelagoSession session, DeathLinkService death_link) { + _logger.Debug("connectHandlers"); + session.MessageLog.OnMessageReceived += MessageLog_OnMessageReceived; session.Socket.ErrorReceived += Socket_ErrorReceived; session.Socket.SocketOpened += Socket_SocketOpened; @@ -111,49 +156,57 @@ private static void connectHandlers(ArchipelagoSession session, DeathLinkService session.MessageLog.OnMessageReceived += RecentItemsModule.post_item_message; - death_link.OnDeathLinkReceived += DeathLinkModule.post_deathlink; + death_link.OnDeathLinkReceived += _death_link!.post_deathlink; } - private static void Locations_CheckedLocationsUpdated(System.Collections.ObjectModel.ReadOnlyCollection newCheckedLocations) { + private void disconnectHandlers(ArchipelagoSession? session, DeathLinkService? death_link) { + _logger.Debug("disconnectHandlers"); + + session?.MessageLog.OnMessageReceived -= MessageLog_OnMessageReceived; + session?.Socket.ErrorReceived -= Socket_ErrorReceived; + session?.Socket.SocketOpened -= Socket_SocketOpened; + session?.Socket.SocketClosed -= Socket_SocketClosed; + session?.Locations.CheckedLocationsUpdated -= Locations_CheckedLocationsUpdated; + + session?.MessageLog.OnMessageReceived -= RecentItemsModule.post_item_message; + + death_link?.OnDeathLinkReceived -= _death_link!.post_deathlink; + } + + private void Locations_CheckedLocationsUpdated(System.Collections.ObjectModel.ReadOnlyCollection newCheckedLocations) { lock (client_lock) { remote_locations_updated = true; } } - private static void Socket_ErrorReceived(Exception e, string message) { - ArchipelagoFFXModule.logger.Debug($"Socket Error: {message}"); - ArchipelagoFFXModule.logger.Debug($"Socket Exception: {e.Message}"); + private void Socket_ErrorReceived(Exception e, string message) { + _logger.Debug($"Socket Error: {message}"); + _logger.Debug($"Socket Exception: {e.Message}"); if (e.StackTrace != null) foreach (var line in e.StackTrace.Split('\n')) - ArchipelagoFFXModule.logger.Debug($" {line}"); + _logger.Debug($" {line}"); else - ArchipelagoFFXModule.logger.Debug($" No stacktrace provided"); + _logger.Debug(" No stacktrace provided"); } - private static void Socket_SocketOpened() { - ArchipelagoFFXModule.logger.Debug($"Socket Opened: \"{current_session?.Socket.Uri}\""); + private void Socket_SocketOpened() { + _logger.Debug($"Socket Opened: \"{current_session?.Socket.Uri}\""); } - private static void Socket_SocketClosed(string reason) { - ArchipelagoFFXModule.logger.Debug($"Socket Closed: \"{reason}\""); - ArchipelagoGUI.add_log_message([($"Disconnected from server ({reason})", Color.Red)]); + private void Socket_SocketClosed(string reason) { + _logger.Debug($"Socket Closed: \"{reason}\""); + _gui!.add_log_message([($"Disconnected from server ({reason})", Color.Red)]); lock (client_lock) { current_session = null; - current_death_link = null; + current_death_link_service = null; SeedId = null; current_server = null; is_disconnecting = false; } } - public unsafe static void update() { - /* - foreach (ItemInfo item in session.Items.AllItemsReceived) { - ArchipelagoFFXModule.logger.Debug($"received_item: {item.ItemName}"); - } - */ - + public unsafe void update() { lock (client_lock) { // TODO: Check for post-battle/other menu? if ( !is_connected @@ -166,10 +219,10 @@ public unsafe static void update() { } if (current_session!.Items.AllItemsReceived.Count > received_items) { - ArchipelagoFFXModule.logger.Debug("New items received"); + _logger.Debug("New items received"); foreach (ItemInfo item in current_session.Items.AllItemsReceived.Skip(received_items)) { - ArchipelagoFFXModule.logger.Debug($"received_item: {item.ItemName}"); - ArchipelagoFFXModule.obtain_item((uint)item.ItemId); + _logger.Debug($"received_item: {item.ItemName}"); + _ffx_interop!.obtain_item((uint)item.ItemId); received_items++; } } @@ -178,7 +231,7 @@ public unsafe static void update() { var local_only = local_checked_locations.Except(current_session.Locations.AllLocationsChecked); if (local_only.Any()) { current_session.Locations.CompleteLocationChecksAsync(local_only.ToArray()); - ArchipelagoFFXModule.logger.Debug($"Sent: {string.Join(",", local_only)}"); + _logger.Debug($"Sent: {string.Join(",", local_only)}"); } local_locations_updated = false; @@ -202,35 +255,19 @@ public unsafe static void update() { var remote_only = current_session.Locations.AllLocationsChecked.Except(local_checked_locations); foreach (long location in remote_only) { if (ArchipelagoFFXModule.item_locations.location_to_item((int)location, out var item)) { - ArchipelagoFFXModule.logger.Debug($"Synced remote location: location:{location}, item:{item.name}, player:{item.player}"); - ArchipelagoFFXModule.obtain_item(item.id); + _logger.Debug($"Synced remote location: location:{location}, item:{item.name}, player:{item.player}"); + _ffx_interop!.obtain_item(item.id); } } local_checked_locations.UnionWith(remote_only); remote_locations_updated = false; } } - - /* - var remote_only = session.Locations.AllLocationsChecked.Except(local_checked_locations); - if (remote_only.Any()) { - ArchipelagoFFXModule.logger.Debug($"Received Remote Locations: {string.Join(",", remote_only)}"); - foreach (var location in remote_only) { - // TODO: Distinguish between location types - var treasure_id = (location - 0x14)/4; - ArchipelagoFFXModule.logger.Debug($"Location id: {Convert.ToInt32(treasure_id)}"); - ArchipelagoModule.receive_treasure(Convert.ToInt32(treasure_id)); - local_checked_locations.Add(location); - } - } - */ - - } - private static void MessageLog_OnMessageReceived(LogMessage message) { + private void MessageLog_OnMessageReceived(LogMessage message) { var parts = message.Parts; - List<(string, Color)> messageParts = parts.Select((part) => { + List<(string, Color)> messageParts = parts.Select(part => { Color color = part.Color; if (part.IsBackgroundColor) { color = Color.White; @@ -240,38 +277,19 @@ private static void MessageLog_OnMessageReceived(LogMessage message) { } return (part.Text, color); }).ToList(); - ArchipelagoGUI.add_log_message(messageParts); + _gui!.add_log_message(messageParts); } - /* -public unsafe static void connectHandlers() { - session.Locations.CheckedLocationsUpdated += (newCheckedLocations) => { - if (Globals.save_data->current_room_id == 23) return; - - var remote_only = newCheckedLocations.Except(local_checked_locations); - if (remote_only.Any()) { - ArchipelagoFFXModule.logger.Debug($"Received Remote Locations: {string.Join(",", remote_only)}"); - foreach (var location in remote_only) { - ArchipelagoFFXModule.logger.Debug($"Location id: {Convert.ToInt32(location)}"); - ArchipelagoModule.receive_treasure(Convert.ToInt32(location)); - local_checked_locations.Add(location); - } - } - }; -} -*/ - - public static void SayAsync(string message) + public void SayAsync(string message) { lock (client_lock) { - if (is_connected) - { + if (is_connected) { current_session!.Socket.SendPacketAsync(new SayPacket { Text = message }); } } } - public enum ArchipelagoLocationType: int { + public enum ArchipelagoLocationType { Treasure = 0x1000, Boss = 0x2000, Overdrive = 0x3000, @@ -283,19 +301,19 @@ public enum ArchipelagoLocationType: int { PartyMember = 0xF000, } - public static bool sendLocation(long locationId, ArchipelagoLocationType locationType) { + public bool sendLocation(long locationId, ArchipelagoLocationType locationType) { var absoluteId = locationId | (long)locationType; return sendLocation(absoluteId); } - private static bool sendLocation(long locationId) { + + private bool sendLocation(long locationId) { if (!local_checked_locations.Add(locationId)) return false; local_locations_updated = true; lock (client_lock) { if (is_connected) { - ArchipelagoFFXModule.logger.Debug(current_session!.Locations.GetLocationNameFromId(locationId) ?? $"Location: {locationId}"); + _logger.Debug(current_session!.Locations.GetLocationNameFromId(locationId) ?? $"Location: {locationId}"); } } return true; } - } diff --git a/src/customization.cs b/src/customization.cs index 6875ee4..b214e95 100644 --- a/src/customization.cs +++ b/src/customization.cs @@ -1,70 +1,37 @@ -// SPDX-License-Identifier: MIT +// SPDX-License-Identifier: MIT +using Fahrenheit; using Fahrenheit.FFX; +using Fahrenheit.FFX.Ids; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - -using Fahrenheit; - -using static ArchipelagoFFX.delegates; +using FhXCall = Fahrenheit.FFX.FhCall; namespace ArchipelagoFFX; public unsafe partial class ArchipelagoFFXModule { + public enum CustomizationStatusEnum : byte { + NONE = 0x0, + AEON_AVAILABLE = 0x4, + AEON_ALREADY_LEARNED = 0x5, + AEON_CANNOT_LEARN_WITHOUT_KEY = 0x6, + AEON_NOT_ENOUGH_ITEMS = 0x7, + + GEAR_AVAILABLE = 0xb, + GEAR_ALREADY_APPLIED = 0xc, + GEAR_NOT_ENOUGH_ITEMS = 0xe, + GEAR_CONFLICTING = 0xf, // (same group but lower level) or (same group, same level, different international bonus) or (international bonus is 0xfe AND gear has any ability with 0xff international bonus) + GEAR_NO_SLOTS = 0x10, + //NONE = 0x11 + } - // Customization - public static FhMethodHandle _PrepareMenuList; - public static FhMethodHandle _UpdateGearCustomizationMenuState; - public static FhMethodHandle _UpdateAeonCustomizationMenuState; - public static FhMethodHandle _DrawGearCustomizationMenu; - public static FhMethodHandle _DrawAeonCustomizationMenu; - public static delegates.MsGetRomKaizou _MsGetRomKaizou; - public static delegates.MsGetRomAbility _MsGetRomAbility; - public static delegates.MsGetRomSummonGrow _MsGetRomSummonGrow; - public static delegates.TkMn2GetSummonGrowMax _TkMn2GetSummonGrowMax; - public static delegates.TkMenuGetCurrentSummon _TkMenuGetCurrentSummon; - public static delegates.MsGetSaveCommand _MsGetSaveCommand; - - public static delegates.FUN_008c1c70 _FUN_008c1c70; - public static delegates.TODrawMenuPlateXYWHType _TODrawMenuPlateXYWHType; - public static delegates.FUN_008f8bb0 _FUN_008f8bb0; - public static delegates.TODrawScissorXYWH _TODrawScissorXYWH; - public static delegates.FUN_008d5d20 _FUN_008d5d20; - public static delegates.FUN_008c0f40 _FUN_008c0f40; - public static delegates.FUN_008c1350_DrawScissor512x416 _FUN_008c1350_DrawScissor512x416; - public static delegates.FUN_008d5dc0 _FUN_008d5dc0; - public static delegates.DrawCrossMenuScrollParts _DrawCrossMenuScrollParts; - public static delegates.FUN_008d6630 _FUN_008d6630; - - public static delegates.TkVU1SyncPath _TkVU1SyncPath; - public static delegates.FUN_008e71d0 _FUN_008e71d0; - public static delegates.FUN_008ff490 _FUN_008ff490; - public static delegates.FUN_008cd960 _FUN_008cd960; - public static delegates.FUN_008cd9f0 _FUN_008cd9f0; - public static delegates.ToGetCrossExtMesFontWidth _ToGetCrossExtMesFontWidth; - public static delegates.FUN_008bee80 _FUN_008bee80; - - public static delegates.TOMkpShapeXYWHUV _TOMkpShapeXYWHUV; - public static delegates.TOMkpCrossExtMesFontLClut _TOMkpCrossExtMesFontLClut; - public static delegates.FUN_008d48e0 _FUN_008d48e0; - public static delegates.FUN_008d4140 _FUN_008d4140; - public static delegates.TkMn2DrawKickSyncPacket _TkMn2DrawKickSyncPacket; - - - public static delegates.TkMenuMainAllocWindow _TkMenuMainAllocWindow; - public static delegates.TkMenuMainRegistWindow _TkMenuMainRegistWindow; - - - public static delegates.FUN_008e33a0 _FUN_008e33a0; - public static delegates.FUN_008b4460 _FUN_008b4460; - public static delegates.FUN_008e2de0 _FUN_008e2de0; - public static delegates.MsSetSaveParamAll _MsSetSaveParamAll; - public static delegates.MsSetWeaponName _MsSetWeaponName; - public static delegates.FUN_008c2c40 _FUN_008c2c40; - public static delegates.TkMn2DrawCrossCursor _TkMn2DrawCrossCursor; - - public static FhMethodHandle _FUN_008d5720; + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct CustomizationMenuList { + public ushort a_ability_id; + public CustomizationStatusEnum status; + public byte customization_id; + } // Customization-related private static int selected_gear_slot = 0; @@ -74,7 +41,7 @@ public unsafe partial class ArchipelagoFFXModule { public void PrepareMenuList_InitList() { // Init list ushort* _DAT_01597330 = FhUtil.ptr_at(0x1197330); - delegates.CustomizationMenuList* menu_list_iter = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list_iter = FhUtil.ptr_at(0x1197730); for (int i = 0; i < 0x200; i++) { menu_list_iter[i].a_ability_id = 0; @@ -82,6 +49,7 @@ public void PrepareMenuList_InitList() { menu_list_iter[i].customization_id = 0; _DAT_01597330[i] = 0; } + uint* _DAT_0186a20c = FhUtil.ptr_at(0x146A20C); *_DAT_0186a20c = 0; } @@ -97,29 +65,30 @@ public void PrepareMenuList_SetLength(uint added, uint skipped) { } } - public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* gear) - { - logger.Info($"{menu_list_id}"); + public void PrepareMenuList(TkMenuItemListId menu_list_id, Equipment* gear) { + //MenuList menu_list_id = (MenuList)menu_list_id_raw; + _logger.Info($"{menu_list_id}"); uint[] ability_international_bonuses = new uint[4]; uint[] ability_group_idxs = new uint[4]; uint[] ability_group_levels = new uint[4]; - if (menu_list_id == delegates.MenuListEnum.GEAR_CUSTOMIZATION) { + if (menu_list_id == TkMenuItemListId.GEAR_CUSTOMIZATION) { // Modify kaizou.bin int num_customizations; - CustomizationRecipe* customizations = _MsGetRomKaizou(&num_customizations); + CustomizationRecipe* customizations = FhXCall.MsGetRomKaizou.fnptr!(&num_customizations); if (original_kaizou_costs == null) { original_kaizou_costs = new ushort[num_customizations]; for (int i = 0; i < num_customizations; i++) { original_kaizou_costs[i] = customizations[i].item_cost; } } + uint item_id = 0xC000; for (int i = 0; i < num_customizations; i++, item_id++) { if (other_inventory.TryGetValue(item_id, out int count)) { if (count > 0) { - logger.Debug($"Free customization: {get_other_item_name(item_id)}"); + _logger.Debug($"Free customization: {get_other_item_name(item_id)}"); customizations[i].item_cost = 0; } } @@ -127,7 +96,7 @@ public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* ge // Init list PrepareMenuList_InitList(); - delegates.CustomizationMenuList* menu_list_iter = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list_iter = FhUtil.ptr_at(0x1197730); uint* _DAT_0186a20c = FhUtil.ptr_at(0x146A20C); @@ -150,7 +119,7 @@ public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* ge ushort ability_id = gear->abilities[i]; if (ability_id != 0 && ability_id != 0xFF) { int a_ability_id; - AutoAbility* a_ability = _MsGetRomAbility(ability_id, &a_ability_id); + AutoAbility* a_ability = FhXCall.MsGetRomAbility.fnptr!(ability_id, &a_ability_id); ability_group_idxs[num_abilities] = (uint)a_ability->group_idx; ability_group_levels[num_abilities] = (uint)a_ability->group_level; @@ -158,6 +127,7 @@ public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* ge if (a_ability->international_bonus_idx == 0xff) { has_ribbon = true; } + num_abilities++; } } @@ -171,49 +141,48 @@ public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* ge if (customization.target_gear_type.HasFlag(gear_type)) { ushort a_ability_id = customization.auto_ability; int local_68; - AutoAbility* a_ability = _MsGetRomAbility(a_ability_id, &local_68); + AutoAbility* a_ability = FhXCall.MsGetRomAbility.fnptr!(a_ability_id, &local_68); uint item_count = Globals.save_data->get_item_count(customization.item); if (item_count == 0 && customization.item_cost != 0) { skipped++; continue; - } - else { - delegates.CustomizationStatusEnum status = delegates.CustomizationStatusEnum.GEAR_AVAILABLE; + } else { + CustomizationStatusEnum status = CustomizationStatusEnum.GEAR_AVAILABLE; if (num_abilities == 0) { if (item_count < customization.item_cost) { - status = delegates.CustomizationStatusEnum.GEAR_NOT_ENOUGH_ITEMS; + status = CustomizationStatusEnum.GEAR_NOT_ENOUGH_ITEMS; } - } - else { + } else { for (int i = 0; i < num_abilities; i++) { if (ability_group_idxs[i] == a_ability->group_idx) { if (a_ability->group_level < ability_group_levels[i]) { // Same group, lower level - status = delegates.CustomizationStatusEnum.GEAR_CONFLICTING; + status = CustomizationStatusEnum.GEAR_CONFLICTING; } + //if (a_ability->group_level == ability_group_levels[i]) { // status = a_ability->international_bonus_idx != ability_international_bonuses[i] ? CustomizationStatusEnum.GEAR_CONFLICTING : CustomizationStatusEnum.GEAR_ALREADY_APPLIED; //} - if (a_ability->group_level == ability_group_levels[i]) - { - if (a_ability->international_bonus_idx == ability_international_bonuses[i]) - { - status = delegates.CustomizationStatusEnum.GEAR_ALREADY_APPLIED; - } else if (selected_gear_slot != i) - { - status = delegates.CustomizationStatusEnum.GEAR_CONFLICTING; + if (a_ability->group_level == ability_group_levels[i]) { + if (a_ability->international_bonus_idx == ability_international_bonuses[i]) { + status = CustomizationStatusEnum.GEAR_ALREADY_APPLIED; + } else if (selected_gear_slot != i) { + status = CustomizationStatusEnum.GEAR_CONFLICTING; } } } + if (has_ribbon && a_ability->international_bonus_idx == 0xFE) { - status = delegates.CustomizationStatusEnum.GEAR_CONFLICTING; + status = CustomizationStatusEnum.GEAR_CONFLICTING; } } - if (status == delegates.CustomizationStatusEnum.GEAR_AVAILABLE && item_count < customization.item_cost) { - status = delegates.CustomizationStatusEnum.GEAR_NOT_ENOUGH_ITEMS; + + if (status == CustomizationStatusEnum.GEAR_AVAILABLE && item_count < customization.item_cost) { + status = CustomizationStatusEnum.GEAR_NOT_ENOUGH_ITEMS; } } + //if (gear->abilities[gear->slot_count - 1] != 0xff && gear->abilities[gear->slot_count - 1] != 0) { // status = CustomizationStatusEnum.GEAR_NO_SLOTS; //} @@ -225,9 +194,10 @@ public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* ge } } } + for (int i = 0; i < skipped; i++) { // ???? - menu_list_iter->status = (delegates.CustomizationStatusEnum)0x11; + menu_list_iter->status = (CustomizationStatusEnum)0x11; menu_list_iter->a_ability_id = 0; menu_list_iter->customization_id = 0xFF; menu_list_iter++; @@ -237,23 +207,23 @@ public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* ge // Set length PrepareMenuList_SetLength(added, skipped); - } - else if (menu_list_id == delegates.MenuListEnum.AEON_ABILITIES) { + } else if (menu_list_id == TkMenuItemListId.AEON_ABILITIES) { // TODO: Modify sum_grow.bin int num_customizations; - CustomizationRecipe* customizations = _MsGetRomSummonGrow(&num_customizations); - num_customizations = _TkMn2GetSummonGrowMax(); + AeonAbilityRecipe* customizations = FhXCall.MsGetRomSummonGrow.fnptr!(&num_customizations); + num_customizations = FhXCall.TkMn2GetSummonGrowMax.fnptr!(); if (original_sum_grow_costs == null) { original_sum_grow_costs = new ushort[num_customizations]; for (int i = 0; i < num_customizations; i++) { original_sum_grow_costs[i] = customizations[i].item_cost; } } + uint item_id = 0xC07D; for (int i = 0; i < num_customizations; i++, item_id++) { if (other_inventory.TryGetValue(item_id, out int count)) { if (count > 0) { - logger.Debug($"Free customization: {get_other_item_name(item_id)}"); + _logger.Debug($"Free customization: {get_other_item_name(item_id)}"); customizations[i].item_cost = 0; } } @@ -261,41 +231,42 @@ public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* ge // Init list PrepareMenuList_InitList(); - delegates.CustomizationMenuList* menu_list_iter = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list_iter = FhUtil.ptr_at(0x1197730); uint* _DAT_0186a20c = FhUtil.ptr_at(0x146A20C); - byte current_summon = _TkMenuGetCurrentSummon(); + byte current_summon = FhXCall.TkMenuGetCurrentSummon.fnptr!(); bool has_key_item = Globals.save_data->key_items.get(0xa022); uint added = 0; if (0 < num_customizations) { for (byte customization_id = 0; customization_id < num_customizations; customization_id++) { - CustomizationRecipe customization = customizations[customization_id]; - ushort auto_ability_id = customization.auto_ability; + AeonAbilityRecipe customization = customizations[customization_id]; + short auto_ability_id = customization.command; menu_list_iter->customization_id = 0xff; - bool has_command = _MsGetSaveCommand(current_summon, auto_ability_id); + bool has_command = FhXCall.MsGetSaveCommand.fnptr!(current_summon, (uint)auto_ability_id) != 0; if (!has_command) { uint item_count = Globals.save_data->get_item_count(customization.item); if (item_count == 0 && customization.item_cost != 0) { continue; } else { - menu_list_iter->a_ability_id = auto_ability_id; + menu_list_iter->a_ability_id = (ushort)auto_ability_id; menu_list_iter->customization_id = customization_id; if (item_count < customization.item_cost) { - menu_list_iter->status = delegates.CustomizationStatusEnum.AEON_NOT_ENOUGH_ITEMS; - } else if (((int)customization.target_gear_type & (1 << (current_summon - 8))) == 0 && !has_key_item) { + menu_list_iter->status = CustomizationStatusEnum.AEON_NOT_ENOUGH_ITEMS; + } else if ((0x7F & (1 << (current_summon - 8))) == 0 && !has_key_item) { // Never reached because both conditions are always false: Bit is set for all Aeons (always 0x7F) and key item is unused. - menu_list_iter->status = delegates.CustomizationStatusEnum.AEON_CANNOT_LEARN_WITHOUT_KEY; + menu_list_iter->status = CustomizationStatusEnum.AEON_CANNOT_LEARN_WITHOUT_KEY; } else { - menu_list_iter->status = delegates.CustomizationStatusEnum.AEON_AVAILABLE; + menu_list_iter->status = CustomizationStatusEnum.AEON_AVAILABLE; } } } else { - menu_list_iter->a_ability_id = auto_ability_id; + menu_list_iter->a_ability_id = (ushort)auto_ability_id; menu_list_iter->customization_id = customization_id; - menu_list_iter->status = delegates.CustomizationStatusEnum.AEON_ALREADY_LEARNED; + menu_list_iter->status = CustomizationStatusEnum.AEON_ALREADY_LEARNED; } + menu_list_iter++; added++; } @@ -303,13 +274,12 @@ public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* ge // Set length PrepareMenuList_SetLength(added, 0); - } else { - _PrepareMenuList.orig_fptr(menu_list_id, gear); + FhXCall.FUN_008c2370.chain_from(PrepareMenuList).fnptr!(menu_list_id, gear); } - //if (menu_list_id == MenuListEnum.GEAR_CUSTOMIZATION) { + //if (menu_list_id == MenuList.GEAR_CUSTOMIZATION) { // CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); // int i = 0; // while (menu_list->status != CustomizationStatusEnum.NONE) { @@ -328,7 +298,7 @@ public void h_PrepareMenuList(delegates.MenuListEnum menu_list_id, Equipment* ge /// 6: Calls TkMenuRestartSelFileWindow, then ??? and goes to 7 /// /// - public void h_UpdateGearCustomizationMenuState(TkWindow* window) { + public void UpdateGearCustomizationMenuState(TkWindow* window) { uint* state = FhUtil.ptr_at(0x146AA28); uint pre_state = *state; @@ -337,147 +307,140 @@ public void h_UpdateGearCustomizationMenuState(TkWindow* window) { byte* p_DAT_0186a9f8 = (byte*)FhUtil.get_at(0x146A9F8); bool break_loop = false; - while (!break_loop) - { + while (!break_loop) { switch (*state) { case 2: - _FUN_008b4460(window); - if (window->exit_value < 1) - { + FhXCall.FUN_008b4460.fnptr!(window); + if (window->exit_value < 1) { return; } + ushort weapon_index = *(ushort*)(p_DAT_0186a9f8 + window->selected_index * 2); - gear = _MsGetSaveWeapon(weapon_index, 0); + gear = FhXCall.MsGetSaveWeapon.fnptr!(weapon_index, 0); bool can_customize = false; - if (gear->exists && !gear->is_hidden && gear->slot_count > 0) - { - if (!gear->is_celestial && !gear->is_brotherhood) - { + if (gear->exists && !gear->is_hidden && gear->slot_count > 0) { + if (!gear->is_celestial && !gear->is_brotherhood) { //if (gear->abilities[gear->slot_count-1] == 0xff || gear->abilities[gear->slot_count - 1] == 0) can_customize = true; } } - if (!can_customize) - { + + if (!can_customize) { goto default; - } - else - { - _SndSepPlaySimple(0x80000001); + } else { + FhXCall.SndSepPlaySimple.fnptr!(0x80000001); { int slot = 0; - for (; slot < gear->slot_count; slot++) - { - if (gear->abilities[slot] is 0 or 0xff) - { + for (; slot < gear->slot_count; slot++) { + if (gear->abilities[slot] is 0 or 0xff) { break; } } - if (slot < 4 && slot < gear->slot_count) - { + + if (slot < 4 && slot < gear->slot_count) { selected_gear_slot = slot; *state = 0x5; - } else - { + } else { CreateMyWindow(gear); *state = 0xe; } } } + break; - case 6: - { - TkWindow* _GearSelectionWindow = (TkWindow*)FhUtil.get_at(0x146A9F0); // DAT_0186a9f0 - gear = _MsGetSaveWeapon(*(ushort*)(p_DAT_0186a9f8 + _GearSelectionWindow->selected_index * 2), - (nint)(&gear_name)); - int slot = 0; - for (; slot < gear->slot_count; slot++) - { - if (gear->abilities[slot] is 0 or 0xff) - { - break; - } - } - if (slot < 4 && slot < gear->slot_count) - { - selected_gear_slot = slot; - goto default; - } - else - { - *state = 8; + + case 6: { + TkWindow* _GearSelectionWindow = (TkWindow*)FhUtil.get_at(0x146A9F0); // DAT_0186a9f0 + gear = FhXCall.MsGetSaveWeapon.fnptr!( + *(ushort*)(p_DAT_0186a9f8 + _GearSelectionWindow->selected_index * 2), + (nint)(&gear_name) + ); + int slot = 0; + for (; slot < gear->slot_count; slot++) { + if (gear->abilities[slot] is 0 or 0xff) { + break; } } + + if (slot < 4 && slot < gear->slot_count) { + selected_gear_slot = slot; + goto default; + } else { + *state = 8; + } + } break; + case 8: - if (MyWindow != null) - { + if (MyWindow != null) { MyWindow->should_destroy = true; MyWindow = null; } + goto default; - case 0xc: - { - TkWindow* DAT_023cc120 = (TkWindow*)FhUtil.get_at(0x1FCC120); - if (DAT_023cc120->exit_value < 0) - { - _FUN_008e2de0(); - *state = 6; - break_loop = true; - break; - } - if (DAT_023cc120->exit_value == 0) - { - break_loop = true; - break; - } - _FUN_008e2de0(); - if (DAT_023cc120->selected_index != 0) - { - _SndSepPlaySimple(0x80000001); - *state = 6; - break_loop = true; - break; - } + + case 0xc: { + TkWindow* DAT_023cc120 = (TkWindow*)FhUtil.get_at(0x1FCC120); + if (DAT_023cc120->exit_value < 0) { + FhXCall.FUN_008e2de0.fnptr!(); + *state = 6; + break_loop = true; + break; } + + if (DAT_023cc120->exit_value == 0) { + break_loop = true; + break; + } + + FhXCall.FUN_008e2de0.fnptr!(); + if (DAT_023cc120->selected_index != 0) { + FhXCall.SndSepPlaySimple.fnptr!(0x80000001); + *state = 6; + break_loop = true; + break; + } + } *state = 0xd; break; + case 0xd: TkWindow* AbilitySelectionWindow = (TkWindow*)FhUtil.get_at(0x146A9F4); // PTR_0186a9f4 TkWindow* GearSelectionWindow = (TkWindow*)FhUtil.get_at(0x146A9F0); // DAT_0186a9f0 - delegates.CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); short selected_ability = AbilitySelectionWindow->selected_index; int num_customizations; - CustomizationRecipe* customizations = _MsGetRomKaizou(&num_customizations); + CustomizationRecipe* customizations = FhXCall.MsGetRomKaizou.fnptr!(&num_customizations); byte customization_id = menu_list[selected_ability].customization_id; - gear = _MsGetSaveWeapon(*(ushort*)(p_DAT_0186a9f8 + GearSelectionWindow->selected_index * 2), - (nint)(&gear_name)); + gear = FhXCall.MsGetSaveWeapon.fnptr!( + *(ushort*)(p_DAT_0186a9f8 + GearSelectionWindow->selected_index * 2), + (nint)(&gear_name) + ); byte* p_DAT_0186aa30 = FhUtil.ptr_at(0x146AA30); int i = -1; - do - { + do { i++; p_DAT_0186aa30[i] = gear_name[i]; } while (gear_name[i] != 0); + //_FUN_008d5650((int)gear, menu_list[selected_ability].a_ability_id); - if (gear->slot_count != 0) - { + if (gear->slot_count != 0) { gear->abilities[selected_gear_slot] = menu_list[selected_ability].a_ability_id; } - _MsSetSaveParamAll(); - _MsSetWeaponName(gear); - _MsSaveItemUse(customizations[customization_id].item, -customizations[customization_id].item_cost); - _SndSepPlaySimple(0x80000063); - _MsGetSaveWeapon((uint)*(ushort*)(p_DAT_0186a9f8 + GearSelectionWindow->selected_index * 2), (nint)(&gear_name)); + FhXCall.MsSetSaveParamAll.fnptr!(); + + FhXCall.MsSetWeaponName.fnptr!(gear); + FhXCall.MsSaveItemUse.fnptr!(customizations[customization_id].item, -customizations[customization_id].item_cost); + FhXCall.SndSepPlaySimple.fnptr!(0x80000063); + FhXCall.MsGetSaveWeapon.fnptr!((uint)*(ushort*)(p_DAT_0186a9f8 + GearSelectionWindow->selected_index * 2), (nint)(&gear_name)); byte* p_DAT_0186aa70 = FhUtil.ptr_at(0x146AA70); i = -1; - do - { + do { i++; p_DAT_0186aa70[i] = gear_name[i]; } while (gear_name[i] != 0); @@ -486,78 +449,75 @@ public void h_UpdateGearCustomizationMenuState(TkWindow* window) { byte prev; byte curr; i = -1; - do - { + do { i++; prev = p_DAT_0186aa30[i]; curr = p_DAT_0186aa70[i]; int is_lower = curr < prev ? 1 : 0; - if (curr != prev) - { + if (curr != prev) { uVar9 = (byte)(-is_lower | 1); break; } } while (curr != 0); - if (uVar9 == 0) - { + + if (uVar9 == 0) { uVar9 = 0x1e; - } - else - { + } else { uVar9 = 0x1f; } - byte* pbVar8 = _FUN_008bee80(uVar9); - _FUN_008c2c40(0, 0, p_DAT_0186aa30); - _FUN_008c2c40(2, 0, p_DAT_0186aa70); - _FUN_008e33a0(pbVar8, (byte*)0, (byte*)0); - { - TkWindow* DAT_023cc120 = (TkWindow*)FhUtil.get_at(0x1FCC120); ; - DAT_023cc120->render_priority = 4; - } + + byte* pbVar8 = FhXCall.FUN_008bee80.fnptr!(uVar9); + FhXCall.FUN_008c2c40.fnptr!(0, 0, p_DAT_0186aa30); + FhXCall.FUN_008c2c40.fnptr!(2, 0, p_DAT_0186aa70); + FhXCall.FUN_008e33a0.fnptr!(pbVar8, (byte*)0, (byte*)0); + { + TkWindow* DAT_023cc120 = (TkWindow*)FhUtil.get_at(0x1FCC120); + ; + DAT_023cc120->render_priority = 4; + } *state = 10; break_loop = true; break; + case 0xe: // Custom state for selecting slot to overwrite - if (MyWindow->exit_value == 0) - { + if (MyWindow->exit_value == 0) { break_loop = true; - } else - { - logger.Info($"exit_value={MyWindow->exit_value}"); - if (MyWindow->exit_value > 0) - { + } else { + _logger.Info($"exit_value={MyWindow->exit_value}"); + if (MyWindow->exit_value > 0) { selected_gear_slot = MyWindow->selected_index; - logger.Info($"selected_gear_slot={selected_gear_slot}"); + _logger.Info($"selected_gear_slot={selected_gear_slot}"); *state = 5; - } else - { + } else { *state = 8; } + break_loop = true; } + break; + default: - _UpdateGearCustomizationMenuState.orig_fptr(window); + FhXCall.UpdateGearCustomizationMenuState.chain_from(UpdateGearCustomizationMenuState).fnptr!(window); break_loop = true; break; } } - if (*state != pre_state) { - logger.Info($"{pre_state} -> {*state}"); + _logger.Info($"{pre_state} -> {*state}"); if (pre_state == 0xc && *state == 0xa) { // Applied customization TkWindow* DAT_0186a9f4 = (TkWindow*)FhUtil.get_at(0x0146A9F4); short selected_idx = DAT_0186a9f4->selected_index; - delegates.CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); int num_customizations; - CustomizationRecipe* customizations = _MsGetRomKaizou(&num_customizations); + CustomizationRecipe* customizations = FhXCall.MsGetRomKaizou.fnptr!(&num_customizations); byte customization_id = menu_list[selected_idx].customization_id; if (customizations[customization_id].item_cost != original_kaizou_costs[customization_id]) { uint item_id = (uint)(0xC000 | customization_id); @@ -565,8 +525,7 @@ public void h_UpdateGearCustomizationMenuState(TkWindow* window) { if (--count <= 0) { other_inventory.Remove(item_id); customizations[customization_id].item_cost = original_kaizou_costs[customization_id]; - } - else other_inventory[item_id] = count; + } else other_inventory[item_id] = count; } } } @@ -575,7 +534,7 @@ public void h_UpdateGearCustomizationMenuState(TkWindow* window) { // Reset kaizou.bin if (original_kaizou_costs != null) { int num_customizations; - CustomizationRecipe* customizations = _MsGetRomKaizou(&num_customizations); + CustomizationRecipe* customizations = FhXCall.MsGetRomKaizou.fnptr!(&num_customizations); for (int i = 0; i < num_customizations; i++) { customizations[i].item_cost = original_kaizou_costs[i]; } @@ -584,33 +543,31 @@ public void h_UpdateGearCustomizationMenuState(TkWindow* window) { } // param_1 is TkMenu* - public void h_UpdateAeonCustomizationMenuState(uint param_1, uint param_2) { - uint* state = (uint *)(param_1 + 0x1c); + public void TkMenuCtrlSummon(TkMenu* menu, int param_2) { + uint* state = (uint*)(menu->state); uint pre_state = *state; - _UpdateAeonCustomizationMenuState.orig_fptr(param_1, param_2); + FhXCall.TkMenuCtrlSummon.chain_from(TkMenuCtrlSummon).fnptr!(menu, param_2); if (*state != pre_state) { - logger.Debug($"{pre_state} -> {*state}"); + _logger.Debug($"{pre_state} -> {*state}"); if (pre_state == 0x15) { TkWindow* DAT_0186a568 = (TkWindow*)FhUtil.get_at(0x0146a568); short selected_idx = DAT_0186a568->selected_index; - delegates.CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); byte customization_id = menu_list[selected_idx].customization_id; int num_customizations; - CustomizationRecipe* customizations = _MsGetRomSummonGrow(&num_customizations); - logger.Debug($"Applied customization {get_other_item_name((uint)(0xC07D + customization_id))}"); + AeonAbilityRecipe* customizations = FhXCall.MsGetRomSummonGrow.fnptr!(&num_customizations); + _logger.Debug($"Applied customization {get_other_item_name((uint)(0xC07D + customization_id))}"); if (customizations[customization_id].item_cost != original_sum_grow_costs[customization_id]) { uint item_id = (uint)(0xC07D + customization_id); other_inventory.TryGetValue(item_id, out int count); if (--count <= 0) { other_inventory.Remove(item_id); - customizations[customization_id].item_cost = original_sum_grow_costs[customization_id]; - } - else other_inventory[item_id] = count; - + customizations[customization_id].item_cost = (byte)original_sum_grow_costs[customization_id]; + } else other_inventory[item_id] = count; } } @@ -618,25 +575,26 @@ public void h_UpdateAeonCustomizationMenuState(uint param_1, uint param_2) { } } - public static ManagedCustomString customization_string = new ManagedCustomString($"Free!"); - public void h_DrawGearCustomizationMenu(TkWindow* window) { - //_DrawGearCustomizationMenu.orig_fptr(param_1); + public static ManagedCustomString customization_string = new("Free!"); + + public void DrawGearCustomizationMenu(TkWindow* window) { + //FhXCall.DrawGearCustomizationMenu.chain_from(DrawGearCustomizationMenu).fnptr!(param_1); DrawGearCustomizationMenu_reimplement(window); return; } - public void h_DrawAeonCustomizationMenu(TkWindow* window) { - //_DrawAeonCustomizationMenu.orig_fptr(param_1); + public void DrawAeonCustomizationMenu(TkWindow* window) { + //FhXCall.DrawAeonCustomizationMenu.chain_from(DrawAeonCustomizationMenu).fnptr!(param_1); DrawAeonCustomizationMenu_reimplement(window); } public void DrawAeonCustomizationMenu_reimplement(TkWindow* window) { - _TkVU1SyncPath(); - _FUN_008e71d0(7); - uint current_summon = _TkMenuGetCurrentSummon(); + FhXCall.TkVU1SyncPath.fnptr!(); + FhXCall.FUN_008e71d0.fnptr!(7); + uint current_summon = FhXCall.TkMenuGetCurrentSummon.fnptr!(); - delegates.CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); short selected_idx = window->selected_index; Vector2 pos_1; Vector2 pos_2; @@ -647,7 +605,7 @@ public void DrawAeonCustomizationMenu_reimplement(TkWindow* window) { } else { byte customization_id = menu_list[selected_idx].customization_id; int num_customizations; - CustomizationRecipe* customizations = _MsGetRomSummonGrow(&num_customizations); + AeonAbilityRecipe* customizations = FhXCall.MsGetRomSummonGrow.fnptr!(&num_customizations); item_id = customizations[customization_id].item; int item_cost = customizations[customization_id].item_cost; @@ -656,149 +614,180 @@ public void DrawAeonCustomizationMenu_reimplement(TkWindow* window) { if (item_cost == 0) { fixed (byte* text = customization_string.encoded) { Vector2 pos = new Vector2(1260f, 381f).game_remap_1080p(); - _ToMakeBtlEasyFont(text, pos.X, pos.Y, 0, 2f); + FhXCall.ToMakeBtlEasyFont.fnptr!(text, pos.X, pos.Y, 0, 2f); } - } - else { + } else { pos_1 = new Vector2(970f, 380f).game_remap_1080p(); - _FUN_008c1c70((int)pos_1.X, (int)pos_1.Y, item_id, item_cost); + FhXCall.FUN_008c1c70.fnptr!((int)pos_1.X, (int)pos_1.Y, item_id, item_cost); } - } pos_1 = new Vector2(210f, 226f).game_remap_1080p(); - _FUN_008ff490(current_summon, pos_1.X, pos_1.Y); + FhXCall.FUN_008ff490.fnptr!(current_summon, pos_1.X, pos_1.Y); pos_1 = new Vector2(210f, 312f).game_remap_1080p(); pos_2 = new Vector2(740f, 48f).game_remap_1080p(); - _TODrawMenuPlateXYWHType(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, 2); + FhXCall.TODrawMenuPlateXYWHType.fnptr!(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, 2); // Header text pos_1 = new Vector2(365f, 320f).game_remap_1080p(); pos_2 = new Vector2(430f, 36f).game_remap_1080p(); - _FUN_008f8bb0(0xf, pos_1.X, pos_1.Y, pos_2.X, pos_2.Y); + FhXCall.FUN_008f8bb0.fnptr!(0xf, pos_1.X, pos_1.Y, pos_2.X, pos_2.Y); if (-1 < (int)item_id) { pos_1 = new Vector2(970f, 312f).game_remap_1080p(); pos_2 = new Vector2(740f, 48f).game_remap_1080p(); - _TODrawMenuPlateXYWHType(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, 2); + FhXCall.TODrawMenuPlateXYWHType.fnptr!(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, 2); // Header text ("Item cost")? pos_1 = new Vector2(1125f, 318f).game_remap_1080p(); - pos_2 = new Vector2( 430f, 36f).game_remap_1080p(); - _FUN_008f8bb0(0x10, pos_1.X, pos_1.Y, pos_2.X, pos_2.Y); + pos_2 = new Vector2(430f, 36f).game_remap_1080p(); + FhXCall.FUN_008f8bb0.fnptr!(0x10, pos_1.X, pos_1.Y, pos_2.X, pos_2.Y); } - int iVar2 = (int)new Vector2(0, 365f).game_remap_1080p().Y; + int iVar2 = (int)new Vector2(0, 365f).game_remap_1080p() + .Y; int iVar6, sVar1; float fVar10; if (window->visible_item_offset == window->scroll_offset) { // Draw ability list - _FUN_008c0f40(iVar2, (int)(new Vector2(0, 70f).game_remap_1080p().Y * 9.0), 0, window->scroll_delta); + FhXCall.FUN_008c0f40.fnptr!( + iVar2, + (int)(new Vector2(0, 70f).game_remap_1080p() + .Y * 9.0), + 0, + window->scroll_delta + ); sVar1 = window->visible_item_offset; fVar10 = 0.0f; iVar6 = 0; - } - else { + } else { // Draw ability list when quick scrolling (L2/R2) - _FUN_008c0f40(iVar2, (int)(new Vector2(0, 70f).game_remap_1080p().Y * 9.0), 1, window->scroll_delta); + FhXCall.FUN_008c0f40.fnptr!( + iVar2, + (int)(new Vector2(0, 70f).game_remap_1080p() + .Y * 9.0), + 1, + window->scroll_delta + ); FUN_008cd960_Extra(window, 1, window->visible_item_offset, 0.0f, 0.0f); - _FUN_008c0f40(iVar2, (int)(new Vector2(0, 70f).game_remap_1080p().Y * 9.0), 2, window->scroll_delta); + FhXCall.FUN_008c0f40.fnptr!( + iVar2, + (int)(new Vector2(0, 70f).game_remap_1080p() + .Y * 9.0), + 2, + window->scroll_delta + ); - fVar10 = (int)(new Vector2(0, 70f).game_remap_1080p().Y * 9.0 * window->scroll_delta * -0.00024414063); + fVar10 = (int)(new Vector2(0, 70f).game_remap_1080p() + .Y * 9.0 * window->scroll_delta * -0.00024414063); sVar1 = window->scroll_offset; iVar6 = 2; } + FUN_008cd960_Extra(window, iVar6, sVar1, 0.0f, fVar10); - _FUN_008c1350_DrawScissor512x416(); + FhXCall.FUN_008c1350_DrawScissor512x416.fnptr!(); ushort _DAT_0186a5a4 = FhUtil.get_at(0x0146a5a4); ushort _DAT_0186a5a6 = FhUtil.get_at(0x0146a5a6); - _FUN_008cd9f0(window, _DAT_0186a5a4 + 0xc, _DAT_0186a5a6 + 1); + FhXCall.FUN_008cd9f0.fnptr!(window, _DAT_0186a5a4 + 0xc, _DAT_0186a5a6 + 1); float local_8; - _ToGetCrossExtMesFontWidth(0, _FUN_008bee80(5), &local_8, 0.78f, 1.0f); + FhXCall.ToGetCrossExtMesFontWidth.fnptr!(0, FhXCall.FUN_008bee80.fnptr!(5), &local_8, 0.78f, 1.0f); - fVar10 = (float)(double)(new Vector2(80f, 0).game_remap_1080p().X + local_8); + fVar10 = (float)(double)(new Vector2(80f, 0).game_remap_1080p() + .X + local_8); local_8 = fVar10; - - float fVar11 = new Vector2(660f, 0).game_remap_1080p().X; + float fVar11 = new Vector2(660f, 0).game_remap_1080p() + .X; if (fVar11 < (float)fVar10 == (float.IsNaN(fVar11) || float.IsNaN(fVar10))) { - fVar10 = new Vector2(740f, 0).game_remap_1080p().X; - } - else { - fVar10 = (float)(new Vector2(80f, 0).game_remap_1080p().X + local_8); + fVar10 = new Vector2(740f, 0).game_remap_1080p() + .X; + } else { + fVar10 = (float)(new Vector2(80f, 0).game_remap_1080p() + .X + local_8); } // graphicUiRemapX2(1806.0); - fVar11 = new Vector2(1806f, 0).game_remap_1080p().X - fVar10; + fVar11 = new Vector2(1806f, 0).game_remap_1080p() + .X - fVar10; float fVar12 = (float)((fVar10 - local_8) * 0.5 + fVar11); pos_1 = new Vector2(955f, 370f).game_remap_1080p(); pos_2 = new Vector2( 8f, 630f).game_remap_1080p(); - _DrawCrossMenuScrollParts(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, window->visible_item_offset, window->max_visible_items, window->num_items); - - _TODrawMenuPlateXYWHType(fVar11, new Vector2(0, 925f).game_remap_1080p().Y, fVar10, new Vector2(0, 48f).game_remap_1080p().Y, 2); + FhXCall.DrawCrossMenuScrollParts.fnptr!(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, window->visible_item_offset, window->max_visible_items, window->num_items); + + FhXCall.TODrawMenuPlateXYWHType.fnptr!( + fVar11, + new Vector2(0, 925f).game_remap_1080p() + .Y, + fVar10, + new Vector2(0, 48f).game_remap_1080p() + .Y, + 2 + ); float uv_y2 = 0.3017578f; float uv_x2 = 0.99902344f; float uv_y1 = 0.22851563f; float uv_x1 = 0.9267578f; - pos_1 = new Vector2( 0f, 920f).game_remap_1080p(); + pos_1 = new Vector2(0f, 920f).game_remap_1080p(); pos_2 = new Vector2(64f, 64f).game_remap_1080p(); - _TOMkpShapeXYWHUV(0xf3, fVar12, pos_1.Y, pos_2.X, pos_2.Y, uv_x1, uv_y1, uv_x2, uv_y2); + FhXCall.TOMkpShapeXYWHUV.fnptr!(0xf3, fVar12, pos_1.Y, pos_2.X, pos_2.Y, uv_x1, uv_y1, uv_x2, uv_y2); pos_1 = new Vector2(80f, 928f).game_remap_1080p(); - _TOMkpCrossExtMesFontLClut(0, _FUN_008bee80(5), pos_1.X + fVar12, pos_1.Y, 0, 0.78f, 1.0f); + FhXCall.TOMkpCrossExtMesFontLClut.fnptr!(0, FhXCall.FUN_008bee80.fnptr!(5), pos_1.X + fVar12, pos_1.Y, 0, 0.78f, 1.0f); - item_id = _FUN_008d48e0(); - _FUN_008d4140(item_id, 1); - _TkMn2DrawKickSyncPacket(); + item_id = FhXCall.FUN_008d48e0.fnptr!(); + FhXCall.FUN_008d4140.fnptr!(item_id, 1); + FhXCall.TkMn2DrawKickSyncPacket.fnptr!(); } private void FUN_008cd960_Extra(TkWindow* window, int param_2, int menu_offset, float x, float y) { - _FUN_008cd960(window, param_2, menu_offset, x, y); + FhXCall.FUN_008cd960.fnptr!(window, param_2, menu_offset, x, y); Vector2 pos = new(x, y); pos += new Vector2(209f + 50f, 306f).game_remap_1080p(); if (param_2 == 0) { - pos.Y -= (float)(new Vector2(0, 70f).game_remap_1080p().Y * window->scroll_delta * 0.00024414063); // Scroll offset + pos.Y -= (float)(new Vector2(0, 70f).game_remap_1080p() + .Y * window->scroll_delta * 0.00024414063); // Scroll offset } - delegates.CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); short menu_length = window->num_items; for (int i = -1; i < 10; i++) { int curr_index = menu_offset + i; if (0 <= curr_index && curr_index < menu_length) { if (menu_list[curr_index].customization_id != 0xFF) { int num_customizations; - CustomizationRecipe* customizations = _MsGetRomSummonGrow(&num_customizations); + AeonAbilityRecipe* customizations = FhXCall.MsGetRomSummonGrow.fnptr!(&num_customizations); uint item_id = customizations[menu_list[curr_index].customization_id].item; int item_cost = customizations[menu_list[curr_index].customization_id].item_cost; if (item_cost == 0) { fixed (byte* text = customization_string.encoded) { - _ToMakeBtlEasyFont(text, pos.X, pos.Y, 0, 0.78f); + FhXCall.ToMakeBtlEasyFont.fnptr!(text, pos.X, pos.Y, 0, 0.78f); } } } } + pos += new Vector2(0, 70f).game_remap_1080p(); } } public void DrawGearCustomizationMenu_reimplement(TkWindow* window) { - delegates.CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); short selected_idx = window->selected_index; Vector2 pos_1; Vector2 pos_2; if (menu_list[selected_idx].customization_id != 0xFF) { int num_customizations; - CustomizationRecipe* customizations = _MsGetRomKaizou(&num_customizations); + CustomizationRecipe* customizations = FhXCall.MsGetRomKaizou.fnptr!(&num_customizations); uint item_id = customizations[menu_list[selected_idx].customization_id].item; int item_cost = customizations[menu_list[selected_idx].customization_id].item_cost; @@ -807,57 +796,78 @@ public void DrawGearCustomizationMenu_reimplement(TkWindow* window) { if (item_cost == 0) { fixed (byte* text = customization_string.encoded) { Vector2 pos = new Vector2(1260f, 320f).game_remap_1080p(); - _ToMakeBtlEasyFont(text, pos.X, pos.Y, 0, 2f); + FhXCall.ToMakeBtlEasyFont.fnptr!(text, pos.X, pos.Y, 0, 2f); } } else { pos_1 = new Vector2(970f, 319f).game_remap_1080p(); - _FUN_008c1c70((int)pos_1.X, (int)pos_1.Y, item_id, item_cost); + FhXCall.FUN_008c1c70.fnptr!((int)pos_1.X, (int)pos_1.Y, item_id, item_cost); } // Header background pos_1 = new Vector2(970f, 252f).game_remap_1080p(); pos_2 = new Vector2(740f, 60f).game_remap_1080p(); - _TODrawMenuPlateXYWHType(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, 2); + FhXCall.TODrawMenuPlateXYWHType.fnptr!(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, 2); // Header ("Item cost") pos_1 = new Vector2(1125f, 264f).game_remap_1080p(); pos_2 = new Vector2(430f, 36f).game_remap_1080p(); - _FUN_008f8bb0(0x10, pos_1.X, pos_1.Y, pos_2.X, pos_2.Y); + FhXCall.FUN_008f8bb0.fnptr!(0x10, pos_1.X, pos_1.Y, pos_2.X, pos_2.Y); } //_TkMenuGetCurrentPlayer(); // Result is unused? // Abilities Header background pos_1 = new Vector2(211f, 252f).game_remap_1080p(); pos_2 = new Vector2(740f, 60f).game_remap_1080p(); - _TODrawMenuPlateXYWHType(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, 2); + FhXCall.TODrawMenuPlateXYWHType.fnptr!(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, 2); // Header ("Abilities") pos_1 = new Vector2(366f, 264f).game_remap_1080p(); pos_2 = new Vector2(430f, 36f).game_remap_1080p(); - _FUN_008f8bb0(7, pos_1.X, pos_1.Y, pos_2.X, pos_2.Y); + FhXCall.FUN_008f8bb0.fnptr!(7, pos_1.X, pos_1.Y, pos_2.X, pos_2.Y); if (window->visible_item_offset == window->scroll_offset) { - // Draw ability list - _TODrawScissorXYWH(0, (int)(new Vector2(0, 315f).game_remap_1080p().Y), 0x200, (int)(new Vector2(0, 680f).game_remap_1080p().Y)); + FhXCall.TODrawScissorXYWH.fnptr!( + 0, + (int)(new Vector2(0, 315f).game_remap_1080p() + .Y), + 0x200, + (int)(new Vector2(0, 680f).game_remap_1080p() + .Y) + ); FUN_008d5d20_Extra(window, 0, window->visible_item_offset, 0, 0); - } else { // Draw ability list when quick scrolling (L2/R2) short uVar5 = window->scroll_delta; // Scroll offset - _FUN_008c0f40((int)(new Vector2(0, 315f).game_remap_1080p().Y), (int)(new Vector2(0, 680f).game_remap_1080p().Y), 1, uVar5); + FhXCall.FUN_008c0f40.fnptr!( + (int)(new Vector2(0, 315f).game_remap_1080p() + .Y), + (int)(new Vector2(0, 680f).game_remap_1080p() + .Y), + 1, + uVar5 + ); FUN_008d5d20_Extra(window, 1, window->visible_item_offset, 0, 0); - _FUN_008c0f40((int)(new Vector2(0, 315f).game_remap_1080p().Y), (int)(new Vector2(0, 680f).game_remap_1080p().Y), 2, uVar5); - - int iVar2 = (int)(new Vector2(0, 675f).game_remap_1080p().Y * uVar5 * -0.00024414063); + FhXCall.FUN_008c0f40.fnptr!( + (int)(new Vector2(0, 315f).game_remap_1080p() + .Y), + (int)(new Vector2(0, 680f).game_remap_1080p() + .Y), + 2, + uVar5 + ); + + int iVar2 = (int)(new Vector2(0, 675f).game_remap_1080p() + .Y * uVar5 * -0.00024414063); FUN_008d5d20_Extra(window, 2, window->scroll_offset, 0, iVar2); } - _FUN_008c1350_DrawScissor512x416(); + + FhXCall.FUN_008c1350_DrawScissor512x416.fnptr!(); pos_1 = new Vector2(389f, 325f).game_remap_1080p(); - _FUN_008d5dc0(window, (int)pos_1.X, (int)pos_1.Y); + FhXCall.FUN_008d5dc0.fnptr!(window, (int)pos_1.X, (int)pos_1.Y); { int uVar5 = window->num_items; @@ -865,7 +875,7 @@ public void DrawGearCustomizationMenu_reimplement(TkWindow* window) { int iVar2 = window->visible_item_offset; pos_1 = new Vector2(955f, 319f).game_remap_1080p(); pos_2 = new Vector2(8f, 675f).game_remap_1080p(); - _DrawCrossMenuScrollParts(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, iVar2, uVar1, uVar5); + FhXCall.DrawCrossMenuScrollParts.fnptr!(pos_1.X, pos_1.Y, pos_2.X, pos_2.Y, iVar2, uVar1, uVar5); } { @@ -873,47 +883,48 @@ public void DrawGearCustomizationMenu_reimplement(TkWindow* window) { uint _DAT_0186a9f0 = FhUtil.get_at(0x146A9F0); int iVar2 = *(short*)(_DAT_0186a9f0 + 0x48); pos_1 = new Vector2(970f, 659f).game_remap_1080p(); - _FUN_008d6630((int)pos_1.X, (int)pos_1.Y, iVar2); + FhXCall.FUN_008d6630.fnptr!((int)pos_1.X, (int)pos_1.Y, iVar2); } - return; } private void FUN_008d5d20_Extra(TkWindow* window, int param_2, int menu_offset, int x, int y) { - _FUN_008d5d20(window, param_2, menu_offset, x, y); + FhXCall.FUN_008d5d20.fnptr!(window, param_2, menu_offset, x, y); Vector2 pos = new(x, y); pos += new Vector2(209f + 50f, 255f).game_remap_1080p(); if (param_2 == 0) { - pos.Y -= (float)(new Vector2(0, 75f).game_remap_1080p().Y * window->scroll_delta * 0.00024414063); // Scroll offset + pos.Y -= (float)(new Vector2(0, 75f).game_remap_1080p() + .Y * window->scroll_delta * 0.00024414063); // Scroll offset } - delegates.CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); + CustomizationMenuList* menu_list = FhUtil.ptr_at(0x1197730); short menu_length = window->num_items; for (int i = -1; i < 10; i++) { int curr_index = menu_offset + i; if (0 <= curr_index && curr_index < menu_length) { if (menu_list[curr_index].customization_id != 0xFF) { int num_customizations; - CustomizationRecipe* customizations = _MsGetRomKaizou(&num_customizations); + CustomizationRecipe* customizations = FhXCall.MsGetRomKaizou.fnptr!(&num_customizations); uint item_id = customizations[menu_list[curr_index].customization_id].item; int item_cost = customizations[menu_list[curr_index].customization_id].item_cost; if (item_cost == 0) { fixed (byte* text = customization_string.encoded) { - _ToMakeBtlEasyFont(text, pos.X, pos.Y, 0, 0.78f); + FhXCall.ToMakeBtlEasyFont.fnptr!(text, pos.X, pos.Y, 0, 0.78f); } } } } + pos += new Vector2(0, 75f).game_remap_1080p(); } } public static TkWindow* MyWindow; - public static void CreateMyWindow(Equipment* gear) - { - MyWindow = _TkMenuMainAllocWindow(); + + public static void CreateMyWindow(Equipment* gear) { + MyWindow = FhXCall.TkMenuMainAllocWindow.fnptr!(); MyWindow->num_items = gear->slot_count; MyWindow->max_visible_items = 4; MyWindow->selected_index = 0; @@ -921,76 +932,74 @@ public static void CreateMyWindow(Equipment* gear) MyWindow->fn_init = &MyWindow_Init; MyWindow->fn_state = &MyWindow_State; MyWindow->fn_render = &MyWindow_Render; - _TkMenuMainRegistWindow(MyWindow); + FhXCall.TkMenuMainRegistWindow.fnptr!(MyWindow); } [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] public static void MyWindow_Init(TkWindow* window) { window->current_state = 0; } + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] public static void MyWindow_State(TkWindow* window) { - while (true) - { - switch (window->current_state) - { + while (true) { + switch (window->current_state) { case 0: window->exit_value = 0; window->selected_index = 0; window->current_state = 1; return; + case 1: - if (Globals.Input.up.just_pressed && 0 < window->selected_index) - { - _SndSepPlaySimple(0x80000001); + if (Globals.Input.up.is_pressed && 0 < window->selected_index) { + FhXCall.SndSepPlaySimple.fnptr!(0x80000001); window->selected_index--; - } else if (Globals.Input.down.just_pressed && window->selected_index < window->num_items - 1) - { - _SndSepPlaySimple(0x80000001); + } else if (Globals.Input.down.is_pressed && window->selected_index < window->num_items - 1) { + FhXCall.SndSepPlaySimple.fnptr!(0x80000001); window->selected_index++; - } else if (Globals.Input.confirm.just_pressed) - { - _SndSepPlaySimple(0x80000001); + } else if (Globals.Input.confirm.is_pressed) { + FhXCall.SndSepPlaySimple.fnptr!(0x80000001); window->current_state = 2; - - } else if (Globals.Input.cancel.just_pressed) - { - _SndSepPlaySimple(0x80000004); + } else if (Globals.Input.cancel.is_pressed) { + FhXCall.SndSepPlaySimple.fnptr!(0x80000004); window->current_state = 3; } + return; + case 2: window->exit_value = 1; window->current_state = 5; break; + case 3: window->exit_value = -1; window->current_state = 7; break; + default: return; } } } + [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] public static void MyWindow_Render(TkWindow* window) { Vector2 pos = new Vector2(970 + 150, 735 + 12 + 68 * window->selected_index).game_remap_1080p(); - _TkMn2DrawCrossCursor(pos.X, pos.Y, 0); + FhXCall.TkMn2DrawCrossCursor.fnptr!(pos.X, pos.Y, 0); } - public static bool h_FUN_008d5720(uint gear_id, int param_2) - { - Equipment* gear = _MsGetSaveWeapon(gear_id, 0); + public static bool FUN_008d5720(uint gear_id, int param_2) { + Equipment* gear = FhXCall.MsGetSaveWeapon.fnptr!(gear_id, 0); bool can_customize = false; - if (gear->exists && !gear->is_hidden && gear->slot_count > 0) - { - if (param_2 != 0 || (!gear->is_celestial && !gear->is_brotherhood)) - { + if (gear->exists && !gear->is_hidden && gear->slot_count > 0) { + if (param_2 != 0 || (!gear->is_celestial && !gear->is_brotherhood)) { //if (gear->abilities[gear->slot_count-1] == 0xff || gear->abilities[gear->slot_count - 1] == 0) can_customize = true; } } + return can_customize; } } diff --git a/src/data/ArchipelagoData.cs b/src/data/ArchipelagoData.cs index 5d4b9f5..0619851 100644 --- a/src/data/ArchipelagoData.cs +++ b/src/data/ArchipelagoData.cs @@ -1,7 +1,10 @@ using Archipelago.MultiClient.Net.Enums; + using ArchipelagoFFX.Client; + using Fahrenheit.FFX; using Fahrenheit.FFX.Ids; + using System; using System.Collections.Generic; using System.Linq; @@ -59,10 +62,8 @@ public enum RegionEnum { MonsterArena, } - public static RegionEnum stringToRegion(string region) - { - return region.ToLowerInvariant() switch - { + public static RegionEnum stringToRegion(string region) { + return region.ToLowerInvariant() switch { "dreamzanarkand" or "intro" or "dz" or "drzn" or "drzk" or "open" or "znkd" or "dream" => RegionEnum.DreamZanarkand, "baajtemple" or "baj" or "baaj" or "bt" or "bjyt" or "cdsp" => RegionEnum.BaajTemple, "besaid" or "besaidisland" or "bsil" or "bsa" or "bsvr" or "bsyt" or "bsmm" => RegionEnum.Besaid, @@ -91,6 +92,7 @@ public static RegionEnum stringToRegion(string region) _ => RegionEnum.None }; } + public enum Goal { YuYevon = 0, Nemesis, @@ -129,459 +131,484 @@ public enum CaptureRequirement { 2850 // Yunalesca ]; - public static Dictionary> region_to_ids = new(){ - { RegionEnum.DreamZanarkand, [ - 132, - 368, - 376, - 371, - 370, - 366, - 389, - 367, - 384, - 385, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.BaajTemple, [ - 48, - 49, - 50, - 63, - 52, - 74, - 295, - 196, - 298, - 51, - 71, - 288, - 64, - 380, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Besaid, [ - 70, - 20, - 41, - 67, - 69, - 133, - 17, - 142, - 144, - 145, - 60, - 143, - 84, - 42, - 147, - 146, - 122, - 103, - 83, - 100, - 252, - 68, - 21, - 22, - 19, - 117, - 301, - 148, - 149, - 150, - 154, - 61, - 282, - 220, - 139, - 191, // - 336, // Jecht Sphere - 337, // Jecht Sphere - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Kilika, [ - 43, - 53, - 152, - 46, - 16, - 151, - 293, - 18, - 65, - 78, - 155, - 156, - 96, - 44, - 108, - 45, - 98, - 47, - 118, - 167, - 237, - 168, - 94, - 169, - 191, - 297, - 185, - 294, // Maybe - 302, // Maybe - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Luca, [ - 267, - 377, - 268, - 355, - 72, - 123, - 73, - 85, - 86, - 87, - 88, - 89, - 77, - 157, - 170, - 158, - 184, - 104, - 107, - 159, - 57, - 121, - 299, - 113, - 124, - 62, - 212, - 347, - 250, - 125, - 55, - 335, // Jecht Sphere - ] }, - { RegionEnum.MiihenHighroad, [ - 95, - 120, - 127, - 58, - 171, - 112, - 115, - 116, - 59, - 334, // Jecht Sphere - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.MushroomRockRoad, [ - 79, - 92, - 128, - 119, - 247, - 254, - 218, - 341, - 134, - 131, - 253, // Jecht Sphere? - 289, // Maybe - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Djose, [ - 93, - 76, - 82, - 210, - 81, - 161, - 160, - 214, - 90, - 91, - 245, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Moonflow, [ - 75, - 105, - 187, - 188, - 235, - 99, - 291, - 236, - 190, - 189, - 109, - 97, - 234, // Maybe - 333, // Jecht Sphere - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Guadosalam, [ - 135, - 243, - 174, - 173, - 172, - 163, - 141, - 197, - 217, - 175, - 257, - 193, - 364, - 134, - 213, // Maybe? - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.ThunderPlains, [ - 140, - 256, - 264, - 263, - 262, - 162, - 332, // Jecht Sphere - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Macalania, [ - 110, - 241, - 242, - 221, - 248, - 164, - 215, - 102, - 192, - 153, - 106, - 178, - 179, - 239, - 80, - 54, - 284, - 330, - 331, - 332, - 191, - 260, // Maybe - 365, // Maybe - 391, // Luca flashback - 338, // Jecht Sphere - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Bikanel, [ - 129, - 136, - 137, - 138, - 130, - 276, - 280, - 286, - 275, - 219, - 303, - 261, - 391, // Luca flashback - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Airship, [ - 194, - 265, - 351, - 211, - 277, - 255, - 392, - 205, - 199, - 200, - 201, - 374, // Unsure - 375, // Unsure - 202, // Unsure - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Bevelle, [ - 205, - 180, - 181, - 182, - 306, - 226, - 198, - 209, - 208, - 183, - 274, - 206, - 177, - 176, - 329, - 227, - 305, - 238, // Maybe - 269, // Maybe - 273, // Maybe - 287, // Maybe - 339, // Jecht Sphere - 195, - 207, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.CalmLands, [ - 223, - 290, - 308, - 279, - 372, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.CavernOfTheStolenFayth, [ - 266, - 56, - 283, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.MtGagazet, [ - 259, - 244, - 285, - 309, - 134, - 165, - 249, - 272, - 310, - 311, - 312, - 361, - 381, - 383, // Braska Sphere - 362, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.ZanarkandRuins, [ - 132, - 363, - 225, - 314, - 222, - 316, - 320, - 317, - 318, - 224, - 270, - 319, - 315, - 313, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.Sin, [ - 322, - 203, - 296, - 204, - 327, - 324, // Point of no return : 3250 - 325, - 326, - 386, // Ending - 387, // Ending - 388, // Ending - 390, // Ending - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.OmegaRuins, [ - 258, - 271, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, - { RegionEnum.MonsterArena, [ - 307, - 355, //Blitzball Tutorial - 347, //Blitzball Menu - 62, //Blitzball Arena - 212, //Results Screen - ] }, + public static Dictionary> region_to_ids = new() { + { + RegionEnum.DreamZanarkand, [ + 132, + 368, + 376, + 371, + 370, + 366, + 389, + 367, + 384, + 385, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.BaajTemple, [ + 48, + 49, + 50, + 63, + 52, + 74, + 295, + 196, + 298, + 51, + 71, + 288, + 64, + 380, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Besaid, [ + 70, + 20, + 41, + 67, + 69, + 133, + 17, + 142, + 144, + 145, + 60, + 143, + 84, + 42, + 147, + 146, + 122, + 103, + 83, + 100, + 252, + 68, + 21, + 22, + 19, + 117, + 301, + 148, + 149, + 150, + 154, + 61, + 282, + 220, + 139, + 191, // + 336, // Jecht Sphere + 337, // Jecht Sphere + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Kilika, [ + 43, + 53, + 152, + 46, + 16, + 151, + 293, + 18, + 65, + 78, + 155, + 156, + 96, + 44, + 108, + 45, + 98, + 47, + 118, + 167, + 237, + 168, + 94, + 169, + 191, + 297, + 185, + 294, // Maybe + 302, // Maybe + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Luca, [ + 267, + 377, + 268, + 355, + 72, + 123, + 73, + 85, + 86, + 87, + 88, + 89, + 77, + 157, + 170, + 158, + 184, + 104, + 107, + 159, + 57, + 121, + 299, + 113, + 124, + 62, + 212, + 347, + 250, + 125, + 55, + 335, // Jecht Sphere + ] + }, { + RegionEnum.MiihenHighroad, [ + 95, + 120, + 127, + 58, + 171, + 112, + 115, + 116, + 59, + 334, // Jecht Sphere + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.MushroomRockRoad, [ + 79, + 92, + 128, + 119, + 247, + 254, + 218, + 341, + 134, + 131, + 253, // Jecht Sphere? + 289, // Maybe + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Djose, [ + 93, + 76, + 82, + 210, + 81, + 161, + 160, + 214, + 90, + 91, + 245, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Moonflow, [ + 75, + 105, + 187, + 188, + 235, + 99, + 291, + 236, + 190, + 189, + 109, + 97, + 234, // Maybe + 333, // Jecht Sphere + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Guadosalam, [ + 135, + 243, + 174, + 173, + 172, + 163, + 141, + 197, + 217, + 175, + 257, + 193, + 364, + 134, + 213, // Maybe? + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.ThunderPlains, [ + 140, + 256, + 264, + 263, + 262, + 162, + 332, // Jecht Sphere + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Macalania, [ + 110, + 241, + 242, + 221, + 248, + 164, + 215, + 102, + 192, + 153, + 106, + 178, + 179, + 239, + 80, + 54, + 284, + 330, + 331, + 332, + 191, + 260, // Maybe + 365, // Maybe + 391, // Luca flashback + 338, // Jecht Sphere + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Bikanel, [ + 129, + 136, + 137, + 138, + 130, + 276, + 280, + 286, + 275, + 219, + 303, + 261, + 391, // Luca flashback + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Airship, [ + 194, + 265, + 351, + 211, + 277, + 255, + 392, + 205, + 199, + 200, + 201, + 374, // Unsure + 375, // Unsure + 202, // Unsure + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Bevelle, [ + 205, + 180, + 181, + 182, + 306, + 226, + 198, + 209, + 208, + 183, + 274, + 206, + 177, + 176, + 329, + 227, + 305, + 238, // Maybe + 269, // Maybe + 273, // Maybe + 287, // Maybe + 339, // Jecht Sphere + 195, + 207, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.CalmLands, [ + 223, + 290, + 308, + 279, + 372, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.CavernOfTheStolenFayth, [ + 266, + 56, + 283, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.MtGagazet, [ + 259, + 244, + 285, + 309, + 134, + 165, + 249, + 272, + 310, + 311, + 312, + 361, + 381, + 383, // Braska Sphere + 362, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.ZanarkandRuins, [ + 132, + 363, + 225, + 314, + 222, + 316, + 320, + 317, + 318, + 224, + 270, + 319, + 315, + 313, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.Sin, [ + 322, + 203, + 296, + 204, + 327, + 324, // Point of no return : 3250 + 325, + 326, + 386, // Ending + 387, // Ending + 388, // Ending + 390, // Ending + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.OmegaRuins, [ + 258, + 271, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, { + RegionEnum.MonsterArena, [ + 307, + 355, //Blitzball Tutorial + 347, //Blitzball Menu + 62, //Blitzball Arena + 212, //Results Screen + ] + }, }; - public static readonly Lookup id_to_regions = (Lookup)region_to_ids.SelectMany(region => region.Value, (region, id) => new{region.Key, id}).ToLookup(pair => pair.id, pair => pair.Key); + public static readonly Lookup id_to_regions = (Lookup)region_to_ids + .SelectMany(region => region.Value, (region, id) => new { region.Key, id }) + .ToLookup(pair => pair.id, pair => pair.Key); - public delegate void ArchipelagoStoryCheckDelegate(ArchipelagoRegion region); + public delegate void ArchipelagoStoryCheckDelegate(ArchipelagoRegion region, ArchipelagoClientModule client, ArchipelagoFFXModule ffx_interop); public class ArchipelagoStoryCheck { public ushort? next_story_progress; @@ -592,355 +619,653 @@ public class ArchipelagoStoryCheck { public bool return_to_airship = false; public ArchipelagoStoryCheckDelegate? check_delegate; } + public enum SaveDataType { Byte, Short, Int, } + public struct ArchipelagoRegionSaveData(uint offset, int size) { - [JsonInclude] - public uint offset = offset; - [JsonInclude] - public int size = size; - [JsonInclude] - public byte[] bytes = new byte[size]; + [JsonInclude] public uint offset = offset; + [JsonInclude] public int size = size; + [JsonInclude] public byte[] bytes = new byte[size]; + public ArchipelagoRegionSaveData(uint offset, int size, byte[] value) : this(offset, size) { this.bytes = value; } } + public unsafe class ArchipelagoRegion { - public Dictionary story_checks = []; + public Dictionary story_checks = [ ]; - [JsonInclude] - public int completed_visits; - [JsonInclude] - public ushort story_progress; - [JsonInclude] - public ushort room_id; - [JsonInclude] - public ushort entrance; + [JsonInclude] public int completed_visits; + [JsonInclude] public ushort story_progress; + [JsonInclude] public ushort room_id; + [JsonInclude] public ushort entrance; public bool pilgrimage_completed { get; set; } public uint airship_destination_index; - [JsonInclude] - public ArchipelagoRegionSaveData[] savedata = []; - + [JsonInclude] public ArchipelagoRegionSaveData[] savedata = [ ]; } - public static unsafe Dictionary region_starting_state => new(){ - {RegionEnum.DreamZanarkand, new(){ story_progress = 0, room_id = 132, entrance = 0, airship_destination_index = 99, - story_checks = { - // Dream Zanarkand region does not exist in Apworld, so no place to put Tidus location. Revisit when starting party member rando is added. - //{ 4, new() {check_delegate = (r) => { - // // Tidus - // int partyMember_id = 0; - // if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - // if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - // if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - // ArchipelagoFFXModule.obtain_item(item.id); - // } - // } - // } - //} } }, - { 5, new() {check_delegate = (r) => { - ArchipelagoFFXModule.logger.Info("Dream Zanarkand complete"); - ArchipelagoFFXModule.save_party(); - ArchipelagoFFXModule.reset_party(); - ArchipelagoFFXModule.call_warp_to_map(382, 0); - }} } - } } }, - {RegionEnum.BaajTemple, new(){ story_progress = 30, room_id = 48, entrance = 0, airship_destination_index = 1, - story_checks = { - { 60, new() {check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Baaj Temple visit 1 complete"); } } }, - { 110, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 49, next_entrance = 2, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Al Bhed Ship complete"); } } }, - } } }, - {RegionEnum.Besaid, new(){ story_progress = 111, room_id = 70, entrance = 0, airship_destination_index = 2, - story_checks = { - { 119, new() {check_delegate = (r) => { - // Wakka - int partyMember_id = 4; - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + public unsafe static Dictionary region_starting_state => new() { + { + RegionEnum.DreamZanarkand, new() { + story_progress = 0, room_id = 132, entrance = 0, airship_destination_index = 99, + story_checks = { + // Dream Zanarkand region does not exist in Apworld, so no place to put Tidus location. Revisit when starting party member rando is added. + //{ 4, new() {check_delegate = (r, client, ffx_interop) => { + // // Tidus + // int partyMember_id = 0; + // if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { + // if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + // if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { + // ffx_interop.obtain_item(item.id); + // } + // } + // } + //} } }, + { + 5, new() { + check_delegate = (r, client, ffx_interop) => { + //ffx_interop.logger.Info("Dream Zanarkand complete"); + ffx_interop.save_party(); + ffx_interop.reset_party(); + ffx_interop.call_warp_to_map(382, 0); } } } - } } }, - { 182, new() {pilgrimage = true, check_delegate = (r) => { - // Valefor - int partyMember_id = 8; - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + } + } + }, { + RegionEnum.BaajTemple, new() { + story_progress = 30, room_id = 48, entrance = 0, airship_destination_index = 1, + story_checks = { + { + 60, + new() { + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Baaj Temple visit 1 complete"); } } - } - } } }, - { 210, new() {check_delegate = (r) => { - // Send and obtain Map and Brotherhood locations if skipped by CSR - int treasure_id = 459; - if (!FFXArchipelagoClient.local_checked_locations.Contains(treasure_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(treasure_id, FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + { + 110, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 49, + next_entrance = 2, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Al Bhed Ship complete"); } } - } - int other_id = 0; - if (!FFXArchipelagoClient.local_checked_locations.Contains(other_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Other)) { - if (ArchipelagoFFXModule.item_locations.other.TryGetValue(other_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(other_id, FFXArchipelagoClient.ArchipelagoLocationType.Other)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + } + } + }, { + RegionEnum.Besaid, new() { + story_progress = 111, room_id = 70, entrance = 0, airship_destination_index = 2, + story_checks = { + { + 119, new() { + check_delegate = (r, client, ffx_interop) => { + // Wakka + int partyMember_id = 4; + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } + } + } } } - } - } } }, - { 228, new() {check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Besaid visit 1 complete"); } } }, - { 248, new() {check_delegate = (r) => { - int partyMember_id = 3; // Kimahri - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, { + 182, new() { + pilgrimage = true, + check_delegate = (r, client, ffx_interop) => { + // Valefor + int partyMember_id = 8; + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } + } + } } } - } - } } }, - { 290, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 19, next_entrance = 1, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("S.S Liki visit complete"); } } }, - } } }, - {RegionEnum.Kilika, new(){ story_progress = 304, room_id = 16, entrance = 0, airship_destination_index = 3, - savedata = [ - new ArchipelagoRegionSaveData(0x03AC, 1, [0]), - ], - story_checks = { - { 348, new() {pilgrimage = true, check_delegate = (r) => { - // Ifrit - int partyMember_id = 9; - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, { + 210, new() { + check_delegate = (r, client, ffx_interop) => { + // Send and obtain Map and Brotherhood locations if skipped by CSR + int treasure_id = 459; + if (!client.local_checked_locations.Contains(treasure_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { + if (client.sendLocation(treasure_id, ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + ffx_interop.obtain_item(item.id); + } + } + } + + int other_id = 0; + if (!client.local_checked_locations.Contains(other_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Other)) { + if (ArchipelagoFFXModule.item_locations.other.TryGetValue(other_id, out var item)) { + if (client.sendLocation(other_id, ArchipelagoClientModule.ArchipelagoLocationType.Other)) { + ffx_interop.obtain_item(item.id); + } + } + } } } - } - } } }, - { 372, new() {check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Kilika visit 1 complete"); } } }, - { 400, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 98, next_entrance = 3, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("S.S Winno visit complete"); } } }, - { 402, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 98, next_entrance = 3, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("S.S Winno visit complete"); } } }, - } } }, - {RegionEnum.Luca, new(){ story_progress = 402, room_id = 267, entrance = 0, airship_destination_index = 4, - story_checks = { - { 600, new() {check_delegate = (r) => { - // Auron - int partyMember_id = 2; - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + { 228, + new() { + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Besaid visit 1 complete"); } } - } - } } }, - { 730, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 123, next_entrance = 6, return_to_airship = true, - check_delegate = (r) => { - ArchipelagoFFXModule.logger.Info("Luca visit complete"); - // CSR workaround - Globals.save_data->current_room_id = 123; - Globals.save_data->current_spawnpoint = 6; - } } }, - } } }, - {RegionEnum.MiihenHighroad, new(){ story_progress = 730, room_id = 95, entrance = 0, airship_destination_index = 5, - savedata = [ - new ArchipelagoRegionSaveData(0x0285, 1), - new ArchipelagoRegionSaveData(0x0C3C, 4), - new ArchipelagoRegionSaveData(0x0C40, 4), - new ArchipelagoRegionSaveData(0x0C44, 4), - new ArchipelagoRegionSaveData(0x0C48, 4), + + }, { + 248, new() { + check_delegate = (r, client, ffx_interop) => { + int partyMember_id = 3; // Kimahri + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } + } + } + } + } + }, + { + 290, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 19, + next_entrance = 1, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("S.S Liki visit complete"); + } + } + }, + } + } + }, { + RegionEnum.Kilika, new() { + story_progress = 304, room_id = 16, entrance = 0, airship_destination_index = 3, + savedata = [ + new ArchipelagoRegionSaveData(0x03AC, 1, [ 0 ]), ], - story_checks = { - { 787, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 171, next_entrance = 1, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Mi'ihen Highroad visit complete"); } } }, - } } }, - {RegionEnum.MushroomRockRoad, new(){ story_progress = 787, room_id = 79, entrance = 0, airship_destination_index = 6, - story_checks = { - { 960, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 131, next_entrance = 3, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Mushroom Rock Road visit complete"); } } }, - } } }, - {RegionEnum.Djose, new(){ story_progress = 960, room_id = 93, entrance = 0, airship_destination_index = 7, - story_checks = { - { 1010, new() {pilgrimage = true, check_delegate = (r) => { - // Ixion - int partyMember_id = 10; - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + story_checks = { + { + 348, new() { + pilgrimage = true, check_delegate = (r, client, ffx_interop) => { + // Ifrit + int partyMember_id = 9; + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } + } + } } } - } - } } }, - { 1030, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 82, next_entrance = 0, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Djose visit 1 complete"); } } }, - } } }, - {RegionEnum.Moonflow, new(){ story_progress = 1030, room_id = 75, entrance = 0, airship_destination_index = 8, - story_checks = { - { 1085, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 235, next_entrance = 1, return_to_airship = true, - check_delegate = (r) => { - // Rikku - int partyMember_id = 6; - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + { + 372, + new() { + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Kilika visit 1 complete"); } } - } - ArchipelagoFFXModule.logger.Info("Moonflow visit complete"); - } } }, - } } }, - {RegionEnum.Guadosalam, new(){ story_progress = 1085, room_id = 135, entrance = 0, airship_destination_index = 9, - story_checks = { - { 1170, new() {check_delegate = (r) => { - // Send and obtain Brotherhood upgrade location if skipped by CSR - int other_id = 37; - if (!FFXArchipelagoClient.local_checked_locations.Contains(other_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Other)) { - if (ArchipelagoFFXModule.item_locations.other.TryGetValue(other_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(other_id, FFXArchipelagoClient.ArchipelagoLocationType.Other)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + { + 400, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 98, + next_entrance = 3, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("S.S Winno visit complete"); } } - } - } } }, - { 1210, new() {visit_complete = true, next_story_progress = 1310, next_room_id = 243, next_entrance = 1, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Guadosalam visit complete"); } } }, - } } }, - {RegionEnum.ThunderPlains, new(){ story_progress = 1210, room_id = 140, entrance = 0, airship_destination_index = 10, - savedata = [ - new ArchipelagoRegionSaveData(0x03F8, 1, [0]), - new ArchipelagoRegionSaveData(0x03F1, 3, [0, 0, 0]) //save_data->progression_flags_thunder_plains - ], - story_checks = { - { 1375, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 263, next_entrance = 2, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Thunder Plains visit complete"); } } }, - } } }, - {RegionEnum.Macalania, new(){ story_progress = 1400, room_id = 110, entrance = 0, airship_destination_index = 11, - story_checks = { - { 1470, new() {check_delegate = (r) => { - ArchipelagoFFXModule.logger.Info("Macalania Woods visit complete"); - int treasure_id = 177; - if (!FFXArchipelagoClient.local_checked_locations.Contains(treasure_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(treasure_id, FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + { + 402, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 98, + next_entrance = 3, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("S.S Winno visit complete"); } } - } - } } }, - { 1530, new() {check_delegate = (r) => { - int treasure_id = 85; - if (!FFXArchipelagoClient.local_checked_locations.Contains(treasure_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(treasure_id, FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + } + } + }, { + RegionEnum.Luca, new() { + story_progress = 402, room_id = 267, entrance = 0, airship_destination_index = 4, + story_checks = { + { + 600, new() { + check_delegate = (r, client, ffx_interop) => { + // Auron + int partyMember_id = 2; + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } + } + } } } - } } } }, - { 1545, new() {pilgrimage = true, check_delegate = (r) => { - // Shiva - int partyMember_id = 11; - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, { + 730, new() { + visit_complete = true, next_story_progress = 3210, next_room_id = 123, next_entrance = 6, return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Luca visit complete"); + // CSR workaround + Globals.save_data->current_room_id = 123; + Globals.save_data->current_spawnpoint = 6; } } - } - } } }, - { 1704, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 215, next_entrance = 1, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Lake Macalania visit 1 complete"); } } }, - } } }, - {RegionEnum.Bikanel, new(){ story_progress = 1704, room_id = 129, entrance = 0, airship_destination_index = 12, - story_checks = { - { 1940, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 129, next_entrance = 2, return_to_airship = true, check_delegate = (r) => { - ArchipelagoFFXModule.logger.Info("Bikanel visit complete"); - int[] treasure_ids = [362, 363, 364]; - foreach (int treasure_id in treasure_ids) { - if (!FFXArchipelagoClient.local_checked_locations.Contains(treasure_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(treasure_id, FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + } + } + }, { + RegionEnum.MiihenHighroad, new() { + story_progress = 730, room_id = 95, entrance = 0, airship_destination_index = 5, + savedata = [ + new ArchipelagoRegionSaveData(0x0285, 1), + new ArchipelagoRegionSaveData(0x0C3C, 4), + new ArchipelagoRegionSaveData(0x0C40, 4), + new ArchipelagoRegionSaveData(0x0C44, 4), + new ArchipelagoRegionSaveData(0x0C48, 4), + ], + story_checks = { + { + 787, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 171, + next_entrance = 1, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Mi'ihen Highroad visit complete"); + } + } + }, + } + } + }, { + RegionEnum.MushroomRockRoad, new() { + story_progress = 787, room_id = 79, entrance = 0, airship_destination_index = 6, + story_checks = { + { + 960, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 131, + next_entrance = 3, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Mushroom Rock Road visit complete"); + } + } + }, + } + } + }, { + RegionEnum.Djose, new() { + story_progress = 960, room_id = 93, entrance = 0, airship_destination_index = 7, + story_checks = { + { + 1010, new() { + pilgrimage = true, check_delegate = (r, client, ffx_interop) => { + // Ixion + int partyMember_id = 10; + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } + } } } } - } - } } }, - { 1950, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 129, next_entrance = 2, return_to_airship = true, check_delegate = (r) => { - ArchipelagoFFXModule.logger.Info("Bikanel visit complete"); - int[] treasure_ids = [362, 363, 364]; - foreach (int treasure_id in treasure_ids) { - if (!FFXArchipelagoClient.local_checked_locations.Contains(treasure_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(treasure_id, FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + { + 1030, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 82, + next_entrance = 0, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Djose visit 1 complete"); + } + } + }, + } + } + }, { + RegionEnum.Moonflow, new() { + story_progress = 1030, room_id = 75, entrance = 0, airship_destination_index = 8, + story_checks = { + { + 1085, new() { + visit_complete = true, next_story_progress = 3210, next_room_id = 235, next_entrance = 1, return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + // Rikku + int partyMember_id = 6; + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } + } } + + //ArchipelagoFFXModule.logger.Info("Moonflow visit complete"); } } - } - } } }, - } } }, - {RegionEnum.Airship, new(){ story_progress = 1950, room_id = 194, entrance = 1, airship_destination_index = 13, - story_checks = { - { 2075, new() {visit_complete = true, next_story_progress = 2970, next_room_id = 255, next_entrance = 0, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Airship visit 1 complete"); } } }, - //{ 3135, new() {next_story_progress = 3210, next_room_id = 255, next_entrance = 0, return_if_locked = RegionEnum.Sin, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Airship visit 2 complete"); } } }, - } } }, - {RegionEnum.Bevelle, new(){ story_progress = 2040, room_id = 205, entrance = 0, airship_destination_index = 14, - story_checks = { - { 2220, new() {pilgrimage = true, check_delegate = (r) => { - // Bahamut - int partyMember_id = 12; - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, + } + } + }, { + RegionEnum.Guadosalam, new() { + story_progress = 1085, room_id = 135, entrance = 0, airship_destination_index = 9, + story_checks = { + { + 1170, new() { + check_delegate = (r, client, ffx_interop) => { + // Send and obtain Brotherhood upgrade location if skipped by CSR + int other_id = 37; + if (!client.local_checked_locations.Contains(other_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Other)) { + if (ArchipelagoFFXModule.item_locations.other.TryGetValue(other_id, out var item)) { + if (client.sendLocation(other_id, ArchipelagoClientModule.ArchipelagoLocationType.Other)) { + ffx_interop.obtain_item(item.id); + } + } + } } } - } - } } }, - { 2385, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 208, next_entrance = 1, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Bevelle complete"); } } }, - } } }, - {RegionEnum.CalmLands, new(){ story_progress = 2385, room_id = 223, entrance = 0, airship_destination_index = 15, - savedata = [ - new ArchipelagoRegionSaveData(0x0285, 1), - new ArchipelagoRegionSaveData(0x0C3C, 4), - new ArchipelagoRegionSaveData(0x0C40, 4), - new ArchipelagoRegionSaveData(0x0C44, 4), - new ArchipelagoRegionSaveData(0x0C48, 4), + }, + { + 1210, + new() { + visit_complete = true, + next_story_progress = 1310, + next_room_id = 243, + next_entrance = 1, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Guadosalam visit complete"); + } + } + }, + } + } + }, { + RegionEnum.ThunderPlains, new() { + story_progress = 1210, room_id = 140, entrance = 0, airship_destination_index = 10, + savedata = [ + new ArchipelagoRegionSaveData(0x03F8, 1, [ 0 ]), + new ArchipelagoRegionSaveData(0x03F1, 3, [ 0, 0, 0 ]) //save_data->progression_flags_thunder_plains ], - story_checks = { - { 2440, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 223, next_entrance = 4, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Calm Lands complete"); } } }, // Normally ends at 2440, but CSR skips from 2420 to 2510 - { 2510, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 223, next_entrance = 4, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Calm Lands complete"); } } }, // Normally ends at 2440, but CSR skips from 2420 to 2510 - } } }, - {RegionEnum.CavernOfTheStolenFayth, new(){ story_progress = 2420, room_id = 266, entrance = 0, airship_destination_index = 16 } }, - {RegionEnum.MtGagazet, new(){ story_progress = 2440, room_id = 259, entrance = 0, airship_destination_index = 18, - story_checks = { - { 2680, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 259, next_entrance = 2, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Mt. Gagazet complete"); } } }, - } } }, - {RegionEnum.ZanarkandRuins, new(){ story_progress = 2680, room_id = 132, entrance = 0, airship_destination_index = 19, - story_checks = { - { 2850, new() {pilgrimage = true } }, - { 2875, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 313, next_entrance = 3, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Zanarkand Ruins complete"); } } }, - { 2900, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 313, next_entrance = 3, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Zanarkand Ruins complete"); } } }, - } } }, - {RegionEnum.Sin, new(){ story_progress = 3125, room_id = 322, entrance = 2, airship_destination_index = 20, - story_checks = { - { 3400, new() {visit_complete = true, next_room_id = 322, next_entrance = 2, check_delegate = (r) => { - ArchipelagoFFXModule.logger.Info("Game Complete"); - foreach (var character in ArchipelagoFFXModule.locked_characters) { - ArchipelagoFFXModule.locked_characters[character.Key] = false; - } - } } }, - { 11000, new() {next_story_progress = 3210, next_room_id = 327, next_entrance = 0, check_delegate = (r) => { - ArchipelagoFFXModule.call_warp_to_map(382, 0); - } } }, - } } }, - {RegionEnum.OmegaRuins, new(){ story_progress = 3210, room_id = 258, entrance = 2, airship_destination_index = 21 } }, // Story_progress? - {RegionEnum.MonsterArena, new(){ story_progress = 3210, room_id = 307, entrance = 0, airship_destination_index = 17 } }, + story_checks = { + { + 1375, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 263, + next_entrance = 2, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Thunder Plains visit complete"); + } + } + }, + } + } + }, { + RegionEnum.Macalania, new() { + story_progress = 1400, room_id = 110, entrance = 0, airship_destination_index = 11, + story_checks = { + { + 1470, new() { + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Macalania Woods visit complete"); + int treasure_id = 177; + if (!client.local_checked_locations.Contains(treasure_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { + if (client.sendLocation(treasure_id, ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + ffx_interop.obtain_item(item.id); + } + } + } + } + } + }, { + 1530, new() { + check_delegate = (r, client, ffx_interop) => { + int treasure_id = 85; + if (!client.local_checked_locations.Contains(treasure_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { + if (client.sendLocation(treasure_id, ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + ffx_interop.obtain_item(item.id); + } + } + } + } + } + }, { + 1545, new() { + pilgrimage = true, check_delegate = (r, client, ffx_interop) => { + // Shiva + int partyMember_id = 11; + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } + } + } + } + } + }, + { + 1704, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 215, + next_entrance = 1, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Lake Macalania visit 1 complete"); + } + } + }, + } + } + }, { + RegionEnum.Bikanel, new() { + story_progress = 1704, room_id = 129, entrance = 0, airship_destination_index = 12, + story_checks = { + { + 1940, new() { + visit_complete = true, next_story_progress = 3210, next_room_id = 129, next_entrance = 2, return_to_airship = true, check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Bikanel visit complete"); + int[] treasure_ids = [ 362, 363, 364 ]; + foreach (int treasure_id in treasure_ids) { + if (!client.local_checked_locations.Contains(treasure_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { + if (client.sendLocation(treasure_id, ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + ffx_interop.obtain_item(item.id); + } + } + } + } + } + } + }, { + 1950, new() { + visit_complete = true, next_story_progress = 3210, next_room_id = 129, next_entrance = 2, return_to_airship = true, check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Bikanel visit complete"); + int[] treasure_ids = [ 362, 363, 364 ]; + foreach (int treasure_id in treasure_ids) { + if (!client.local_checked_locations.Contains(treasure_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { + if (client.sendLocation(treasure_id, ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { + ffx_interop.obtain_item(item.id); + } + } + } + } + } + } + }, + } + } + }, { + RegionEnum.Airship, new() { + story_progress = 1950, room_id = 194, entrance = 1, airship_destination_index = 13, + story_checks = { + { 2075, new() { visit_complete = true, next_story_progress = 2970, next_room_id = 255, next_entrance = 0, return_to_airship = true, check_delegate = (r, client, ffx_interop) => { /* ArchipelagoFFXModule.logger.Info(Airship visit 1 complete); */ } } }, + //{ 3135, new() {next_story_progress = 3210, next_room_id = 255, next_entrance = 0, return_if_locked = RegionEnum.Sin, check_delegate = (r, client, ffx_interop) => {ArchipelagoFFXModule.logger.Info("Airship visit 2 complete"); } } }, + } + } + }, { + RegionEnum.Bevelle, new() { + story_progress = 2040, room_id = 205, entrance = 0, airship_destination_index = 14, + story_checks = { + { + 2220, new() { + pilgrimage = true, check_delegate = (r, client, ffx_interop) => { + // Bahamut + int partyMember_id = 12; + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } + } + } + } + } + }, + { + 2385, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 208, + next_entrance = 1, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Bevelle complete"); + } + } + }, + } + } + }, { + RegionEnum.CalmLands, new() { + story_progress = 2385, room_id = 223, entrance = 0, airship_destination_index = 15, + savedata = [ + new ArchipelagoRegionSaveData(0x0285, 1), + new ArchipelagoRegionSaveData(0x0C3C, 4), + new ArchipelagoRegionSaveData(0x0C40, 4), + new ArchipelagoRegionSaveData(0x0C44, 4), + new ArchipelagoRegionSaveData(0x0C48, 4), + ], + story_checks = { + { + 2440, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 223, + next_entrance = 4, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Calm Lands complete"); + } + } + }, // Normally ends at 2440, but CSR skips from 2420 to 2510 + + { + 2510, + new() { + visit_complete = true, + next_story_progress = 3210, + next_room_id = 223, + next_entrance = 4, + return_to_airship = true, + check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Calm Lands complete"); + } + } + }, // Normally ends at 2440, but CSR skips from 2420 to 2510 + } + } + }, + { RegionEnum.CavernOfTheStolenFayth, new() { story_progress = 2420, room_id = 266, entrance = 0, airship_destination_index = 16 } }, { + RegionEnum.MtGagazet, new() { + story_progress = 2440, room_id = 259, entrance = 0, airship_destination_index = 18, + story_checks = { + { 2680, new() { visit_complete = true, next_story_progress = 3210, next_room_id = 259, next_entrance = 2, return_to_airship = true, check_delegate = (r, client, ffx_interop) => { /* ArchipelagoFFXModule.logger.Info(Mt. Gagazet complete); */ } } }, + } + } + }, { + RegionEnum.ZanarkandRuins, new() { + story_progress = 2680, room_id = 132, entrance = 0, airship_destination_index = 19, + story_checks = { + { 2850, new() { pilgrimage = true } }, + { 2875, new() { visit_complete = true, next_story_progress = 3210, next_room_id = 313, next_entrance = 3, return_to_airship = true, check_delegate = (r, client, ffx_interop) => { /* ArchipelagoFFXModule.logger.Info(Zanarkand Ruins complete); */ } } }, + { 2900, new() { visit_complete = true, next_story_progress = 3210, next_room_id = 313, next_entrance = 3, return_to_airship = true, check_delegate = (r, client, ffx_interop) => { /* ArchipelagoFFXModule.logger.Info(Zanarkand Ruins complete); */ } } }, + } + } + }, { + RegionEnum.Sin, new() { + story_progress = 3125, room_id = 322, entrance = 2, airship_destination_index = 20, + story_checks = { + { + 3400, new() { + visit_complete = true, next_room_id = 322, next_entrance = 2, check_delegate = (r, client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Game Complete"); + foreach (var character in ArchipelagoFFXModule.locked_characters) { + ArchipelagoFFXModule.locked_characters[character.Key] = false; + } + } + } + }, + { 11000, new() { next_story_progress = 3210, next_room_id = 327, next_entrance = 0, check_delegate = (r, client, ffx_interop) => { ffx_interop.call_warp_to_map(382, 0); } } }, + } + } + }, + { RegionEnum.OmegaRuins, new() { story_progress = 3210, room_id = 258, entrance = 2, airship_destination_index = 21 } }, // Story_progress? + { RegionEnum.MonsterArena, new() { story_progress = 3210, room_id = 307, entrance = 0, airship_destination_index = 17 } }, }; public static uint[] airship_destination_addresses = [ @@ -998,25 +1323,32 @@ public unsafe class ArchipelagoRegion { ]; // For battles that don't push/pop but should - public static Dictionary> encounterToPartyDict => new(){ - {"bjyt02_00", [PlySaveId.PC_TIDUS, - PlySaveId.PC_WAKKA, - PlySaveId.PC_RIKKU, - ]}, - {"bjyt02_01", [PlySaveId.PC_TIDUS, - PlySaveId.PC_WAKKA, - PlySaveId.PC_RIKKU, - ]}, - {"lchb07_00", [ // Auron solo - ]}, - {"lchb08_00", [ // Luca post-blitzball sahagins - ]}, + public static Dictionary> encounterToPartyDict => new() { + { + "bjyt02_00", [ + PlySaveId.PC_TIDUS, + PlySaveId.PC_WAKKA, + PlySaveId.PC_RIKKU, + ] + }, { + "bjyt02_01", [ + PlySaveId.PC_TIDUS, + PlySaveId.PC_WAKKA, + PlySaveId.PC_RIKKU, + ] + }, { + "lchb07_00", [ // Auron solo + ] + }, { + "lchb08_00", [ // Luca post-blitzball sahagins + ] + }, }; - public static Dictionary encounterVictoryActions => new() { + public static Dictionary> encounterVictoryActions => new() { // Evrae airship battle //{"hiku15_00", () => { - // ArchipelagoFFXModule.logger.Info("Defeated Evrae. Airship visit 1 complete"); + // /* ArchipelagoFFXModule.logger.Info(Defeated Evrae. Airship visit 1 complete); */ // ArchipelagoFFXModule.region_states[RegionEnum.Airship].story_progress = 2970; // ArchipelagoFFXModule.region_states[RegionEnum.Airship].room_id = 255; // ArchipelagoFFXModule.region_states[RegionEnum.Airship].entrance = 0; @@ -1025,17 +1357,17 @@ public unsafe class ArchipelagoRegion { //}, // Overdrive Sin { - "ssbt03_00", () => { - ArchipelagoFFXModule.logger.Info("Defeated Overdrive Sin. Airship visit 2 complete"); - ArchipelagoFFXModule.region_states[RegionEnum.Airship].story_progress = 3210; - ArchipelagoFFXModule.region_states[RegionEnum.Airship].room_id = 374; - ArchipelagoFFXModule.region_states[RegionEnum.Airship].entrance = 1; - ArchipelagoFFXModule.skip_state_updates = true; + "ssbt03_00", (client, ffx_interop) => { + //ArchipelagoFFXModule.logger.Info("Defeated Overdrive Sin. Airship visit 2 complete"); + ArchipelagoFFXModule.region_states[RegionEnum.Airship].story_progress = 3210; + ArchipelagoFFXModule.region_states[RegionEnum.Airship].room_id = 374; + ArchipelagoFFXModule.region_states[RegionEnum.Airship].entrance = 1; + ArchipelagoFFXModule.skip_state_updates = true; } }, // Yojimbo (Maybe on recruiting Yojimbo instead?) //{"nagi05_10", () => { - // ArchipelagoFFXModule.logger.Info("Defeated Yojimbo. Cavern of the Stolen Fayth visit 1 complete"); + // /* ArchipelagoFFXModule.logger.Info(Defeated Yojimbo. Cavern of the Stolen Fayth visit 1 complete); */ // ArchipelagoFFXModule.region_states[RegionEnum.CavernOfTheStolenFayth].story_progress = 3210; // ArchipelagoFFXModule.region_states[RegionEnum.CavernOfTheStolenFayth].room_id = 56; // ArchipelagoFFXModule.region_states[RegionEnum.CavernOfTheStolenFayth].entrance = 0; @@ -1050,251 +1382,264 @@ public unsafe class ArchipelagoRegion { //} // Bikanel forced Zu fight - {"bika00_10", () => { - lock (FFXArchipelagoClient.client_lock) { - if (FFXArchipelagoClient.is_connected) FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_LOGIC_ZU"] = true; + { + "bika00_10", (client, ffx_interop) => { + lock (client.client_lock) { + if (client.is_connected) client.current_session!.DataStorage[Scope.Slot, "FFX_LOGIC_ZU"] = true; + } } - } }, + }, }; - public static Dictionary encounterEscapeActions => new() { + public static Dictionary> encounterEscapeActions => new() { // Bikanel forced Zu fight - {"bika00_10", () => { - lock (FFXArchipelagoClient.client_lock) { - if (FFXArchipelagoClient.is_connected) FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_LOGIC_ZU"] = true; + { + "bika00_10", (client, ffx_interop) => { + lock (client.client_lock) { + if (client.is_connected) client.current_session!.DataStorage[Scope.Slot, "FFX_LOGIC_ZU"] = true; + } } - } }, - {"mihn02_00", () => { - int boss_id = 8; // Chocobo Eater - if (!FFXArchipelagoClient.local_checked_locations.Contains(boss_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Boss)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(boss_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(boss_id, FFXArchipelagoClient.ArchipelagoLocationType.Boss)) { - ArchipelagoFFXModule.obtain_item(item.id); + }, { + "mihn02_00", (client, ffx_interop) => { + int boss_id = 8; // Chocobo Eater + if (!client.local_checked_locations.Contains(boss_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Boss)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(boss_id, out var item)) { + if (client.sendLocation(boss_id, ArchipelagoClientModule.ArchipelagoLocationType.Boss)) { + ffx_interop.obtain_item(item.id); + } } } } - } }, + }, }; - public static Dictionary encounterToActionDict => new(){ + public static Dictionary> encounterToActionDict => new() { //{"bjyt04_00", ArchipelagoFFXModule.reset_party }, // Klikk (solo Tidus) //{"bjyt04_01", ArchipelagoFFXModule.reset_party }, // Klikk (Tidus + Rikku) // Auron solo - {"lchb07_00", () => ArchipelagoFFXModule.set_party([PlySaveId.PC_AURON], true, false) }, + { "lchb07_00", (client, ffx_interop) => ffx_interop.set_party([ PlySaveId.PC_AURON ], true, false) }, // Yenke and Biran. Can only target Kimahri and scale on his stats. - {"mtgz01_10", () => ArchipelagoFFXModule.set_party([PlySaveId.PC_KIMAHRI], true, true) }, + { "mtgz01_10", (client, ffx_interop) => ffx_interop.set_party([ PlySaveId.PC_KIMAHRI ], true, true) }, // Tutorials // Will softlock without Lulu - {"bsil07_51", () => { - int partyMember_id = 5; // Lulu - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + { + "bsil07_51", (client, ffx_interop) => { + int partyMember_id = 5; // Lulu + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } } } + + ffx_interop.set_party([ PlySaveId.PC_TIDUS, PlySaveId.PC_WAKKA, PlySaveId.PC_LULU ], true, false); } - ArchipelagoFFXModule.set_party([PlySaveId.PC_TIDUS, PlySaveId.PC_WAKKA, PlySaveId.PC_LULU], true, false); - } }, + }, // Yuna is unable to act without an aeon, causing a softlock. - {"bsil05_50", () => { - int partyMember_id = 1; // Yuna - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + { + "bsil05_50", (client, ffx_interop) => { + int partyMember_id = 1; // Yuna + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } } } + + ffx_interop.set_party([ PlySaveId.PC_LULU, PlySaveId.PC_TIDUS, PlySaveId.PC_WAKKA, PlySaveId.PC_YUNA, PlySaveId.PC_VALEFOR ], true, false); } - ArchipelagoFFXModule.set_party([PlySaveId.PC_LULU, PlySaveId.PC_TIDUS, PlySaveId.PC_WAKKA, PlySaveId.PC_YUNA, PlySaveId.PC_VALEFOR], true, false); - } }, + }, // Gui 2 - {"kino03_10", () => { - int partyMember_id = 7; // Seymour - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + { + "kino03_10", (client, ffx_interop) => { + int partyMember_id = 7; // Seymour + if (!client.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { + if (client.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + ffx_interop.obtain_item(item.id); + } } } } - } }, + }, // Tidus only gets 1 turn? - {"klyt00_50", () => ArchipelagoFFXModule.set_party([PlySaveId.PC_TIDUS, PlySaveId.PC_KIMAHRI, PlySaveId.PC_LULU], true, false) }, + { "klyt00_50", (client, ffx_interop) => ffx_interop.set_party([ PlySaveId.PC_TIDUS, PlySaveId.PC_KIMAHRI, PlySaveId.PC_LULU ], true, false) }, // Piercing tutorial. Tidus only gets 1 turn. Enemy only attacks 3rd character? - {"mihn00_50", () => ArchipelagoFFXModule.set_party([PlySaveId.PC_TIDUS, PlySaveId.PC_AURON, PlySaveId.PC_WAKKA], true, false) }, + { "mihn00_50", (client, ffx_interop) => ffx_interop.set_party([ PlySaveId.PC_TIDUS, PlySaveId.PC_AURON, PlySaveId.PC_WAKKA ], true, false) }, // Rikku tutorial - {"genk16_50", () => ArchipelagoFFXModule.set_party([PlySaveId.PC_RIKKU], true, false) }, + { "genk16_50", (client, ffx_interop) => ffx_interop.set_party([ PlySaveId.PC_RIKKU ], true, false) }, // Summon fights // Belgemine - {"genk00_40", () => ArchipelagoFFXModule.set_summon_party()}, - {"kino04_40", () => ArchipelagoFFXModule.set_summon_party()}, - {"lmyt01_00", () => ArchipelagoFFXModule.set_summon_party()}, - {"lmyt01_01", () => ArchipelagoFFXModule.set_summon_party()}, - {"lmyt01_02", () => ArchipelagoFFXModule.set_summon_party()}, - {"lmyt01_03", () => ArchipelagoFFXModule.set_summon_party()}, - {"lmyt01_04", () => ArchipelagoFFXModule.set_summon_party()}, - {"lmyt01_05", () => ArchipelagoFFXModule.set_summon_party()}, - {"lmyt01_06", () => ArchipelagoFFXModule.set_summon_party()}, - {"lmyt01_07", () => ArchipelagoFFXModule.set_summon_party()}, - {"mihn00_60", () => ArchipelagoFFXModule.set_summon_party()}, - {"nagi00_40", () => ArchipelagoFFXModule.set_summon_party()}, - {"zzzz00_250", () => ArchipelagoFFXModule.set_summon_party()}, - {"zzzz02_85", () => ArchipelagoFFXModule.set_summon_party()}, + { "genk00_40", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "kino04_40", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "lmyt01_00", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "lmyt01_01", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "lmyt01_02", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "lmyt01_03", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "lmyt01_04", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "lmyt01_05", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "lmyt01_06", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "lmyt01_07", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "mihn00_60", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "nagi00_40", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "zzzz00_250", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "zzzz02_85", (client, ffx_interop) => ffx_interop.set_summon_party() }, // Isaaru - {"bvyt09_10", () => ArchipelagoFFXModule.set_summon_party()}, - {"bvyt09_11", () => ArchipelagoFFXModule.set_summon_party()}, - {"bvyt09_12", () => ArchipelagoFFXModule.set_summon_party()}, - {"zzzz00_248", () => ArchipelagoFFXModule.set_summon_party()}, + { "bvyt09_10", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "bvyt09_11", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "bvyt09_12", (client, ffx_interop) => ffx_interop.set_summon_party() }, + { "zzzz00_248", (client, ffx_interop) => ffx_interop.set_summon_party() }, // Underwater fights // Luca post-blitzball underwater fight - {"lchb08_00", () => { - ArchipelagoFFXModule.set_party([PlySaveId.PC_TIDUS, PlySaveId.PC_WAKKA]); // Only 2. Third character stays in original spot when battle moves forward - } }, + { + "lchb08_00", (client, ffx_interop) => { + ffx_interop.set_party([ PlySaveId.PC_TIDUS, PlySaveId.PC_WAKKA ]); // Only 2. Third character stays in original spot when battle moves forward + } + }, // Extractor. May not work correctly without Yuna? - {"genk09_00", () => { - ArchipelagoFFXModule.set_party([PlySaveId.PC_TIDUS, PlySaveId.PC_WAKKA, PlySaveId.PC_YUNA, PlySaveId.PC_RIKKU]); - } }, + { "genk09_00", (client, ffx_interop) => { ffx_interop.set_party([ PlySaveId.PC_TIDUS, PlySaveId.PC_WAKKA, PlySaveId.PC_YUNA, PlySaveId.PC_RIKKU ]); } }, // Baaj. Should work with 3 - {"bjyt02_00", () => ArchipelagoFFXModule.set_underwater_party()}, - {"bjyt02_01", () => ArchipelagoFFXModule.set_underwater_party()}, - {"bjyt02_02", () => ArchipelagoFFXModule.set_underwater_party()}, + { "bjyt02_00", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "bjyt02_01", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "bjyt02_02", (client, ffx_interop) => ffx_interop.set_underwater_party() }, // Al Bhed Ship. May only work with 2 - {"cdsp00_00", () => ArchipelagoFFXModule.set_underwater_party()}, - {"cdsp00_01", () => ArchipelagoFFXModule.set_underwater_party()}, - {"cdsp00_02", () => ArchipelagoFFXModule.set_underwater_party()}, - {"cdsp01_00", () => ArchipelagoFFXModule.set_underwater_party()}, - {"cdsp01_01", () => ArchipelagoFFXModule.set_underwater_party()}, - {"cdsp01_02", () => ArchipelagoFFXModule.set_underwater_party()}, // Not confirmed to exist but cdsp01_XX are probably copies of cdsp00_XX - {"cdsp07_00", () => ArchipelagoFFXModule.set_underwater_party()}, - {"cdsp07_01", () => ArchipelagoFFXModule.set_underwater_party()}, + { "cdsp00_00", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "cdsp00_01", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "cdsp00_02", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "cdsp01_00", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "cdsp01_01", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "cdsp01_02", (client, ffx_interop) => ffx_interop.set_underwater_party() }, // Not confirmed to exist but cdsp01_XX are probably copies of cdsp00_XX + { "cdsp07_00", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "cdsp07_01", (client, ffx_interop) => ffx_interop.set_underwater_party() }, // Gagazet. Probably the underwater fights - {"mtgz07_00", () => ArchipelagoFFXModule.set_underwater_party()}, - {"mtgz07_01", () => ArchipelagoFFXModule.set_underwater_party()}, - {"mtgz07_02", () => ArchipelagoFFXModule.set_underwater_party()}, - {"mtgz07_03", () => ArchipelagoFFXModule.set_underwater_party()}, + { "mtgz07_00", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "mtgz07_01", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "mtgz07_02", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "mtgz07_03", (client, ffx_interop) => ffx_interop.set_underwater_party() }, // Via Purifico - {"stbv00_00", () => ArchipelagoFFXModule.set_underwater_party()}, - {"stbv00_01", () => ArchipelagoFFXModule.set_underwater_party()}, - {"stbv00_02", () => ArchipelagoFFXModule.set_underwater_party()}, - {"stbv00_03", () => ArchipelagoFFXModule.set_underwater_party()}, - {"stbv00_04", () => ArchipelagoFFXModule.set_underwater_party()}, - {"stbv00_10", () => ArchipelagoFFXModule.set_underwater_party()}, - {"stbv00_11", () => ArchipelagoFFXModule.set_underwater_party()}, - {"stbv00_12", () => ArchipelagoFFXModule.set_underwater_party()}, + { "stbv00_00", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "stbv00_01", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "stbv00_02", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "stbv00_03", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "stbv00_04", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "stbv00_10", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "stbv00_11", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "stbv00_12", (client, ffx_interop) => ffx_interop.set_underwater_party() }, // Besaid with Wakka - {"bsil03_00", () => ArchipelagoFFXModule.set_underwater_party()}, - {"bsil03_01", () => ArchipelagoFFXModule.set_underwater_party()}, - {"bsil03_02", () => ArchipelagoFFXModule.set_underwater_party()}, - {"bsil03_03", () => ArchipelagoFFXModule.set_underwater_party()}, + { "bsil03_00", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "bsil03_01", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "bsil03_02", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "bsil03_03", (client, ffx_interop) => ffx_interop.set_underwater_party() }, // S.S Liki - {"slik02_01", () => ArchipelagoFFXModule.set_underwater_party()}, + { "slik02_01", (client, ffx_interop) => ffx_interop.set_underwater_party() }, // Monster Arena - {"zzzz00_52", () => ArchipelagoFFXModule.set_underwater_party()}, - {"zzzz00_54", () => ArchipelagoFFXModule.set_underwater_party()}, - {"zzzz00_73", () => ArchipelagoFFXModule.set_underwater_party()}, - {"zzzz02_83", () => ArchipelagoFFXModule.set_underwater_party()}, + { "zzzz00_52", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "zzzz00_54", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "zzzz00_73", (client, ffx_interop) => ffx_interop.set_underwater_party() }, + { "zzzz02_83", (client, ffx_interop) => ffx_interop.set_underwater_party() }, }; - public static Dictionary encounterToLocationDict = new(){ - {"bjyt04_01", [0]}, // Baaj Temple: Klikk Defeated - {"cdsp07_00", [1]}, // Al Bhed Ship: Tros Defeated - {"bsil07_70", [2]}, // Besaid: Dark Valefor - {"slik02_00", [3]}, // S.S. Liki: Sin Fin - {"slik02_01", [4]}, // S.S. Liki: Sinspawn Echuilles - {"klyt00_00", [5]}, // Kilika: Lord Ochu - {"klyt01_00", [6]}, // Kilika: Sinspawn Geneaux - {"cdsp02_00", [7]}, // Luca: Oblitzerator defeated - {"mihn02_00", [8]}, // Mi'Hen Highroad: Chocobo Eater - {"kino02_00", [9]}, // Mushroom Rock Road: Sinspawn Gui 2 - {"kino03_10", [10]}, // Mushroom Rock Road: Sinspawn Gui - {"genk09_00", [12]}, // Moonflow: Extractor - {"kami03_71", [13]}, // Thunder Plains: Dark Ixion - {"mcfr03_00", [14]}, // Macalania Woods: Spherimorph - {"maca02_00", [15]}, // Lake Macalania: Crawler - {"mcyt06_00", [16]}, // Lake Macalania: Seymour/Anima - {"maca02_01", [17]}, // Lake Macalania: Wendigo - {"mcyt00_70", [18]}, // Lake Macalania: Dark Shiva - {"bika03_70", [19]}, // Bikanel: Dark Ifrit - {"hiku15_00", [20]}, // Airship: Evrae - {"ssbt00_00", [21]}, // Airship: Sin Left Fin - {"ssbt01_00", [22]}, // Airship: Sin Right Fin - {"ssbt02_00", [23]}, // Airship: Sinspawn Genais and Core - {"ssbt03_00", [24]}, // Airship: Overdrive Sin - {"hiku15_70", [25]}, // Airship: Penance - {"bvyt09_12", [26]}, // Bevelle: Isaaru (probably?) - {"stbv00_10", [27]}, // Bevelle: Evrae Altana - {"stbv00_11", [27]}, // Bevelle: Evrae Altana - {"stbv00_12", [27]}, // Bevelle: Evrae Altana - {"stbv01_10", [28]}, // Bevelle: Seymour Natus - {"nagi01_00", [29]}, // Calm Lands: Defender X - {"nagi05_74", [31]}, // Cavern of the Stolen Fayth: Dark Yojimbo - {"mtgz01_10", [32]}, // Gagazet (Outside): Biran and Yenke - {"mtgz02_00", [33]}, // Gagazet (Outside): Seymour Flux - {"mtgz01_70", [34]}, // Gagazet (Outside): Dark Anima - {"mtgz08_00", [35]}, // Gagazet: Sanctuary Keeper - {"dome02_00", [36]}, // Zanarkand: Spectral Keeper - {"dome06_00", [37]}, // Zanarkand: Yunalesca - {"dome06_70", [38]}, // Zanarkand: Dark Bahamut - {"sins03_00", [39]}, // Sin: Seymour Omnis - {"sins06_00", [40]}, // Sin: Braska's Final Aeon - {"sins07_0x", [41]}, // Sin: Contest of Aeons - {"sins07_10", [42]}, // Sin: Yu Yevon - {"omeg00_10", [43]}, // Omega Ruins: Ultima Weapon - {"omeg01_10", [44]}, // Omega Ruins: Omega Weapon - {"kino00_70", [45, 46, 47]}, // Dark Mindy, Dark Sandy, Dark Cindy - {"kino01_70", [45, 46, 47]}, // Dark Mindy, Dark Sandy, Dark Cindy - {"kino01_72", [45, 46]}, // Dark Mindy, Dark Sandy - {"kino05_71", [45]}, // Dark Mindy - {"kino05_70", [46]}, // Dark Sandy - {"kino01_71", [47]}, // Dark Cindy - {"bjyt02_02", [48]}, // Geosgaeno - {"zzzz03_00", [49]}, // Stratoavis - {"zzzz03_04", [50]}, // Malboro Menace - {"zzzz03_05", [51]}, // Kottos - {"zzzz03_09", [52]}, // Coeurlregina - {"zzzz03_11", [53]}, // Jormungand - {"zzzz03_14", [54]}, // Cactuar King - {"zzzz03_18", [55]}, // Espada - {"zzzz03_01", [56]}, // Abyss Worm - {"zzzz03_08", [57]}, // Chimerageist - {"zzzz03_17", [58]}, // Don Tonberry - {"zzzz03_07", [59]}, // Catoblepas - {"zzzz03_12", [60]}, // Abaddon - {"zzzz03_15", [61]}, // Vorban - {"zzzz02_94", [62]}, // Fenrir - {"zzzz02_96", [63]}, // Ornitholestes - {"zzzz02_97", [64]}, // Pteryx - {"zzzz02_98", [65]}, // Hornet - {"zzzz02_93", [66]}, // Vidatu - {"zzzz02_99", [67]}, // One-Eye - {"zzzz02_95", [68]}, // Jumbo Flan - {"zzzz03_06", [69]}, // Nega Elemental - {"zzzz02_92", [70]}, // Tanket - {"zzzz03_03", [71]}, // Fafnir - {"zzzz03_16", [72]}, // Sleep Sprout - {"zzzz03_13", [73]}, // Bomb King - {"zzzz03_02", [74]}, // Juggernaut - {"zzzz03_10", [75]}, // Ironclad - {"zzzz02_79", [76]}, // Earth Eater - {"zzzz02_81", [77]}, // Greater Sphere - {"zzzz02_77", [78]}, // Catastrophe - {"zzzz02_82", [79]}, // Th'uban - {"zzzz00_105", [80]}, // Neslug - {"zzzz02_80", [81]}, // Ultima Buster - {"zzzz02_83", [82]}, // Shinryu - {"zzzz02_76", [83]}, // Monster Arena: Nemesis + public static Dictionary encounterToLocationDict = new() { + { "bjyt04_01", [ 0 ] }, // Baaj Temple: Klikk Defeated + { "cdsp07_00", [ 1 ] }, // Al Bhed Ship: Tros Defeated + { "bsil07_70", [ 2 ] }, // Besaid: Dark Valefor + { "slik02_00", [ 3 ] }, // S.S. Liki: Sin Fin + { "slik02_01", [ 4 ] }, // S.S. Liki: Sinspawn Echuilles + { "klyt00_00", [ 5 ] }, // Kilika: Lord Ochu + { "klyt01_00", [ 6 ] }, // Kilika: Sinspawn Geneaux + { "cdsp02_00", [ 7 ] }, // Luca: Oblitzerator defeated + { "mihn02_00", [ 8 ] }, // Mi'Hen Highroad: Chocobo Eater + { "kino02_00", [ 9 ] }, // Mushroom Rock Road: Sinspawn Gui 2 + { "kino03_10", [ 10 ] }, // Mushroom Rock Road: Sinspawn Gui + { "genk09_00", [ 12 ] }, // Moonflow: Extractor + { "kami03_71", [ 13 ] }, // Thunder Plains: Dark Ixion + { "mcfr03_00", [ 14 ] }, // Macalania Woods: Spherimorph + { "maca02_00", [ 15 ] }, // Lake Macalania: Crawler + { "mcyt06_00", [ 16 ] }, // Lake Macalania: Seymour/Anima + { "maca02_01", [ 17 ] }, // Lake Macalania: Wendigo + { "mcyt00_70", [ 18 ] }, // Lake Macalania: Dark Shiva + { "bika03_70", [ 19 ] }, // Bikanel: Dark Ifrit + { "hiku15_00", [ 20 ] }, // Airship: Evrae + { "ssbt00_00", [ 21 ] }, // Airship: Sin Left Fin + { "ssbt01_00", [ 22 ] }, // Airship: Sin Right Fin + { "ssbt02_00", [ 23 ] }, // Airship: Sinspawn Genais and Core + { "ssbt03_00", [ 24 ] }, // Airship: Overdrive Sin + { "hiku15_70", [ 25 ] }, // Airship: Penance + { "bvyt09_12", [ 26 ] }, // Bevelle: Isaaru (probably?) + { "stbv00_10", [ 27 ] }, // Bevelle: Evrae Altana + { "stbv00_11", [ 27 ] }, // Bevelle: Evrae Altana + { "stbv00_12", [ 27 ] }, // Bevelle: Evrae Altana + { "stbv01_10", [ 28 ] }, // Bevelle: Seymour Natus + { "nagi01_00", [ 29 ] }, // Calm Lands: Defender X + { "nagi05_74", [ 31 ] }, // Cavern of the Stolen Fayth: Dark Yojimbo + { "mtgz01_10", [ 32 ] }, // Gagazet (Outside): Biran and Yenke + { "mtgz02_00", [ 33 ] }, // Gagazet (Outside): Seymour Flux + { "mtgz01_70", [ 34 ] }, // Gagazet (Outside): Dark Anima + { "mtgz08_00", [ 35 ] }, // Gagazet: Sanctuary Keeper + { "dome02_00", [ 36 ] }, // Zanarkand: Spectral Keeper + { "dome06_00", [ 37 ] }, // Zanarkand: Yunalesca + { "dome06_70", [ 38 ] }, // Zanarkand: Dark Bahamut + { "sins03_00", [ 39 ] }, // Sin: Seymour Omnis + { "sins06_00", [ 40 ] }, // Sin: Braska's Final Aeon + { "sins07_0x", [ 41 ] }, // Sin: Contest of Aeons + { "sins07_10", [ 42 ] }, // Sin: Yu Yevon + { "omeg00_10", [ 43 ] }, // Omega Ruins: Ultima Weapon + { "omeg01_10", [ 44 ] }, // Omega Ruins: Omega Weapon + { "kino00_70", [ 45, 46, 47 ] }, // Dark Mindy, Dark Sandy, Dark Cindy + { "kino01_70", [ 45, 46, 47 ] }, // Dark Mindy, Dark Sandy, Dark Cindy + { "kino01_72", [ 45, 46 ] }, // Dark Mindy, Dark Sandy + { "kino05_71", [ 45 ] }, // Dark Mindy + { "kino05_70", [ 46 ] }, // Dark Sandy + { "kino01_71", [ 47 ] }, // Dark Cindy + { "bjyt02_02", [ 48 ] }, // Geosgaeno + { "zzzz03_00", [ 49 ] }, // Stratoavis + { "zzzz03_04", [ 50 ] }, // Malboro Menace + { "zzzz03_05", [ 51 ] }, // Kottos + { "zzzz03_09", [ 52 ] }, // Coeurlregina + { "zzzz03_11", [ 53 ] }, // Jormungand + { "zzzz03_14", [ 54 ] }, // Cactuar King + { "zzzz03_18", [ 55 ] }, // Espada + { "zzzz03_01", [ 56 ] }, // Abyss Worm + { "zzzz03_08", [ 57 ] }, // Chimerageist + { "zzzz03_17", [ 58 ] }, // Don Tonberry + { "zzzz03_07", [ 59 ] }, // Catoblepas + { "zzzz03_12", [ 60 ] }, // Abaddon + { "zzzz03_15", [ 61 ] }, // Vorban + { "zzzz02_94", [ 62 ] }, // Fenrir + { "zzzz02_96", [ 63 ] }, // Ornitholestes + { "zzzz02_97", [ 64 ] }, // Pteryx + { "zzzz02_98", [ 65 ] }, // Hornet + { "zzzz02_93", [ 66 ] }, // Vidatu + { "zzzz02_99", [ 67 ] }, // One-Eye + { "zzzz02_95", [ 68 ] }, // Jumbo Flan + { "zzzz03_06", [ 69 ] }, // Nega Elemental + { "zzzz02_92", [ 70 ] }, // Tanket + { "zzzz03_03", [ 71 ] }, // Fafnir + { "zzzz03_16", [ 72 ] }, // Sleep Sprout + { "zzzz03_13", [ 73 ] }, // Bomb King + { "zzzz03_02", [ 74 ] }, // Juggernaut + { "zzzz03_10", [ 75 ] }, // Ironclad + { "zzzz02_79", [ 76 ] }, // Earth Eater + { "zzzz02_81", [ 77 ] }, // Greater Sphere + { "zzzz02_77", [ 78 ] }, // Catastrophe + { "zzzz02_82", [ 79 ] }, // Th'uban + { "zzzz00_105", [ 80 ] }, // Neslug + { "zzzz02_80", [ 81 ] }, // Ultima Buster + { "zzzz02_83", [ 82 ] }, // Shinryu + { "zzzz02_76", [ 83 ] }, // Monster Arena: Nemesis //{"kino00_70", 45}, {"kino01_70", 45}, {"kino01_72", 45}, {"kino05_71", 45}, // Dark Mindy @@ -1315,7 +1660,7 @@ public unsafe class ArchipelagoRegion { 0x3172248B, // ffx_us_voice20: "Sometimes, when I got a lot on my mind" 0x4BC8C5CB, // ffx_us_voice_btl: "Who did that!?" 0x57EA548B, // ffx_us_voice_btl: "Guardians should fight, not think." + Rikku response - ]; + ]; public static string[] other_item_names = [ // Gear Customizations (0 - 7C) @@ -1522,35 +1867,34 @@ public unsafe class ArchipelagoRegion { "Aeon Customization: LCK +1: 1x Fortune Sphere", "Aeon Customization: EVA +1: 1x Speed Sphere", "Aeon Customization: ACC +1: 1x Speed Sphere", - ]; + ]; - public static Dictionary overdrive_names = new Dictionary() - { - {PlayerCommandId.PCOM_SPIRAL_CUT, "Swordplay: Spiral Cut" }, - {PlayerCommandId.PCOM_SLICE_AND_DICE, "Swordplay: Slice & Dice" }, - {PlayerCommandId.PCOM_ENERGY_RAIN, "Swordplay: Energy Rain" }, - {PlayerCommandId.PCOM_BLITZ_ACE, "Swordplay: Blitz Ace" }, - {PlayerCommandId.PCOM_SHOOTING_STAR, "Bushido: Shooting Star" }, - {PlayerCommandId.PCOM_DRAGON_FANG, "Bushido: Dragon Fang" }, - {PlayerCommandId.PCOM_BANISHING_BLADE, "Bushido: Banishing Blade" }, - {PlayerCommandId.PCOM_TORNADO, "Bushido: Tornado" }, - {PlayerCommandId.PCOM_JUMP, "Ronso Rage: Jump" }, - {PlayerCommandId.PCOM_FIRE_BREATH, "Ronso Rage: Fire Breath" }, - {PlayerCommandId.PCOM_SEED_CANNON, "Ronso Rage: Seed Cannon" }, - {PlayerCommandId.PCOM_SELF_DESTRUCT, "Ronso Rage: Self-Destruct" }, - {PlayerCommandId.PCOM_THRUST_KICK, "Ronso Rage: Thrust Kick" }, - {PlayerCommandId.PCOM_STONE_BREATH, "Ronso Rage: Stone Breath" }, - {PlayerCommandId.PCOM_AQUA_BREATH, "Ronso Rage: Aqua Breath" }, - {PlayerCommandId.PCOM_DOOM, "Ronso Rage: Doom" }, - {PlayerCommandId.PCOM_WHITE_WIND, "Ronso Rage: White Wind" }, - {PlayerCommandId.PCOM_BAD_BREATH, "Ronso Rage: Bad Breath" }, - {PlayerCommandId.PCOM_MIGHTY_GUARD, "Ronso Rage: Might Guard" }, - {PlayerCommandId.PCOM_NOVA, "Ronso Rage: Nova" }, - {PlayerCommandId.PCOM_ELEMENT_REELS, "Slots: Element Reels" }, - {PlayerCommandId.PCOM_ATTACK_REELS, "Slots: Attack Reels" }, - {PlayerCommandId.PCOM_STATUS_REELS, "Slots: Status Reels" }, - {PlayerCommandId.PCOM_AUROCHS_REELS, "Slots: Aurochs Reels" }, - {PlayerCommandId.PCOM_REQUIEM, "Overdrive: Requiem" }, - {PlayerCommandId.PCOM_ENERGY_BLAST, "Overdrive: Energy Blast" }, + public static Dictionary overdrive_names = new Dictionary() { + { PlayerCommandId.PCOM_SPIRAL_CUT, "Swordplay: Spiral Cut" }, + { PlayerCommandId.PCOM_SLICE_AND_DICE, "Swordplay: Slice & Dice" }, + { PlayerCommandId.PCOM_ENERGY_RAIN, "Swordplay: Energy Rain" }, + { PlayerCommandId.PCOM_BLITZ_ACE, "Swordplay: Blitz Ace" }, + { PlayerCommandId.PCOM_SHOOTING_STAR, "Bushido: Shooting Star" }, + { PlayerCommandId.PCOM_DRAGON_FANG, "Bushido: Dragon Fang" }, + { PlayerCommandId.PCOM_BANISHING_BLADE, "Bushido: Banishing Blade" }, + { PlayerCommandId.PCOM_TORNADO, "Bushido: Tornado" }, + { PlayerCommandId.PCOM_JUMP, "Ronso Rage: Jump" }, + { PlayerCommandId.PCOM_FIRE_BREATH, "Ronso Rage: Fire Breath" }, + { PlayerCommandId.PCOM_SEED_CANNON, "Ronso Rage: Seed Cannon" }, + { PlayerCommandId.PCOM_SELF_DESTRUCT, "Ronso Rage: Self-Destruct" }, + { PlayerCommandId.PCOM_THRUST_KICK, "Ronso Rage: Thrust Kick" }, + { PlayerCommandId.PCOM_STONE_BREATH, "Ronso Rage: Stone Breath" }, + { PlayerCommandId.PCOM_AQUA_BREATH, "Ronso Rage: Aqua Breath" }, + { PlayerCommandId.PCOM_DOOM, "Ronso Rage: Doom" }, + { PlayerCommandId.PCOM_WHITE_WIND, "Ronso Rage: White Wind" }, + { PlayerCommandId.PCOM_BAD_BREATH, "Ronso Rage: Bad Breath" }, + { PlayerCommandId.PCOM_MIGHTY_GUARD, "Ronso Rage: Might Guard" }, + { PlayerCommandId.PCOM_NOVA, "Ronso Rage: Nova" }, + { PlayerCommandId.PCOM_ELEMENT_REELS, "Slots: Element Reels" }, + { PlayerCommandId.PCOM_ATTACK_REELS, "Slots: Attack Reels" }, + { PlayerCommandId.PCOM_STATUS_REELS, "Slots: Status Reels" }, + { PlayerCommandId.PCOM_AUROCHS_REELS, "Slots: Aurochs Reels" }, + { PlayerCommandId.PCOM_REQUIEM, "Overdrive: Requiem" }, + { PlayerCommandId.PCOM_ENERGY_BLAST, "Overdrive: Energy Blast" }, }; } diff --git a/src/delegates/capture_delegates.cs b/src/delegates/capture_delegates.cs deleted file mode 100644 index 71cab5a..0000000 --- a/src/delegates/capture_delegates.cs +++ /dev/null @@ -1,142 +0,0 @@ -using Fahrenheit.FFX; -using Fahrenheit.FFX.Battle; -using System.Runtime.InteropServices; - -using Fahrenheit; - -using static ArchipelagoFFX.delegates; - -namespace ArchipelagoFFX; - -public unsafe partial class CaptureModule : FhModule { - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate bool MsMonsterCapture(int target_id, int arena_idx); - private const nint __addr_MsMonsterCapture = 0x390B80; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void FUN_00783bb0(byte mon_idx); - private const int __addr_FUN_00783bb0 = 0x383BB0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate Chr* MsGetMon(byte mon_idx); - private const int __addr_MsGetMon = 0x00395AB0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void AtelEventSetUp(int event_id); - private const nint __addr_AtelEventSetUp = 0x472E90; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate char* AtelGetEventName(uint event_id); - private const nint __addr_AtelGetEventName = 0x4796E0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsDamageCheckDeath(int attacker_id, int target_id, int param_3, uint param_4); - private const nint __addr_MsDamageCheckDeath = 0x38C800; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate Chr* MsGetChr(uint chr_id); - private const nint __addr_MsGetChr = 0x394030; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void MsSetSaveParam(uint chr_id); - public const nint __addr_MsSetSaveParam = 0x3861B0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void MsSetRamChrParam(uint chr_id); - public const nint __addr_MsSetRamChrParam = 0x39C610; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void MsCalcCommand(AttackCue* param_1, int param_2); - public const nint __addr_MsCalcCommand = 0x3893A0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate Command* MsGetCommand(int chr_id, int unused, int quit_on_idx, AttackCommandInfo* param_4, uint* param_5); - public const nint __addr_MsGetCommand = 0x38CF10; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate uint FUN_0078d100(Chr* chr); - public const nint __addr_FUN_0078d100 = 0x38D100; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate uint FUN_0078bb30(int param_1, byte* param_2, byte* param_3, Command* param_4, uint param_5, uint* param_6, int* param_7); - public const nint __addr_FUN_0078bb30 = 0x38BB30; - - private const nint __addr_ret_hasKeyItem = 0x45B7A0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int MsBattleEncountExe(int field_id, int group_idx, float walked_delta); - public const nint __addr_MsBattleEncountExe = 0x380de0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int MsBtlListFieldNum(int field_id); - public const nint __addr_MsBtlListFieldNum = 0x39d1e0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void ResetEncountExe(int p1); - public const nint __addr_ResetEncountExe = 0x3810c0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int brnd(int rng_slot); - public const nint __addr_brnd = 0x398900; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate BtlBinField* MsBtlListField(int field_idx); - private const nint __addr_MsBtlListField = 0x39d1b0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate BtlBinEncounter* MsBtlListEncount(int field_idx); - private const nint __addr_MsBtlListEncount = 0x39d190; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate BtlBinGroup* MsBtlListGroup(int field_idx, int group_idx); - private const nint __addr_MsBtlListGroup = 0x39d230; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void Sg_FadeInW(int p1); - public const nint __addr_Sg_FadeInW = 0x42cc20; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void* sceOpen(byte* p1, int p2); - public const nint __addr_sceOpen = 0x22fbe0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int sceLseek(void* p1, int p2, int p3); - public const nint __addr_sceLseek = 0x22fa90; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int sceRead(void* p1, void* dst, int amount); - public const nint __addr_sceRead = 0x22fdb0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int sceClose(void* p1); - public const nint __addr_sceClose = 0x22f7c0; - - // Method Handles - private readonly FhMethodHandle _MsMonsterCapture; - private readonly FhMethodHandle _FUN_00783bb0; - private readonly FhMethodHandle _AtelEventSetUp; - private readonly FhMethodHandle _ret_hasKeyItem; - private readonly FhMethodHandle _MsDamageCheckDeath; - private readonly FhMethodHandle _MsSetSaveParam; - private readonly FhMethodHandle _MsSetRamChrParam; - private readonly FhMethodHandle _MsCalcCommand; - private readonly FhMethodHandle _MsBattleEncountExe; - - private static char* get_event_name(uint event_id) => FhUtil.get_fptr(__addr_AtelGetEventName)(event_id); - private readonly MsGetMon _MsGetMon = FhUtil.get_fptr(__addr_MsGetMon); - private readonly MsGetChr _MsGetChr = FhUtil.get_fptr(__addr_MsGetChr); - private readonly MsGetCommand _MsGetCommand = FhUtil.get_fptr(__addr_MsGetCommand); - private readonly FUN_0078d100 _FUN_0078d100 = FhUtil.get_fptr(__addr_FUN_0078d100); - private readonly FUN_0078bb30 _FUN_0078bb30 = FhUtil.get_fptr(__addr_FUN_0078bb30); - private readonly MsBtlListFieldNum _MsBtlListFieldNum = FhUtil.get_fptr(__addr_MsBtlListFieldNum); - private readonly ResetEncountExe _ResetEncountExe = FhUtil.get_fptr(__addr_ResetEncountExe); - private readonly brnd _brnd = FhUtil.get_fptr(__addr_brnd); - private readonly MsBtlListField _MsBtlListField = FhUtil.get_fptr(__addr_MsBtlListField); - private readonly MsBtlListEncount _MsBtlListEncount = FhUtil.get_fptr(__addr_MsBtlListEncount); - private readonly MsBtlListGroup _MsBtlListGroup = FhUtil.get_fptr(__addr_MsBtlListGroup); - private readonly Sg_FadeInW _Sg_FadeInW = FhUtil.get_fptr(__addr_Sg_FadeInW); - private readonly sceOpen _sceOpen = FhUtil.get_fptr(__addr_sceOpen); - private readonly sceLseek _sceLseek = FhUtil.get_fptr(__addr_sceLseek); - private readonly sceRead _sceRead = FhUtil.get_fptr(__addr_sceRead); - private readonly sceClose _sceClose = FhUtil.get_fptr(__addr_sceClose); -} diff --git a/src/delegates/deathlink_delegates.cs b/src/delegates/deathlink_delegates.cs deleted file mode 100644 index d8c6164..0000000 --- a/src/delegates/deathlink_delegates.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Runtime.InteropServices; - -using Fahrenheit; -using Fahrenheit.FFX.Battle; - -using static ArchipelagoFFX.delegates; - -namespace ArchipelagoFFX; - -public unsafe partial class DeathLinkModule { - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_0079b480(int chr_id, int com_id, int is_disabled); - public const nint __addr_FUN_0079b480 = 0x39b480; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate Chr* MsGetChr(int chr_id); - public const nint __addr_MsGetChr = 0x394030; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate uint MsGetBattleEndStatus(); - public const nint __addr_MsGetBattleEndStatus = 0x3928f0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void MsBtlReadManage(); - public const nint __addr_MsBtlReadManage = 0x3830d0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int MsDamageCheckDeath(int attacker_id, int target_id, int p3, int targetting_self); - public const nint __addr_MsDamageCheckDeath = 0x38c800; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int MsMessageCueRegist(MessageCueType type, int arg1, int arg2, byte p4, byte p5); - public const nint __addr_MsMessageCueRegist = 0x39cff0; - - // Method Handles - private FhMethodHandle _MsGetBattleEndStatus; - private FhMethodHandle _MsBtlReadManage; - private FhMethodHandle _MsDamageCheckDeath; - - // Function library - private FUN_0079b480 _set_command_disabled = FhUtil.get_fptr(__addr_FUN_0079b480); - private MsGetChr _MsGetChr = FhUtil.get_fptr(__addr_MsGetChr); - private MsMessageCueRegist _MsMessageCueRegist = FhUtil.get_fptr(__addr_MsMessageCueRegist); -} diff --git a/src/delegates/delegates.cs b/src/delegates/delegates.cs deleted file mode 100644 index 0e7f09d..0000000 --- a/src/delegates/delegates.cs +++ /dev/null @@ -1,721 +0,0 @@ -using Fahrenheit.Atel; -using Fahrenheit.FFX; -using Fahrenheit.FFX.Battle; -using System.Numerics; -using System.Runtime.InteropServices; - -namespace ArchipelagoFFX; -public static unsafe class delegates { - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void AtelInitTotal(); - public const nint __addr_AtelInitTotal = 0x0046d660; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void AtelSetUpCallFunc(int nameSpaceId, nint nameSpacePtr); - public const nint __addr_AtelSetUpCallFunc = 0x00477800; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int CT_Exec (AtelBasicWorker* work, AtelStack* atelStack); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int CT_RetInt (AtelBasicWorker* work, int* storage, AtelStack* atelStack); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate float CT_RetFloat(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate char* AtelGetEventName(uint event_id); - - // AtelStackPop - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int AtelStackPop(int* param_1, AtelStack* atelStack); - - // Common.obtainTreasureInit - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void Common_obtainTreasureInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_obtainTreasureInit = 0x0045a740; - - // Common.obtainTreasureSilentlyInit - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void Common_obtainTreasureSilentlyInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_obtainTreasureSilentlyInit = 0x004579e0; - - // Common.obtainBrotherhood - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_obtainBrotherhoodRetInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_obtainBrotherhoodRetInt = 0x00459a40; - - // Common.grantCelestialUpgrade - //[UnmanagedFunctionPointer(CallingConvention.Cdecl)] - //public delegate int Common_grantCelestialUpgrade(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int TkSetLegendAbility(int chr_id, int level); - public const nint __addr_TkSetLegendAbility = 0x004c3150; - - // Common.setPrimerCollected - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_setPrimerCollected(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_setPrimerCollected = 0x0045ab30; - - // Common.transitionToMap - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_transitionToMap(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_transitionToMap = 0x004580c0; - - // Common.warpToMap - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_warpToMap(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_warpToMap = 0x00458370; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void SgEvent_showModularMenuInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_SgEvent_showModularMenuInit = 0x00678210; - - - // Common.playFieldVoiceLineInit - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_playFieldVoiceLineInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_playFieldVoiceLineInit = 0x0045cb70; - // Common.playFieldVoiceLineExec - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_playFieldVoiceLineExec(AtelBasicWorker* param_1, AtelStack* param_2); - public const nint __addr_Common_playFieldVoiceLineExec = 0x0045cd30; - // Common.playFieldVoiceLineResultInt - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_playFieldVoiceLineResultInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_playFieldVoiceLineResultInt = 0x0045d150; - - - // Common.00D6Init - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_00D6Init(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_00D6Init = 0x0045d520; - // Common.00D6eExec - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_00D6Exec(AtelBasicWorker* param_1, AtelStack* param_2); - public const nint __addr_Common_00D6Exec = 0x0045d820; - // Common.00D6ResultInt - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_00D6ResultInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_00D6ResultInt = 0x0045dcf0; - - // Map.show2DLayer - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Map_show2DLayerResultInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Map_show2DLayerResultInt = 0x0051b1a0; - - // Map.hide2DLayer - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Map_hide2DLayerResultInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Map_hide2DLayerResultInt = 0x0051b1e0; - - // Common.01D1Init - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_01D1Init(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - public const nint __addr_Common_01D1Init = 0x0045fb60; - // Common.01D1Exec - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate bool Common_01D1Exec(AtelBasicWorker* param_1, AtelStack* param_2); - public const nint __addr_Common_01D1Exec = 0x0045fdb0; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_addPartyMember(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_removePartyMember(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_removePartyMemberLongTerm(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - // Common.setWeaponVisibilty (Common.0240) - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_setWeaponInvisible(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - - // Common.putPartyMemberInSlot - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_putPartyMemberInSlot(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - - - // Common.pushParty - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_pushParty(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - - // Common.popParty - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_popParty(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int MsBattleLabelExe(uint encounter_id, byte param_2, byte screen_transition); - public const nint __addr_MsBattleLabelExe = 0x00381d60; - - // EndOfBattle? - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate void FUN_00791820(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int MsBtlGetPos(int param_1, Chr* chr, int btl_pos_a, int btl_pos_b, int btl_pos_c, Vector4* out_pos); - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate byte MsBtlReadSetScene(); - - - // giveItem - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate uint FUN_007905a0(uint param_1, int param_2); - - - // readFromBin - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate byte* FUN_007ab890(int param_1, short* param_2, int param_3); - - // getWeaponName - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate ushort FUN_007a0d10(Equipment* param_1); - // getWeaponModel - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_007a0c70(ushort name_id, byte owner, int unknown, ushort* model_id_pointer); - // giveWeapon - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int FUN_007ab930(Equipment* param_1); - // obtainTreasureCleanup - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_007993f0(BtlRewardData* param_1, int param_2); - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_00a48910(uint chr_id, int node_idx); - - - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public delegate bool openFile(nint _this, nint filename, bool readOnly, nint unknown_1, nint unknown_2, nint unknown_3); - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public delegate uint readFile(nint _this, nint buffer, uint max_len); - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public delegate uint FUN_0070aec0(nint _this, uint voice_id, uint param_2); - - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_loadModel(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_linkFieldToBattleActor(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_0043(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - - - - - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Map_800F(AtelBasicWorker* work, int* storage, AtelStack* atelStack); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate byte* FUN_0086bec0(int param_1); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate short FUN_0086bea0(int param_1); - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate void FUN_00656c90(int param_1, int param_2, char* fileName); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate bool graphicInitFMVPlayer(int movie_id, int param_2); - public const nint __addr_graphicInitFMVPlayer = 0x00241840; - - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public delegate int PhyreScene_loadVFXTexture(nint phyreScene, int param_1, byte* param_2, char param_3); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void PhyreScene_onVFXTextureLoaded(nint param_1, int* param_2); - - public struct returnedTexData { - public short unknown1; - public short type; - public nint dataName; - public short offset; - public short size; - public nint unknown2; - } - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public delegate returnedTexData* FUN_0056cd50(nint _this, nint dataName); - - public struct FixedClusterData { - public nint _0x00; // Texture data offsets? - public nint _0x04; // Texture data? - public nint _0x08; - public nint _0x0c; - public nint _0x10; - public nint _0x14; - public nint _0x18; - public nint _0x1c; - } - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public delegate void FUN_0065ee30(FixedClusterData* param_1); - public const nint __addr_ClusterManager_FUN_0065ee30 = 0x0025ee30; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Phyre_PFramework_PApplication_FixupClusters(PCluster* cluster, int param_1); - public const nint __addr_Phyre_PFramework_PApplication_FixupClusters = 0x00223740; - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public delegate PCluster* ClusterManager_loadPCluster(nint _this, nint filePath); - public const nint __addr_ClusterManager_loadPCluster = 0x0029ba80; - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public delegate void ClusterManager_releasePCluster(nint _this, PCluster* cluster); - public const nint __addr_ClusterManager_releasePCluster = 0x0029bef0; - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public delegate PCluster* ClusterManager_getPClusterByName(nint _this, nint filePath); - public const nint __addr_ClusterManager_getPClusterByName = 0x0029b5f0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void fiosUnifyFilename(nint in_string, nint out_buffer, int buffer_size); - public const nint __addr_fiosUnifyFilename = 0x002799d0; - - - [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 0x20)] - public struct PCluster { - } - - - - - - - - - - [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 0x2c)] - public struct TOMesWinWork { - [FieldOffset(0x08)] public byte* text; - [FieldOffset(0x0c)] public byte* _0xc; - [FieldOffset(0x14)] public short status; - - [FieldOffset(0x16)] public short _0x16; - - [FieldOffset(0x18)] public int _0x18; - [FieldOffset(0x1d)] public byte _0x1d; - [FieldOffset(0x20)] public byte _0x20; - - } - - // obbtainTreasure related - public delegate void FUN_008b8910(int window_idx, int variable_idx, int type); // setMessageWindowVariableType (0: text*, 1: int) - public const nint __addr_FUN_008b8910 = 0x004b8910; - - public delegate byte* FUN_008bda20(uint window_idx); // getMenuText - public const nint __addr_FUN_008bda20 = 0x004bda20; - - public delegate void FUN_008b8930(int window_idx, int variable_idx, int value); // setMessageWindowVariable - public const nint __addr_FUN_008b8930 = 0x004b8930; - - public delegate void FUN_0086a0c0(); - public const nint __addr_FUN_0086a0c0 = 0x0046a0c0; - - public delegate TOMesWinWork* AtelGetMesWinWork(int idx); - public const nint __addr_AtelGetMesWinWork = 0x0046be20; - - - // Voice related - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public unsafe delegate int FmodVoice_dataChange(nint FmodVoice, int event_id, nint param_2); - public const nint __addr_FmodVoice_dataChange = 0x0030a720; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public unsafe delegate nint FMOD_EventSystem_load(nint param_1, nint file_path, nint param_3, nint bank); - public const nint __addr_FMOD_EventSystem_load = 0x70C75C; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public unsafe delegate nint FMOD_Bank_Post_Load(nint param_1, nint param_2, nint param_3, nint param_4); - - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public unsafe delegate void FfxFmod_soundInit_setLang(nint ffxFmod, int lang); - public const nint __addr_FfxFmod_soundInit_setLang = 0x0030b4e0; - - - [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 0x1C)] - public struct FFXLocalizationManager { - [FieldOffset(0x00)] public int video; // Also voice? - [FieldOffset(0x04)] public int text; // Probably - [FieldOffset(0x08)] public int voice; // Unused? - } - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public unsafe delegate void LocalizationManager_Initialize(FFXLocalizationManager* localizationManager); - public const nint __addr_LocalizationManager_Initialize = 0x002db1c0; - - public unsafe delegate FFXLocalizationManager* LocalizationManager_GetInstance(); - public const nint __addr_LocalizationManager_GetInstance = 0x002db1a0; - - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public unsafe delegate void FfxFmod_soundInit(nint ffxFmod); - public const nint __addr_FfxFmod_soundInit = 0x00307170; - - [UnmanagedFunctionPointer(CallingConvention.ThisCall)] - public unsafe delegate void FmodVoice_initList(nint fmodVoice); - public const nint __addr_FmodVoice_initList = 0x0030ac80; - - // Set soundtrack type (0 = arranged, 1 = original) - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void FUN_008cc120(int param_1); - public const nint __addr_FUN_008cc120 = 0x004cc120; - - - - - // Temporary - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void AtelEventSetUp(int event_id); - public const nint __addr_AtelEventSetUp = 0x472E90; - - // getCurrentPartySlots - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void MsGetSavePartyMember(uint* param_1, uint* param_2, uint* param_3); - public const nint __addr_MsGetSavePartyMember = 0x3853B0; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int CT_RetInt_01B6(nint work, int* storage, nint atelStack); - public static int __addr_CT_RetInt_01B6 = 0x004594d0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int Common_upgradeBrotherhoodRetInt(nint work, int* storage, nint atelStack); - public static int __addr_CT_RetInt_01B7 = 0x004596a0; - - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate void eiAbmParaGet(); - public static int __addr_eiAbmParaGet = 0x00654860; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate uint MsApUp(int chr_id, Chr* chr, int base_ap_add, uint param_4); - public const nint __addr_MsApUp = 0x00398A10; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void TkMsImportantSet(uint param_1); - public const nint __addr_TkMsImportantSet = 0x0048e700; - - - public delegate void MsFieldItemGet(int treasure_id); - public const nint __addr_MsFieldItemGet = 0x00398fe0; - - public delegate void CT_RetInt_0065(nint work, int* storage, nint atelStack); - public const nint __addr_CT_RetInt_0065 = 0x00457f60; - - public delegate void CT_RetInt_006A(nint work, int* storage, nint atelStack); - public const nint __addr_CT_RetInt_006A = 0x004589f0; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate nint AtelGetCurCtrlWork(); - public const nint __addr_AtelGetCurCtrlWork = 0x46AF80; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate int MsPayGIL(int change); - public const nint __addr_MsPayGIL = 0x385A60; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void SndSepPlaySimple(uint param_1); - public const nint __addr_SndSepPlaySimple = 0x486DE0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate Equipment* MsGetSaveWeapon(uint gear_inv_idx, nint ref_name); - public const nint __addr_MsGetSaveWeapon = 0x3ABBF0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void MsSetSaveParam(uint chr_id); - public const nint __addr_MsSetSaveParam = 0x3861B0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void MsSetRamChrParam(uint chr_id); - public const nint __addr_MsSetRamChrParam = 0x39c610; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void MsBattleExe(uint param_1, int field_idx, int group_idx, int formation_idx); - public const nint __addr_MsBattleExe = 0x3810F0; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void TkMsGetRomItem(uint param_1, int* param_2); - public const nint __addr_TkMsGetRomItem = 0x4AB230; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void MsSaveItemUse(uint item_id, int amount); - public const nint __addr_MsSaveItemUse = 0x3905A0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate byte* MsImportantName(uint key_item_idx); - public const nint __addr_MsImportantName = 0x3908B0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate nint MsBtlListGroup(int field_idx, int group_idx); - public const nint __addr_MsBtlListGroup = 0x39D230; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate nint MsGetExcelData(int req_elem_idx, nint excel_data_ptr, int* ref_data_end); - public const nint __addr_MsGetExcelData = 0x3AB890; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public unsafe delegate void TkMenuAppearMainCmdWindow(int param_1, int param_2); - public static int __addr_TkMenuAppearMainCmdWindow = 0x004e1c60; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int UpgradeBrotherhood(int level); - public static int __addr_UpgradeBrotherhood = 0x004596a0; - - // Initializes monster data pointers - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate Chr* MsGetChr(uint chr_id); - public const nint __addr_MsGetChr = 0x394030; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int FUN_00867370(byte opcode, AtelBasicWorker* work, AtelWorkThread* thread, AtelStack* stack, uint param_5); - public static int __addr_FUN_00867370 = 0x00467370; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008671d0(byte opcode, AtelWorkThread* thread, AtelBasicWorker* work, AtelStack* stack); - public static int __addr_FUN_008671d0 = 0x004671d0; - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void TOMkpCrossExtMesFontLClutTypeRGBA( - uint p1, - byte* text, - float x, - float y, - byte color, - byte p6, - byte tint_r, byte tint_g, byte tint_b, byte tint_a, - float scale, - float _); - public static int __addr_TOMkpCrossExtMesFontLClutTypeRGBA = 0x501700; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void ToMakeBtlEasyFont(byte* text, float x, float y, byte alpha, float scale); - public static int __addr_ToMakeBtlEasyFont = 0x505AB0; - - // Customization-related - public enum MenuListEnum : uint { - OVERDRIVES = 0, - OVERDRIVE_MODES = 1, - AEON_ABILITIES = 3, - GEAR_CUSTOMIZATION = 5, - EQUIPMENT = 21 - } - public enum CustomizationStatusEnum : byte { - NONE = 0x0, - AEON_AVAILABLE = 0x4, - AEON_ALREADY_LEARNED = 0x5, - AEON_CANNOT_LEARN_WITHOUT_KEY = 0x6, - AEON_NOT_ENOUGH_ITEMS = 0x7, - - GEAR_AVAILABLE = 0xb, - GEAR_ALREADY_APPLIED = 0xc, - GEAR_NOT_ENOUGH_ITEMS = 0xe, - GEAR_CONFLICTING = 0xf, // (same group but lower level) or (same group, same level, different international bonus) or (international bonus is 0xfe AND gear has any ability with 0xff international bonus) - GEAR_NO_SLOTS = 0x10, - //NONE = 0x11 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct CustomizationMenuList { - public ushort a_ability_id; - public CustomizationStatusEnum status; - public byte customization_id; - } - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void PrepareMenuList(MenuListEnum menu_list_id, Equipment* gear); - public static int __addr_PrepareMenuList = 0x004c2370; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void UpdateGearCustomizationMenuState(TkWindow* window); - public static int __addr_UpdateGearCustomizationMenuState = 0x004d5800; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void UpdateAeonCustomizationMenuState(uint param_1, uint param_2); - public static int __addr_UpdateAeonCustomizationMenuState = 0x004cc300; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate CustomizationRecipe* MsGetRomKaizou(int *size); - public static int __addr_MsGetRomKaizou = 0x390A60; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate AutoAbility* MsGetRomAbility(uint a_ability_id, int* ref_data_end); - public static int __addr_MsGetRomAbility = 0x3909C0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate CustomizationRecipe* MsGetRomSummonGrow(int* size); - public static int __addr_MsGetRomSummonGrow = 0x390B00; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate int TkMn2GetSummonGrowMax(); - public static int __addr_TkMn2GetSummonGrowMax = 0x4C1C20; - - - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate byte TkMenuGetCurrentSummon(); - public static int __addr_TkMenuGetCurrentSummon = 0x4A9830; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate bool MsGetSaveCommand(int char_id, uint com_id); - public static int __addr_MsGetSaveCommand = 0x3850E0; - - - - - - // Draw customization menu - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void DrawGearCustomizationMenu(TkWindow* window); - public static int __addr_DrawGearCustomizationMenu = 0x004d5f30; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void DrawAeonCustomizationMenu(TkWindow* window); - public static int __addr_DrawAeonCustomizationMenu = 0x004cdb70; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008c1c70(int param_1, int param_2, uint param_3, int param_4); - public static int __addr_FUN_008c1c70 = 0x004c1c70; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void TODrawMenuPlateXYWHType(float x, float y, float w, float h, int type); - public static int __addr_TODrawMenuPlateXYWHType = 0x004f5f70; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008f8bb0(int param_1, float param_2, float param_3, float param_4, float param_5); - public static int __addr_FUN_008f8bb0 = 0x004f8bb0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void TODrawScissorXYWH(int x, int y, int w, int h); - public static int __addr_TODrawScissorXYWH = 0x004f9230; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008d5d20(TkWindow* window, int param_2, int param_3, int param_4, int param_5); - public static int __addr_FUN_008d5d20 = 0x004d5d20; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008c0f40(int param_1, int param_2, int param_3, int param_4); - public static int __addr_FUN_008c0f40 = 0x004c0f40; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate void FUN_008c1350_DrawScissor512x416(); - public static int __addr_FUN_008c1350_DrawScissor512x416 = 0x004c1350; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008d5dc0(TkWindow* window, int param_2, int param_3); - public static int __addr_FUN_008d5dc0 = 0x004d5dc0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void DrawCrossMenuScrollParts(float param_1, float param_2, float param_3, float param_4, int param_5, int param_6, int param_7); - public static int __addr_DrawCrossMenuScrollParts = 0x004e6cc0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008d6630(int param_1, int param_2, int param_3); - public static int __addr_FUN_008d6630 = 0x004d6630; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate void TkVU1SyncPath(); - public static int __addr_TkVU1SyncPath = 0x0048ebd0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008e71d0(int param_1); - public static int __addr_FUN_008e71d0 = 0x004e71d0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008ff490(uint param_1, float param_2, float param_3); - public static int __addr_FUN_008ff490 = 0x004ff490; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008cd960(TkWindow* window, int param_2, int param_3, float param_4, float param_5); - public static int __addr_FUN_008cd960 = 0x004cd960; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008cd9f0(TkWindow* window, int param_2, int param_3); - public static int __addr_FUN_008cd9f0 = 0x004cd9f0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void ToGetCrossExtMesFontWidth(int param_1, byte* param_2, float* param_3, float param_4, float param_5); - public static int __addr_ToGetCrossExtMesFontWidth = 0x00505320; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate byte* FUN_008bee80(uint param_1); - public static int __addr_FUN_008bee80 = 0x004bee80; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void TOMkpShapeXYWHUV(int param_1, float x, float y, float w, float h, float uv_x1, float uv_y1, float uv_x2, float uv_y2); - public static int __addr_TOMkpShapeXYWHUV = 0x00503bb0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void TOMkpCrossExtMesFontLClut(int param_1, byte* text, float x, float y, byte color, float scale, float p7_unused); - public static int __addr_TOMkpCrossExtMesFontLClut = 0x005016b0; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate uint FUN_008d48e0(); - public static int __addr_FUN_008d48e0 = 0x004d48e0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008d4140(uint param_1, int param_2); - public static int __addr_FUN_008d4140 = 0x004d4140; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void TkMn2DrawKickSyncPacket(); - public static int __addr_TkMn2DrawKickSyncPacket = 0x004c0c90; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate int FUN_008e33a0(byte* text, byte* param_2, byte* param_3); - public static int __addr_FUN_008e33a0 = 0x004e33a0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate TkWindow* TkMenuMainAllocWindow(); - public static int __addr_TkMenuMainAllocWindow = 0x004aa150; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate TkWindow* TkMenuMainRegistWindow(TkWindow* window); - public static int __addr_TkMenuMainRegistWindow = 0x004aaab0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008b4460(TkWindow* window); - public static int __addr_FUN_008b4460 = 0x004b4460; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate void FUN_008e2de0(); - public static int __addr_FUN_008e2de0 = 0x004e2de0; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate void MsSetSaveParamAll(); - public static int __addr_MsSetSaveParamAll = 0x003869c0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void MsSetWeaponName(Equipment* gear); - public static int __addr_MsSetWeaponName = 0x003993c0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FUN_008c2c40(int param_1, int param_2, byte* param_3); - public static int __addr_FUN_008c2c40 = 0x004c2c40; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void TkMn2DrawCrossCursor(float x, float y, int param_3); - public static int __addr_TkMn2DrawCrossCursor = 0x004c0640; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate bool FUN_008d5720(uint gear_id, int param_2); - public static int __addr_FUN_008d5720 = 0x004d5720; -} diff --git a/src/delegates/overdrive_delegates.cs b/src/delegates/overdrive_delegates.cs deleted file mode 100644 index 79bbe7b..0000000 --- a/src/delegates/overdrive_delegates.cs +++ /dev/null @@ -1,241 +0,0 @@ -using Fahrenheit.FFX; -using Fahrenheit.FFX.Battle; -using System.Runtime.InteropServices; - -using Fahrenheit; - -using static ArchipelagoFFX.delegates; - -namespace ArchipelagoFFX; - -public unsafe partial class OverdriveModule { - //TODO: Remove these once FhCall is more up-to-date - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsGetSaveCommand(int char_id, uint com_id); - private const int __addr_MsGetSaveCommand = 0x3850E0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsSetRamChrAbility(int chr_id, Chr* chr); - private const nint __addr_MsSetRamChrAbility = 0x39BB70; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsLimitTidusLearn(int chr_id); - private const nint __addr_MsLimitTidusLearn = 0x3B0CE0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate uint MsAfterDamageProcess(int attacker_id, uint param_2, int target_id, uint* param_4, uint param_5); - private const nint __addr_MsAfterDamageProcess = 0x38F0B0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate Chr* MsGetChr(int chr_id); - private const nint __addr_MsGetChr = 0x394030; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsMenuCloseTitleWindow(int param_1); - private const nint __addr_MsMenuCloseTitleWindow = 0x38FA80; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsMessageCueRegist(uint type, int param_2, int param_3, byte param_4, byte param_5); - private const nint __addr_MsMessageCueRegist = 0x39CFF0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsSetStealEffect(int param_1, int param_2); - private const nint __addr_MsSetStealEffect = 0x39ED20; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate uint MsRegSEplay2(int param_1, uint param_2); - private const nint __addr_MsRegSEplay2 = 0x3A0160; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsPayGIL(int param_1); - private const nint __addr_MsPayGIL = 0x385A60; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsSetStealGillEffect(int param_1, int param_2); - private const nint __addr_MsSetStealGillEffect = 0x39ED40; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsCheckRange(int param_1, int param_2, int param_3); - private const nint __addr_MsCheckRange = 0x39A0D0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsSetSaveCommand(int chr_id, uint param_2, int param_3); - private const nint __addr_MsSetSaveCommand = 0x385D10; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void achievementUnlockAchievement(int ach_id); - private const nint __addr_achievementUnlockAchievement = 0x422410; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsNumberRegist(int param_1, int param_2, int param_3, int param_4, int param_5, uint param_6, uint param_7); - private const nint __addr_MsNumberRegist = 0x39FA20; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsLimitTypeDamageCheck(int attacker_id, Chr* attacker, int target_id, Chr* target, int param_5, int param_6, int param_7); - private const nint __addr_MsLimitTypeDamageCheck = 0x3B0D60; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsSubHP(int chr_id, Chr* chr, int param_3, int param_4, int param_5, uint param_6, uint param_7); - private const nint __addr_MsSubHP = 0x38E2F0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsSubMP(int chr_id, Chr* chr, int param_3, int param_4, int param_5, uint param_6, uint param_7); - private const nint __addr_MsSubMP = 0x38E400; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsSubCTB(int chr_id, Chr* chr, int param_3, int param_4, uint param_5, uint param_6); - private const nint __addr_MsSubCTB = 0x38E2A0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsLimitTypeStatusCheck(int attacker_id, Chr* attacker, int target_id, Chr* target, int param_5, uint param_6); - private const nint __addr_MsLimitTypeStatusCheck = 0x3B12D0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsLimitStatusProcess(int chr_id, Chr* chr, uint param_3); - private const nint __addr_MsLimitStatusProcess = 0x38D330; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsAliveProcess(int chr_id, Chr* chr); - private const nint __addr_MsAliveProcess = 0x389220; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsStoneProcess(int chr_id, Chr* chr); - private const nint __addr_MsStoneProcess = 0x38E210; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsBlowProcess(int chr_id, Chr* chr); - private const nint __addr_MsBlowProcess = 0x389270; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsThreatProcess(int chr_id, Chr* chr); - private const nint __addr_MsThreatProcess = 0x38E4B0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsAutoCureProcess(int target_id, Chr* target, int attacker_id, int poison, int zombie, int darkness, int silence); - private const nint __addr_MsAutoCureProcess = 0x3B2520; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsAutoPotionProcess(int target_id, Chr* target, int attacker_id); - private const nint __addr_MsAutoPotionProcess = 0x3B2860; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsSetChrWeak(int chr_id, int new_weak_level); - private const nint __addr_MsSetChrWeak = 0x38D8B0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate bool MsAutoRelifeProcess(int attacker_id, Chr* attacker, int target_id, Chr* target); - private const nint __addr_MsAutoRelifeProcess = 0x38D990; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsStatusEffectCheck(int chr_id); - private const nint __addr_MsStatusEffectCheck = 0x39F010; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsStatusDefenseEffect(int attacker_id, int target_id, int dmg_calc_flags); - private const nint __addr_MsStatusDefenseEffect = 0x39EE40; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsActionRequest(int target_id, int attacker_id, int param_3, int param_4, int param_5, void* param_6); - private const nint __addr_MsActionRequest = 0x3ACEC0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsPopBtlPos(Chr* chr); - private const nint __addr_MsPopBtlPos = 0x3AC620; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int MsDamageCheckDeath(int attacker_id, int target_id, int param_3, int targeting_self); - private const nint __addr_MsDamageCheckDeath = 0x38C800; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsDamageSetMotion(int chr_id, int param_2, int targeting_self); - private const nint __addr_MsDamageSetMotion = 0x38CAE0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int brnd(int rng_idx); - private const nint __addr_brnd = 0x398900; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void MsSetSaveCommandWithPrefix(int chr_id, int com_id, int param_3); - private const nint __addr_MsSetSaveCommandWithPrefix = 0x474190; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int TOBtlDrawLearningMessageWindow(int chr_id, int com_id); - private const nint __addr_TOBtlDrawLearningMessageWindow = 0x495290; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void TOBtlSetMacroCommandType(int param_1, int param_2, byte param_3); - private const nint __addr_TOBtlSetMacroCommandType = 0x4B5770; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate void TOBtlSetMacroCommandValue(int param_1, int param_2, byte* param_3); - private const nint __addr_TOBtlSetMacroCommandValue = 0x4B57A0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate byte* TOGetSaveChrName(int chr_id); - private const nint __addr_TOGetSaveChrName = 0x4AC800; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate Command* MsGetComData(int com_id, byte** param_2); - private const nint __addr_MsGetComData = 0x39A4C0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate byte* MsGetRomBtlText(int param_1, int param_2); - private const nint __addr_MsGetRomBtlText = 0x38F940; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate int FUN_0089db10(int param_1, byte* param_2); - private const nint __addr_FUN_0089db10 = 0x49DB10; - - private const nint __addr_ret_doesChrKnowCommand = 0x3A30C0; - - // Method Handles - private readonly FhMethodHandle _MsGetSaveCommand; - private readonly FhMethodHandle _MsSetRamChrAbility; - private readonly FhMethodHandle _MsLimitTidusLearn; - private readonly FhMethodHandle _MsAfterDamageProcess; - private readonly FhMethodHandle _ret_doesChrKnowCommand; - private readonly FhMethodHandle _MsSetSaveCommandWithPrefix; - private readonly FhMethodHandle _TOBtlDrawLearningMessageWindow; - - private readonly MsGetChr _MsGetChr = FhUtil.get_fptr(__addr_MsGetChr); - private readonly MsMenuCloseTitleWindow _MsMenuCloseTitleWindow = FhUtil.get_fptr(__addr_MsMenuCloseTitleWindow); - private readonly MsMessageCueRegist _MsMessageCueRegist = FhUtil.get_fptr(__addr_MsMessageCueRegist); - private readonly MsSetStealEffect _MsSetStealEffect = FhUtil.get_fptr(__addr_MsSetStealEffect); - private readonly MsRegSEplay2 _MsRegSEplay2 = FhUtil.get_fptr(__addr_MsRegSEplay2); - private readonly MsPayGIL _MsPayGIL = FhUtil.get_fptr(__addr_MsPayGIL); - private readonly MsSetStealGillEffect _MsSetStealGillEffect = FhUtil.get_fptr(__addr_MsSetStealGillEffect); - private readonly MsCheckRange _MsCheckRange = FhUtil.get_fptr(__addr_MsCheckRange); - private readonly MsSetSaveCommand _MsSetSaveCommand = FhUtil.get_fptr(__addr_MsSetSaveCommand); - private readonly achievementUnlockAchievement _achievementUnlockAchievement = FhUtil.get_fptr(__addr_achievementUnlockAchievement); - private readonly MsNumberRegist _MsNumberRegist = FhUtil.get_fptr(__addr_MsNumberRegist); - private readonly MsLimitTypeDamageCheck _MsLimitTypeDamageCheck = FhUtil.get_fptr(__addr_MsLimitTypeDamageCheck); - private readonly MsSubHP _MsSubHP = FhUtil.get_fptr(__addr_MsSubHP); - private readonly MsSubMP _MsSubMP = FhUtil.get_fptr(__addr_MsSubMP); - private readonly MsSubCTB _MsSubCTB = FhUtil.get_fptr(__addr_MsSubCTB); - private readonly MsLimitTypeStatusCheck _MsLimitTypeStatusCheck = FhUtil.get_fptr(__addr_MsLimitTypeStatusCheck); - private readonly MsLimitStatusProcess _MsLimitStatusProcess = FhUtil.get_fptr(__addr_MsLimitStatusProcess); - private readonly MsAliveProcess _MsAliveProcess = FhUtil.get_fptr(__addr_MsAliveProcess); - private readonly MsStoneProcess _MsStoneProcess = FhUtil.get_fptr(__addr_MsStoneProcess); - private readonly MsBlowProcess _MsBlowProcess = FhUtil.get_fptr(__addr_MsBlowProcess); - private readonly MsThreatProcess _MsThreatProcess = FhUtil.get_fptr(__addr_MsThreatProcess); - private readonly MsAutoCureProcess _MsAutoCureProcess = FhUtil.get_fptr(__addr_MsAutoCureProcess); - private readonly MsAutoPotionProcess _MsAutoPotionProcess = FhUtil.get_fptr(__addr_MsAutoPotionProcess); - private readonly MsSetChrWeak _MsSetChrWeak = FhUtil.get_fptr(__addr_MsSetChrWeak); - private readonly MsAutoRelifeProcess _MsAutoRelifeProcess = FhUtil.get_fptr(__addr_MsAutoRelifeProcess); - private readonly MsStatusEffectCheck _MsStatusEffectCheck = FhUtil.get_fptr(__addr_MsStatusEffectCheck); - private readonly MsStatusDefenseEffect _MsStatusDefenseEffect = FhUtil.get_fptr(__addr_MsStatusDefenseEffect); - private readonly MsActionRequest _MsActionRequest = FhUtil.get_fptr(__addr_MsActionRequest); - private readonly MsPopBtlPos _MsPopBtlPos = FhUtil.get_fptr(__addr_MsPopBtlPos); - private readonly MsDamageCheckDeath _MsDamageCheckDeath = FhUtil.get_fptr(__addr_MsDamageCheckDeath); - private readonly MsDamageSetMotion _MsDamageSetMotion = FhUtil.get_fptr(__addr_MsDamageSetMotion); - private readonly brnd _brnd = FhUtil.get_fptr(__addr_brnd); - private readonly TOBtlSetMacroCommandType _TOBtlSetMacroCommandType = FhUtil.get_fptr(__addr_TOBtlSetMacroCommandType); - private readonly TOBtlSetMacroCommandValue _TOBtlSetMacroCommandValue = FhUtil.get_fptr(__addr_TOBtlSetMacroCommandValue); - private readonly TOGetSaveChrName _TOGetSaveChrName = FhUtil.get_fptr(__addr_TOGetSaveChrName); - private readonly MsGetComData _MsGetComData = FhUtil.get_fptr(__addr_MsGetComData); - private readonly MsGetRomBtlText _MsGetRomBtlText = FhUtil.get_fptr(__addr_MsGetRomBtlText); - private readonly FUN_0089db10 _FUN_0089db10 = FhUtil.get_fptr(__addr_FUN_0089db10); - - private readonly MsGetSaveCommand _fn_MsGetSaveCommand = FhUtil.get_fptr(__addr_MsGetSaveCommand); - private readonly TOBtlDrawLearningMessageWindow _fn_TOBtlDrawLearningMessageWindow = FhUtil.get_fptr(__addr_TOBtlDrawLearningMessageWindow); -} diff --git a/src/gui/debugWindow.cs b/src/gui/debugWindow.cs index 749dbb8..3de4bd6 100644 --- a/src/gui/debugWindow.cs +++ b/src/gui/debugWindow.cs @@ -1,7 +1,8 @@ -using Archipelago.MultiClient.Net.Enums; +using Archipelago.MultiClient.Net.Enums; +using ArchipelagoFFX.Client; +using Fahrenheit; using Fahrenheit.FFX; using Fahrenheit.FFX.Battle; - using Hexa.NET.ImGui; using System; using System.Collections.Generic; @@ -9,70 +10,64 @@ using System.Linq; using System.Numerics; using System.Runtime.InteropServices; - -using ArchipelagoFFX.Client; - -using Fahrenheit; - -using static Fahrenheit.FFX.Globals; using static ArchipelagoFFX.ArchipelagoData; using static ArchipelagoFFX.ArchipelagoFFXModule; -using static ArchipelagoFFX.delegates; +using static Fahrenheit.FFX.Globals; using Color = Archipelago.MultiClient.Net.Models.Color; +using FhXCall = Fahrenheit.FFX.FhCall; namespace ArchipelagoFFX.GUI; -public unsafe static class ArchipelagoGUI { - public delegate void OnRenderDelegate(); - +[FhLoad(FhGameId.FFX)] +public unsafe class ArchipelagoGuiModule : FhModule { public const ImGuiKey archipelago_gui_key = ImGuiKey.F8; public const ImGuiKey experimental_gui_key = ImGuiKey.F9; - public static bool enabled = false; - public static bool experiments_enabled = false; - private static bool show = true; + public bool enabled = false; + public bool experiments_enabled = false; + private bool show = true; public const string DEFAULT_CLIENT_ADDRESS = "archipelago.gg:"; - public static string client_input_address = DEFAULT_CLIENT_ADDRESS; - public static string client_input_name = ""; - private static string client_input_password = ""; + public string client_input_address = DEFAULT_CLIENT_ADDRESS; + public string client_input_name = ""; + private string client_input_password = ""; private static string client_input_command = ""; - public static readonly System.Threading.Lock client_log_lock = new(); - private static List> client_log = []; - public static bool client_log_updated = false; - private static float previous_scroll = 1; - private static float previous_scroll_max = 1; + public readonly System.Threading.Lock client_log_lock = new(); + private List> client_log = []; + public bool client_log_updated = false; + private float previous_scroll = 1; + private float previous_scroll_max = 1; private static readonly Vector2 PANE_BUTTON_SIZE = new Vector2(16f); - private static int grav_mode = 1; - private static int field_mode = 0; - private static int motion_type = 0; + private int grav_mode = 1; + private int field_mode = 0; + private int motion_type = 0; - private static int character_model = 0; + private int character_model = 0; - private static int[] MsBtlGetPosParams = [0, 0, 0]; - private static Vector4 MsBtlGetPosResult = new(0, 0, 0, 0); - private static uint LaunchBattleInput = 0; + private int[] MsBtlGetPosParams = [0, 0, 0]; + private Vector4 MsBtlGetPosResult = new(0, 0, 0, 0); + private uint LaunchBattleInput = 0; - private static int auto_ability_id = 0; - private static AutoAbility* ability = null; - private static int chr_id = 0; - private static Equipment* weapon = null; - private static Equipment* armor = null; + private int auto_ability_id = 0; + private AutoAbility* ability = null; + private int chr_id = 0; + private Equipment* weapon = null; + private Equipment* armor = null; - private static int clickedNodeIndex = -1; + private int clickedNodeIndex = -1; - public static int selected_seed; + public int selected_seed; - public static int font_size = -1; + public int font_size = -1; - private static bool show_popup; - public static string popup_content { + private bool show_popup; + public string popup_content { get; set { field = value; @@ -80,7 +75,35 @@ public static string popup_content { } } - public static void render() { + private FhModuleHandle _client_handle; + private ArchipelagoClientModule? _client; + + private FhModuleHandle _ffx_interop_handle; + private ArchipelagoFFXModule? _ffx_interop; + + private FhModuleHandle _deathlink_handle; + private DeathLinkModule? _deathlink; + + private FhModuleHandle _hardcore_dreams_end_handle; + private HardcoreDreamsEndModule? _hardcore_dreams_end; + + public ArchipelagoGuiModule() { + _client_handle = new(this); + _ffx_interop_handle = new(this); + _hardcore_dreams_end_handle = new(this); + _deathlink_handle = new(this); + } + + public override bool init(FhModContext mod_context, FileStream global_state_file) { + shiori_file = mod_context.Paths.ResourcesDir.GetFiles("shiori.png").FirstOrDefault(); + + return _client_handle.try_get_module(out _client) + && _ffx_interop_handle.try_get_module(out _ffx_interop) + && _hardcore_dreams_end_handle.try_get_module(out _hardcore_dreams_end) + && _deathlink_handle.try_get_module(out _deathlink); + } + + public override void render_imgui() { //ImGui.ShowDebugLogWindow(); //ImGui.ShowStyleEditor(); @@ -90,6 +113,7 @@ public static void render() { //ImGui.PushStyleColor(ImGuiCol.WindowBg, new Vector4 { X = 0.5f, Y = 0.5f, Z = 0.5f }); //ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0f); //ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 0f); + if (font_size == -1) font_size = (int)ImGui.GetFontSize(); ImGui.PushFont(null, font_size); @@ -104,6 +128,7 @@ public static void render() { } render_client(); + #if DEBUG render_experiments(); //render_clusters(); @@ -116,14 +141,14 @@ public static void render() { //ImGui.PopStyleColor(); } - public static FileInfo? shiori_file; - private static FhTexture? shiori_image; + public FileInfo? shiori_file; + private FhTexture? shiori_image; - private static int voiceline_id; - public static byte voice_lang = 0xFF; - public static byte text_lang = 0xFF; + private int voiceline_id; + public byte voice_lang = 0xFF; + public byte text_lang = 0xFF; - private static void render_experiments() { + private void render_experiments() { experiments_enabled ^= ImGui.IsKeyPressed(experimental_gui_key); if (!experiments_enabled) return; @@ -133,38 +158,21 @@ private static void render_experiments() { float frameHeight = ImGui.GetFrameHeight(); Vector2 windowPos = ImGui.GetWindowPos(); float windowBorderSize = ImGui.GetStyle().WindowBorderSize; - //if (shiori_image != null) ImGui.GetForegroundDrawList().AddImage(shiori_image.TextureRef, windowPos + new Vector2(windowBorderSize), new(windowPos.X + frameHeight - windowBorderSize, windowPos.Y + frameHeight - windowBorderSize)); + if (shiori_image?.try_use(out ImTextureRef texture_ref, out _) ?? false) { - ImGui.GetForegroundDrawList() - .AddImage( - texture_ref, - windowPos + new Vector2(windowBorderSize), - new( - windowPos.X + frameHeight - windowBorderSize, - windowPos.Y + frameHeight - windowBorderSize - ) - ); + Vector2 image_tl = windowPos + new Vector2(windowBorderSize); + Vector2 image_br = windowPos + new Vector2(frameHeight) - new Vector2(windowBorderSize); + + ImGui.GetForegroundDrawList().AddImage(texture_ref, image_tl, image_br); } - //Span tidus_name = new Span(Globals.save_data->character_names[0].raw, 20); - //byte[] tidus_decoded = new byte[FhEncoding.compute_decode_buffer_size(tidus_name)]; - // - //int decoded_length = FhEncoding.decode(tidus_name, tidus_decoded); - //string tidus_string = Encoding.UTF8.GetString(tidus_decoded, 0, decoded_length); - //fixed (byte* name_string = tidus_decoded) { - // if (ImGui.InputText("Tidus Name", ref tidus_string, 19, ImGuiInputTextFlags.EnterReturnsTrue)) { - // string final_string = tidus_string + "{END}"; - // FhEncoding.encode(Encoding.UTF8.GetBytes(final_string), tidus_name); - // } - //} - if (ImGui.Checkbox($"Original soundtrack?", &save_data->soundtrack_type)) { - var soundtrack_callback = FhUtil.get_fptr(__addr_FUN_008cc120); - soundtrack_callback(save_data->soundtrack_type ? 1 : 0); + if (ImGui.Checkbox("Original soundtrack?", &save_data->soundtrack_type)) { + FhXCall.FUN_008cc120.fnptr!(save_data->soundtrack_type ? 1 : 0); } - ImGui.InputScalarN("frontline? (0x1FC5)", ImGuiDataType.U8, Globals.Battle.btl->__0x1FC5, 7); - ImGui.InputScalarN("frontline? (0x1FCC)", ImGuiDataType.U8, Globals.Battle.btl->__0x1FCC, 7); - ImGui.InputScalarN("backline? (0x1FD3)", ImGuiDataType.U8, Globals.Battle.btl->__0x1FD3, 17); + ImGui.InputScalarN("frontline? (0x1FC5)", ImGuiDataType.U8, &Battle.btl->__0x1FC5, 7); + ImGui.InputScalarN("frontline? (0x1FCC)", ImGuiDataType.U8, &Battle.btl->__0x1FCC, 7); + ImGui.InputScalarN("backline? (0x1FD3)", ImGuiDataType.U8, &Battle.btl->__0x1FD3, 17); @@ -203,7 +211,7 @@ private static void render_experiments() { // ImGui.Image(shiori_image.TextureRef, new(shiori_image.Metadata.width, shiori_image.Metadata.height)); //} - ImGui.Text($"Tidus overdrive uses: {Globals.save_data->tidus_limit_uses}"); + ImGui.Text($"Tidus overdrive uses: {save_data->tidus_limit_uses}"); //for (int i = 0; i < 18; i++) { // string name = Globals.save_data->character_names[i].name; @@ -214,16 +222,15 @@ private static void render_experiments() { ImGui.InputInt("Voiceline id", ref voiceline_id); if (ImGui.Button("Play voiceline")) { - queued_voice_lines.Enqueue(voiceline_id); + _ffx_interop!.queued_voice_lines.Enqueue(voiceline_id); } int inMenu = FhUtil.get_at(0x01efb4d4); ImGui.Text($"Is in menu?: {inMenu}"); + BtlArea* pos_def_ptr = Battle.btl->ptr_pos_def; - BtlArea* pos_def_ptr = Globals.Battle.btl->ptr_pos_def; - - if (pos_def_ptr != null && Globals.Battle.btl->battle_state != 0) { + if (pos_def_ptr != null && Battle.btl->battle_state != 0) { BtlAreasHelper areas = new(pos_def_ptr); //BtlAreas areas = *pos_def_ptr; @@ -354,7 +361,7 @@ private static void render_experiments() { // localizationManager->voice = voice_language; // // nint _FmodManager = FhUtil.get_at(0x008E9000); - // //_FfxFmod_soundInit(*(nint*)(_FmodManager+8)); + // //FhXCall.FfxFmod_soundInit.fnptr!(*(nint*)(_FmodManager+8)); // // nint ffxFmod = *(nint*)(_FmodManager + 8); // @@ -362,9 +369,9 @@ private static void render_experiments() { // // *(byte*)(fmodVoice + 4) = (byte)voice_language; // - // _FmodVoice_initList(fmodVoice); + // FhXCall.FmodVoice_initList.fnptr!(fmodVoice); // - // int dataChange_result = h_FmodVoice_dataChange(fmodVoice, Globals.save_data->current_room_id, *(nint*)(ffxFmod + 4)); + // int dataChange_result = FmodVoice_dataChange(fmodVoice, Globals.save_data->current_room_id, *(nint*)(ffxFmod + 4)); // if (dataChange_result != 0) { // *(nint*)(*(int*)((int)ffxFmod + 0xc) + 0x28) = **(nint**)((int)ffxFmod + 0x10); // } @@ -375,142 +382,17 @@ private static void render_experiments() { //if (ImGui.InputText("Name Test", ref tidusName, 20)) { // Globals.save_data->character_names[0].name = tidusName; //} - - } - ImGui.End(); - - return; - - if (Globals.SphereGrid.lpamng == null) return; - - if (!ImGui.Begin("Archipelago###Archipelago.Experiments.GUI")) { - ImGui.End(); - return; - } - - if (ImGui.Button("Activate all nodes for all characters")) { - for (int i = 0; i < Globals.SphereGrid.lpamng->node_count; i++) { - Globals.SphereGrid.lpamng->nodes[i].activated_by = 0x7f; - } - } - - //if (ImGui.InputScalar("Selected node:", ImGuiDataType.U32, (nint)(&Globals.SphereGrid.lpamng->selected_node_idx))) { - // Globals.SphereGrid.lpamng->cam_desired_pos.X = Globals.SphereGrid.lpamng->nodes[Globals.SphereGrid.lpamng->selected_node_idx].x; - // Globals.SphereGrid.lpamng->cam_desired_pos.Y = Globals.SphereGrid.lpamng->nodes[Globals.SphereGrid.lpamng->selected_node_idx].y; - //} - var camDesiredPos = Globals.SphereGrid.lpamng->cam_desired_pos; - //ImGui.Text($"desired pos: {camDesiredPos.X}, {camDesiredPos.Y}, {camDesiredPos.Z}, {camDesiredPos.W}"); - - - int selectedNodeIndex = Globals.SphereGrid.lpamng->selected_node_idx; - SphereGridNode selectedNode = Globals.SphereGrid.lpamng->nodes[selectedNodeIndex]; - - //ImGui.Text($"Selected node: {selectedNodeIndex}, pos: ({selectedNode.x}, {selectedNode.y}), type: {(NodeType)selectedNode.node_type}"); - - Matrix4x4* world_matrix = (Matrix4x4*)(*FhUtil.ptr_at(0x8cb9d8) + 0xd34); - //if (ImGui.CollapsingHeader("World Matrix")) { - // ImGui.InputScalarN($"x", ImGuiDataType.Float, (nint)(&world_matrix->M11), 4); - // ImGui.InputScalarN($"y", ImGuiDataType.Float, (nint)(&world_matrix->M21), 4); - // ImGui.InputScalarN($"z", ImGuiDataType.Float, (nint)(&world_matrix->M31), 4); - // ImGui.InputScalarN($"w", ImGuiDataType.Float, (nint)(&world_matrix->M41), 4); - //} - Vector4* temp = (Vector4*)(&world_matrix->M11); - - var mousePos = ImGui.GetMousePos(); - //ImGui.Text($"Mouse pos: {mousePos.X}, {mousePos.Y}"); - var centeredPos = mousePos - (ImGui.GetWindowViewport().Size * 0.5f); - //ImGui.Text($"Centered mouse pos: {centeredPos.X}, {centeredPos.Y}"); - - // Doesn't work - //float tiltRatio = Globals.SphereGrid.lpamng->tilt_level switch { - // SphereGridTilt.FarTilt => 1.40625f, - // SphereGridTilt.SlightTilt => 1.125f, - // _ => 1, - //}; - - float main_x = 2560; - float main_y = 1440; - float x_ratio = main_x / ImGui.GetWindowViewport().Size.X; - float y_ratio = x_ratio * (3.0f/4.0f); - var gridPos = new Vector2(centeredPos.X * x_ratio, centeredPos.Y * y_ratio); - //ImGui.Text($"Grid mouse pos: {gridPos.X}, {gridPos.Y}"); - float zoom_mult = Globals.SphereGrid.lpamng->zoom_level.get_zoom(); - var absPos = new Vector2(-gridPos.X / zoom_mult + world_matrix->M31, -gridPos.Y / zoom_mult + world_matrix->M32); - //ImGui.Text($"Absolute mouse pos: {absPos.X}, {absPos.Y}"); - - // Adjusts the center offset - //float tiltAdjustment = Globals.SphereGrid.lpamng->tilt_level switch { - // SphereGridTilt.FarTilt => 855.801f, - // SphereGridTilt.SlightTilt => 455.475f, - // _ => 0, - //}; - var truePos = new Vector2((absPos.X ) / -3.75f, (absPos.Y ) / -2.8125f); - //ImGui.Text($"True mouse pos: {truePos.X}, {truePos.Y}"); - - // Only bother if flat - int closestNodeIndex = -1; - if (Globals.SphereGrid.lpamng->tilt_level == SphereGridTilt.FLAT) { - float shortestDistance = 20; - for (int i = 0; i < 1024; i++) { - float distance = (new Vector2(Globals.SphereGrid.lpamng->nodes[i].x, Globals.SphereGrid.lpamng->nodes[i].y) - truePos).Length(); - if (distance < shortestDistance) { - closestNodeIndex = i; - shortestDistance = distance; - } - } - if (closestNodeIndex != -1) { - SphereGridNode closestNode = Globals.SphereGrid.lpamng->nodes[closestNodeIndex]; - //ImGui.Text($"Hovered node: {closestNodeIndex}, pos: ({closestNode.x}, {closestNode.y}), type: {(NodeType)closestNode.node_type}"); - - } - if (!ImGui.GetIO().WantCaptureMouse && ImGui.IsMouseReleased(ImGuiMouseButton.Left)) { - clickedNodeIndex = closestNodeIndex; - } } - if (clickedNodeIndex != -1) { - SphereGridNode* clickedNode = &Globals.SphereGrid.lpamng->nodes[clickedNodeIndex]; - ImGui.Text($"Clicked node: {clickedNodeIndex}, pos: ({clickedNode->x}, {clickedNode->y}), type: {(NodeType)clickedNode->node_type}"); - NodeType[] typeArray = Enum.GetValues(); - //ImGui.ListBox("Node type", clickedNode->node_type, typeArray, typeArray.Length); - if (ImGui.BeginListBox("Node type")) { - for (int i = 0; i < typeArray.Length; i++) { - bool is_selected = (typeArray[i] == clickedNode->node_type); - if (ImGui.Selectable($"{typeArray[i]}")) { - clickedNode->node_type = typeArray[i]; - Globals.SphereGrid.lpamng->should_update = 1; - Globals.SphereGrid.lpamng->should_update_node = clickedNodeIndex; - } - if (is_selected) { - ImGui.SetItemDefaultFocus(); - } - } - ImGui.EndListBox(); - } - - for (int i = 0; i < 7; i++) { - if (ImGui.Button($"{id_to_character[i]}: {(clickedNode->activated_by & (1 << i)) != 0}")) { - clickedNode->activated_by ^= (byte)(1 << i); - ArchipelagoFFXModule.h_eiAbmParaGet(); - Globals.SphereGrid.lpamng->should_update = 1; - // Setting to clickedNodeIndex only turns off light if no character has it activated. Setting to -1 correctly turns on/off node itself, but not surrounding lights (per character). - Globals.SphereGrid.lpamng->should_update_node = -1; - } - } - } - - - - ImGui.End(); } - private static void render_sphere_grid_editor() { + private void render_sphere_grid_editor() { ImGuiStylePtr style = ImGui.GetStyle(); if (ImGui.Button("Activate all nodes for all characters")) { - for (int i = 0; i < Globals.SphereGrid.lpamng->node_count; i++) { - Globals.SphereGrid.lpamng->nodes[i].activated_by = 0x7f; + for (int i = 0; i < SphereGrid.lpamng->node_count; i++) { + SphereGrid.lpamng->nodes[i].activated_by = 0x7f; } } @@ -523,23 +405,23 @@ private static void render_sphere_grid_editor() { float x_ratio = main_x / ImGui.GetWindowViewport().Size.X; float y_ratio = x_ratio * (3.0f/4.0f); var gridPos = new Vector2(centeredPos.X * x_ratio, centeredPos.Y * y_ratio); - float zoom_mult = Globals.SphereGrid.lpamng->zoom_level.get_zoom(); + float zoom_mult = SphereGrid.lpamng->zoom_level.get_zoom(); var absPos = new Vector2(-gridPos.X / zoom_mult + world_matrix->M31, -gridPos.Y / zoom_mult + world_matrix->M32); var truePos = new Vector2((absPos.X ) / -3.75f, (absPos.Y ) / -2.8125f); // Only bother if flat int closestNodeIndex = -1; - if (Globals.SphereGrid.lpamng->tilt_level == SphereGridTilt.FLAT) { + if (SphereGrid.lpamng->tilt_level == SphereGridTilt.FLAT) { float shortestDistance = 20; for (int i = 0; i < 1024; i++) { - float distance = (new Vector2(Globals.SphereGrid.lpamng->nodes[i].x, Globals.SphereGrid.lpamng->nodes[i].y) - truePos).Length(); + float distance = (new Vector2(SphereGrid.lpamng->nodes[i].x, SphereGrid.lpamng->nodes[i].y) - truePos).Length(); if (distance < shortestDistance) { closestNodeIndex = i; shortestDistance = distance; } } if (closestNodeIndex != -1) { - SphereGridNode closestNode = Globals.SphereGrid.lpamng->nodes[closestNodeIndex]; + SphereGridNode closestNode = SphereGrid.lpamng->nodes[closestNodeIndex]; } if (!ImGui.GetIO().WantCaptureMouse && ImGui.IsMouseReleased(ImGuiMouseButton.Left)) { @@ -548,16 +430,16 @@ private static void render_sphere_grid_editor() { } if (clickedNodeIndex != -1) { - SphereGridNode* clickedNode = &Globals.SphereGrid.lpamng->nodes[clickedNodeIndex]; - ImGui.Text($"Clicked node: {clickedNodeIndex}, pos: ({clickedNode->x}, {clickedNode->y}), type: {(NodeType)clickedNode->node_type}"); + SphereGridNode* clickedNode = &SphereGrid.lpamng->nodes[clickedNodeIndex]; + ImGui.Text($"Clicked node: {clickedNodeIndex}, pos: ({clickedNode->x}, {clickedNode->y}), type: {clickedNode->node_type}"); NodeType[] typeArray = Enum.GetValues(); if (ImGui.BeginListBox("Node type")) { for (int i = 0; i < typeArray.Length - 1; i++) { bool is_selected = (typeArray[i] == clickedNode->node_type); if (ImGui.Selectable($"{typeArray[i]}")) { clickedNode->node_type = typeArray[i]; - Globals.SphereGrid.lpamng->should_update = 1; - Globals.SphereGrid.lpamng->should_update_node = clickedNodeIndex; + SphereGrid.lpamng->should_update = 1; + SphereGrid.lpamng->should_update_node = clickedNodeIndex; } if (is_selected) { ImGui.SetItemDefaultFocus(); @@ -569,59 +451,58 @@ private static void render_sphere_grid_editor() { for (int i = 0; i < 7; i++) { if (ImGui.Button($"{id_to_character[i]}: {(clickedNode->activated_by & (1 << i)) != 0}")) { clickedNode->activated_by ^= (byte)(1 << i); - ArchipelagoFFXModule.h_eiAbmParaGet(); - Globals.SphereGrid.lpamng->should_update = 1; + FhXCall.eiAbmParaGet.fnptr!(); + SphereGrid.lpamng->should_update = 1; // Setting to clickedNodeIndex only turns off light if no character has it activated. Setting to -1 correctly turns on/off node itself, but not surrounding lights (per character). - Globals.SphereGrid.lpamng->should_update_node = -1; + SphereGrid.lpamng->should_update_node = -1; } } } } - private static void render_connection() { - if (seed.Options.SeedId is null && !FFXArchipelagoClient.is_connected) { - string[] seedNames = [.. ArchipelagoFFXModule.loaded_seeds.Select(x => x.Name)]; + private void render_connection() { + if (seed.Options.SeedId is null && !(_client!.is_connected)) { + string[] seedNames = [.. loaded_seeds.Select(x => x.Name)]; if (ImGui.Combo("Selected seed", ref selected_seed, seedNames, seedNames.Length)) { - ArchipelagoFFXModule.ArchipelagoSeed seed = ArchipelagoFFXModule.loaded_seeds[selected_seed]; + ArchipelagoSeed seed = loaded_seeds[selected_seed]; client_input_name = seed.Options.PlayerName; - if (ArchipelagoFFXModule.SeedToServer.TryGetValue(seed.Options.SeedId, out string? server)) { + if (SeedToServer.TryGetValue(seed.Options.SeedId, out string? server)) { client_input_address = server; } else { - ArchipelagoGUI.client_input_address = ArchipelagoGUI.DEFAULT_CLIENT_ADDRESS; + client_input_address = DEFAULT_CLIENT_ADDRESS; } } } else { ImGui.Text($"Loaded seed: {seed.Name}"); } - if (!FFXArchipelagoClient.is_connected) { + if (!(_client!.is_connected)) { ImGui.InputText("Address", ref client_input_address, 50); ImGui.InputText("Name", ref client_input_name, 50); ImGui.InputText("Password", ref client_input_password, 50); if (ImGui.Button("Connect")) { //Task.Run(() => FFXArchipelagoClient.Connect(client_input_address, client_input_name, client_input_password)); - _ = FFXArchipelagoClient.Connect(client_input_address, client_input_name, client_input_password); + _ = _client!.Connect(client_input_address, client_input_name, client_input_password); //FFXArchipelagoClient.Connect(client_input_address, client_input_name, client_input_password); } } else { - ImGui.Text($"Connected as {FFXArchipelagoClient.active_player?.Name}"); + ImGui.Text($"Connected as {_client!.active_player?.Name}"); if (ImGui.Button("Disconnect")) { - FFXArchipelagoClient.disconnect(); + _client!.disconnect(); } } } - public static void add_log_message(List<(string, Color)> message) { + public void add_log_message(List<(string, Color)> message) { lock (client_log_lock) { client_log.Add(message); client_log_updated = true; } } - private static LinkedList client_input_history = new(); - private static LinkedListNode? client_input_history_current = null; - private static ImGuiInputTextCallback _client_input_ImGuiInputTextCallback = client_input_ImGuiInputTextCallback; - private static bool focus_client_input = false; - private static int client_input_ImGuiInputTextCallback(ImGuiInputTextCallbackData* data) { + private LinkedList client_input_history = new(); + private LinkedListNode? client_input_history_current; + private bool focus_client_input; + private int client_input_ImGuiInputTextCallback(ImGuiInputTextCallbackData* data) { if (data->EventFlag == ImGuiInputTextFlags.CallbackHistory) { if (data->EventKey == ImGuiKey.UpArrow) { if (client_input_history_current is null && client_input_history.First is not null) { @@ -634,7 +515,6 @@ private static int client_input_ImGuiInputTextCallback(ImGuiInputTextCallbackDat data->InsertChars(0, client_input_history_current.Value); } } else if (data->EventKey == ImGuiKey.DownArrow) { - client_input_history_current = client_input_history_current?.Previous; data->DeleteChars(0, data->BufTextLen); if (client_input_history_current is not null) { @@ -642,9 +522,11 @@ private static int client_input_ImGuiInputTextCallback(ImGuiInputTextCallbackDat } } } + return 0; } - private static void render_console() { + + private void render_console() { ImGuiStylePtr style = ImGui.GetStyle(); if (ImGui.BeginChild("Archipelago.GUI.Log", new(0, ImGui.GetContentRegionAvail().Y - ImGui.GetTextLineHeight() - 3 * style.ItemSpacing.Y), ImGuiChildFlags.Borders, ImGuiWindowFlags.NoMove)) { //var curr_scroll = ImGui.GetScrollY() / previous_scroll_max; @@ -693,11 +575,14 @@ private static void render_console() { ImGui.SetKeyboardFocusHere(); focus_client_input = false; } - bool process_input = ImGui.InputText("Input", - ref client_input_command, - 150, - ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CallbackHistory, - _client_input_ImGuiInputTextCallback); + + bool process_input = ImGui.InputText( + "Input", + ref client_input_command, + 150, + ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CallbackHistory, + client_input_ImGuiInputTextCallback + ); if (process_input && client_input_command.Length > 0) { client_input_history.AddFirst(client_input_command); @@ -710,199 +595,197 @@ private static void render_console() { if (!client_input_command.StartsWith("/")) { // Say - FFXArchipelagoClient.SayAsync(client_input_command); + _client!.SayAsync(client_input_command); } else { // Client-side command string[] cmd = client_input_command.Split(" "); + Action cmd_fn = parse_command(cmd); - Action fn = cmd switch { - ["/resetregion", string regionString] => () => { - ArchipelagoData.RegionEnum region = stringToRegion(regionString); - if (region != ArchipelagoData.RegionEnum.None) { - ArchipelagoFFXModule.region_states[region].story_progress = region_starting_state[region].story_progress; - ArchipelagoFFXModule.region_states[region].room_id = region_starting_state[region].room_id; - ArchipelagoFFXModule.region_states[region].entrance = region_starting_state[region].entrance; - region_starting_state[region].savedata.CopyTo(ArchipelagoFFXModule.region_states[region].savedata); + cmd_fn(); + client_log_updated = true; + } + client_input_command = ""; + } + } - List<(string, Color)> message = [(region.ToString(), Color.Blue), (" has been reset", Color.White)]; - add_log_message(message); - } - else { - List<(string, Color)> message = [("invalid region: ", Color.Red), (regionString, Color.Blue)]; - add_log_message(message); - } - } - , - ["/resetregion", ..] => () => { - List<(string, Color)> message = [("Wrong arguments for '/resetregion': Should be ", Color.Red), ($"/resetregion regionName", Color.Blue)]; - add_log_message(message); - } - , -#if DEBUG - ["/setdatastorage", string key, string value] => () => { - lock (FFXArchipelagoClient.client_lock) { - if (FFXArchipelagoClient.is_connected) { - FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_ROOM"] = value; - } + private Action parse_command(string[] command) { + return command switch { + ["/resetregion", { } region_name] => () => { + RegionEnum region = stringToRegion(region_name); + if (region != RegionEnum.None) { + ArchipelagoRegion region_state = region_states[region]; + region_state.story_progress = region_starting_state[region].story_progress; + region_state.room_id = region_starting_state[region].room_id; + region_state.entrance = region_starting_state[region].entrance; + region_starting_state[region].savedata.CopyTo(region_state.savedata); + + List<(string, Color)> message = [(region.ToString(), Color.Blue), (" has been reset", Color.White)]; + add_log_message(message); + } + else { + List<(string, Color)> message = [("invalid region: ", Color.Red), (region_name, Color.Blue)]; + add_log_message(message); + } + }, - } - } - , - ["/getdatastorage", string key] => () => { - lock (FFXArchipelagoClient.client_lock) { - if (FFXArchipelagoClient.is_connected) { - string? message_text = FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, key]; - if (message_text != null) { - List<(string, Color)> message = [(key, Color.Blue), (message_text, Color.White)]; - add_log_message(message); - } - } - } - } - , - ["/setregion", string regionString, string progressString, string mapString, string entranceString] => () => { - ArchipelagoData.RegionEnum region = stringToRegion(regionString); - if (region != ArchipelagoData.RegionEnum.None) { - if (ushort.TryParse(progressString, out ushort progress)) { - if (ushort.TryParse(mapString, out ushort map)) { - if (ushort.TryParse(entranceString, out ushort entrance)) { - ArchipelagoData.ArchipelagoRegion r = ArchipelagoFFXModule.region_states[region]; - r.story_progress = progress; - r.room_id = map; - r.entrance = entrance; - - List<(string, Color)> message = [(region.ToString(), Color.Blue), ($"'s state has been set to (story_progress: {progress}, room_id: {map}, entrance: {entrance})", Color.White)]; - add_log_message(message); - } - else { - List<(string, Color)> message = [("invalid entrance_id: ", Color.Red), (entranceString, Color.Blue)]; - add_log_message(message); - } - } - else{ - List<(string, Color)> message = [("invalid map_id: ", Color.Red), (mapString, Color.Blue)]; - add_log_message(message); - } + ["/resetregion", ..] => () => { + List<(string, Color)> message = [("Wrong arguments for '/resetregion': Should be ", Color.Red), ("/resetregion regionName", Color.Blue)]; + add_log_message(message); + }, - } - else { - List<(string, Color)> message = [("invalid story_progress: ", Color.Red), (progressString, Color.Blue)]; - add_log_message(message); - } +#if DEBUG + ["/setdatastorage", { } key, { } value] => () => { + lock (_client!.client_lock) { + if (_client!.is_connected) { + _client!.current_session!.DataStorage[Scope.Slot, key] = value; + } - } - else { - List<(string, Color)> message = [("invalid region: ", Color.Red), (regionString, Color.Blue)]; + } + }, + + ["/getdatastorage", { } key] => () => { + lock (_client!.client_lock) { + if (_client!.is_connected) { + string? message_text = _client!.current_session!.DataStorage[Scope.Slot, key]; + if (message_text != null) { + List<(string, Color)> message = [(key, Color.Blue), (message_text, Color.White)]; add_log_message(message); } } - , - ["/setregion", ..] => () => { - List<(string, Color)> message = [("Wrong arguments for '/setregion': Should be ", Color.Red), ($"/setregion regionName story_progress map_id entrance_id", Color.Blue)]; - add_log_message(message); - } - , - ["/warp", string map, string entrance] => () => { - if (int.TryParse(map, out int map_id)) { - if (int.TryParse(entrance, out int entrance_id)) { - List<(string, Color)> message = [("Warping to ", Color.White), ($"{map_id} (entrance {entrance_id})", Color.Blue)]; + } + }, + + ["/setregion", { } regionString, { } progressString, { } mapString, { } entranceString] => () => { + RegionEnum region = stringToRegion(regionString); + if (region != RegionEnum.None) { + if (ushort.TryParse(progressString, out ushort progress)) { + if (ushort.TryParse(mapString, out ushort map)) { + if (ushort.TryParse(entranceString, out ushort entrance)) { + ArchipelagoRegion region_state = region_states[region]; + region_state.story_progress = progress; + region_state.room_id = map; + region_state.entrance = entrance; + + List<(string, Color)> message = [(region.ToString(), Color.Blue), ($"'s state has been set to (story_progress: {progress}, room_id: {map}, entrance: {entrance})", Color.White)]; add_log_message(message); - ArchipelagoFFXModule.call_warp_to_map(map_id, entrance_id); - } - else { - List<(string, Color)> message = [("invalid entrance_id: ", Color.Red), (entrance, Color.Blue)]; + } else { + List<(string, Color)> message = [("invalid entrance_id: ", Color.Red), (entranceString, Color.Blue)]; add_log_message(message); } - } - else { - List<(string, Color)> message = [("invalid map_id: ", Color.Red), (map, Color.Blue)]; + } else { + List<(string, Color)> message = [("invalid map_id: ", Color.Red), (mapString, Color.Blue)]; add_log_message(message); } - } - , - ["/warp", ..] => () => { - List<(string, Color)> message = [("Wrong arguments for /warp: Should be ", Color.Red), ($"/warp map_id entrance_id", Color.Blue)]; + } else { + List<(string, Color)> message = [("invalid story_progress: ", Color.Red), (progressString, Color.Blue)]; add_log_message(message); } - , -#endif - ["/send_checks"] => () => { - FFXArchipelagoClient.local_locations_updated = true; + } else { + List<(string, Color)> message = [("invalid region: ", Color.Red), (regionString, Color.Blue)]; + add_log_message(message); + } + }, + + ["/setregion", ..] => () => { + List<(string, Color)> message = [("Wrong arguments for '/setregion': Should be ", Color.Red), ("/setregion regionName story_progress map_id entrance_id", Color.Blue)]; + add_log_message(message); + }, - List<(string, Color)> message = [("Resending local checks", Color.White)]; + ["/warp", { } map, { } entrance] => () => { + if (int.TryParse(map, out int map_id)) { + if (int.TryParse(entrance, out int entrance_id)) { + List<(string, Color)> message = [("Warping to ", Color.White), ($"{map_id} (entrance {entrance_id})", Color.Blue)]; + add_log_message(message); + _ffx_interop!.call_warp_to_map(map_id, entrance_id); + } else { + List<(string, Color)> message = [("invalid entrance_id: ", Color.Red), (entrance, Color.Blue)]; add_log_message(message); } - , - ["/clear"] => () => { - lock (client_log_lock) { - client_log.Clear(); - } - } - , - ["/help"] => () => { - add_log_message([("Available commands:", Color.White)]); + } else { + List<(string, Color)> message = [("invalid map_id: ", Color.Red), (map, Color.Blue)]; + add_log_message(message); + } + }, + + ["/warp", ..] => () => { + List<(string, Color)> message = [("Wrong arguments for /warp: Should be ", Color.Red), ($"/warp map_id entrance_id", Color.Blue)]; + add_log_message(message); + }, +#endif + + ["/send_checks"] => () => { + _client!.local_locations_updated = true; + + List<(string, Color)> message = [("Resending local checks", Color.White)]; + add_log_message(message); + }, + + ["/clear"] => () => { + lock (client_log_lock) { + client_log.Clear(); + } + }, + + ["/help"] => () => { + add_log_message([("Available commands:", Color.White)]); #if DEBUG - add_log_message([("/setregion regionName progress map entrance", Color.White)]); + add_log_message([("/setdatastorage key value", Color.White)]); + add_log_message([("/getdatastorage key", Color.White)]); + add_log_message([("/warp map entrance", Color.White)]); + add_log_message([("/setregion regionName progress map entrance", Color.White)]); #endif - add_log_message([("/resetregion regionName", Color.White)]); - add_log_message([("/send_checks", Color.White)]); - add_log_message([("/clear", Color.White)]); - } - , - _ => () => { - List<(string, Color)> message = [("unknown command: ", Color.Red), (client_input_command, Color.Blue)]; - add_log_message(message); - } - }; - fn(); - client_log_updated = true; + add_log_message([("/resetregion regionName", Color.White)]); + add_log_message([("/send_checks", Color.White)]); + add_log_message([("/clear", Color.White)]); + }, + + _ => () => { + List<(string, Color)> message = [("unknown command: ", Color.Red), (client_input_command, Color.Blue)]; + add_log_message(message); } - client_input_command = ""; - } + }; } - private static void render_debug_tab() { + private void render_debug_tab() { #if DEBUG - fixed (int* ap_mult = &ArchipelagoFFXModule.ap_multiplier) { + fixed (int* ap_mult = &ap_multiplier) { uint step = 1; uint step_fast = 10; ImGui.InputScalar("AP multiplier", ImGuiDataType.U32, ap_mult, &step, &step_fast); } #endif - ImGui.Text($"Current room: {Globals.save_data->current_room_id} ({Marshal.PtrToStringAnsi((nint)ArchipelagoFFXModule.get_event_name(*(uint*)Globals.event_id))!})"); - ImGui.Text($"Current region: {ArchipelagoFFXModule.current_region}"); - ImGui.Text($"Current story progress: {Globals.save_data->story_progress}"); - if (ArchipelagoFFXModule.current_region != ArchipelagoData.RegionEnum.None) { - foreach (var data in ArchipelagoFFXModule.region_states[current_region].savedata) { + ImGui.Text($"Current room: {save_data->current_room_id} ({Marshal.PtrToStringAnsi((nint)get_event_name(*(uint*)event_id))!})"); + ImGui.Text($"Current region: {current_region}"); + ImGui.Text($"Current story progress: {save_data->story_progress}"); + if (current_region != RegionEnum.None) { + foreach (var data in region_states[current_region].savedata) { ImGui.Text($"{data.offset}: {string.Join(" ", data.bytes.Select(b => b.ToString()).ToArray())}"); } } ImGui.SeparatorText("Region states"); if (ImGui.BeginTable("Region states", 5)) { + ImGui.TableSetupColumn("Region"); ImGui.TableSetupColumn("story_progress"); ImGui.TableSetupColumn("room"); ImGui.TableSetupColumn("entrance"); ImGui.TableSetupColumn("completed_visits"); ImGui.TableHeadersRow(); - foreach (var region in ArchipelagoFFXModule.region_states) { - ImGui.TableNextColumn(); - ImGui.Text($"{region.Key}"); - ImGui.TableNextColumn(); - ImGui.Text($"{region.Value.story_progress}"); - ImGui.TableNextColumn(); - ImGui.Text($"{region.Value.room_id}"); - ImGui.TableNextColumn(); - ImGui.Text($"{region.Value.entrance}"); - ImGui.TableNextColumn(); - ImGui.Text($"{region.Value.completed_visits}"); + + foreach (var region in region_states) { + ImGui.TableNextColumn(); ImGui.Text($"{region.Key}"); + ImGui.TableNextColumn(); ImGui.Text($"{region.Value.story_progress}"); + ImGui.TableNextColumn(); ImGui.Text($"{region.Value.room_id}"); + ImGui.TableNextColumn(); ImGui.Text($"{region.Value.entrance}"); + ImGui.TableNextColumn(); ImGui.Text($"{region.Value.completed_visits}"); } + ImGui.EndTable(); } - if (Globals.Battle.btl->battle_state != 0) { + if (Battle.btl->battle_state != 0) { ImGui.Text($"Battle Name: {Marshal.PtrToStringAnsi((nint)FhUtil.ptr_at(0xD2C25A))}"); } else { #if DEBUG @@ -912,7 +795,7 @@ private static void render_debug_tab() { ImGui.InputScalar("launchBattleInput", ImGuiDataType.U32, battle_input, &p_step, &p_step_fast, "%x"); } if (ImGui.Button("launchBattleButton")) { - ArchipelagoFFXModule._MsBattleLabelExe(LaunchBattleInput, 1, 1); + FhXCall.MsBattleLabelExe.fnptr!(LaunchBattleInput, 1, 1); } #endif } @@ -944,16 +827,16 @@ private static void render_unlocks() { ImGui.SetCursorPosX((ImGui.GetWindowWidth() - ImGui.CalcTextSize(s).X) * 0.5f); ImGui.Text(s); if (ImGui.BeginTable("Region Unlocks", 3)) { - foreach (var (region, i) in ArchipelagoFFXModule.region_is_unlocked.Select((value, i) => (value, i))) { + foreach (var (region, i) in region_is_unlocked.Select((value, i) => (value, i))) { ImGui.TableNextColumn(); Color color = region.Value ? Color.Green : Color.Red; ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, 1.0f)); #if !DEBUG ImGui.BeginDisabled(); #endif - bool unlocked = ArchipelagoFFXModule.region_is_unlocked[region.Key]; + bool unlocked = region_is_unlocked[region.Key]; if (ImGui.Checkbox($"###Archipelago.GUI.Unlocks.{region.Key}", &unlocked)) { - ArchipelagoFFXModule.region_is_unlocked[region.Key] = unlocked; + region_is_unlocked[region.Key] = unlocked; } #if !DEBUG ImGui.EndDisabled(); @@ -969,16 +852,16 @@ private static void render_unlocks() { ImGui.SetCursorPosX((ImGui.GetWindowWidth() - ImGui.CalcTextSize(s).X) * 0.5f); ImGui.Text(s); if (ImGui.BeginTable("Character Unlocks", 3)) { - foreach (var (character, i) in ArchipelagoFFXModule.unlocked_characters.Select((value, i) => (value, i))) { + foreach (var (character, i) in unlocked_characters.Select((value, i) => (value, i))) { ImGui.TableNextColumn(); Color color = character.Value ? Color.Green : Color.Red; ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(color.R / 255f, color.G / 255f, color.B / 255f, 1.0f)); #if !DEBUG ImGui.BeginDisabled(); #endif - bool unlocked = ArchipelagoFFXModule.unlocked_characters[character.Key]; + bool unlocked = unlocked_characters[character.Key]; if (ImGui.Checkbox($"###Archipelago.GUI.Unlocks.{id_to_character[character.Key]}", &unlocked)) { - ArchipelagoFFXModule.unlocked_characters[character.Key] = unlocked; + unlocked_characters[character.Key] = unlocked; } #if !DEBUG ImGui.EndDisabled(); @@ -995,7 +878,7 @@ private static void render_unlocks() { } } - private static void render_settings() { + private void render_settings() { ImGui.SliderInt("Font size", ref font_size, 10, 60); if (ImGui.BeginCombo("Voice", voice_lang == 0xFF ? "Default" : ((FhLangId)voice_lang).ToString())) { @@ -1026,34 +909,34 @@ private static void render_settings() { ImGui.Checkbox("Show Recent Items", ref RecentItemsModule.show_recent_items); if (ImGui.Button("Save settings")) { - ArchipelagoFFXModule.VoiceLanguage = voice_lang != 0xFF ? (FhLangId)voice_lang : null; - ArchipelagoFFXModule.TextLanguage = text_lang != 0xFF ? (FhLangId)text_lang : null; - ArchipelagoFFXModule.save_global_state(); + VoiceLanguage = voice_lang != 0xFF ? (FhLangId)voice_lang : null; + TextLanguage = text_lang != 0xFF ? (FhLangId)text_lang : null; + _ffx_interop!.save_global_state(); } ImGui.SeparatorText("Save-Local Settings"); ImGui.Indent(); - if (ArchipelagoFFXModule.seed.Options.SeedId is null) { + if (seed.Options.SeedId is null) { ImGui.Text("Please load a save to display these settings."); ImGui.Unindent(); return; } - bool hardcore_contest = HardcoreDreamsEndModule.get_enabled(); + bool hardcore_contest = _hardcore_dreams_end!.get_enabled(); ImGui.Checkbox("Enable Hardcore Dream's End", ref hardcore_contest); - HardcoreDreamsEndModule.set_enabled(hardcore_contest); + _hardcore_dreams_end!.set_enabled(hardcore_contest); - bool deathlink = DeathLinkModule.get_enabled(); + bool deathlink = _deathlink!.get_enabled(); ImGui.Checkbox("Enable Deathlink", ref deathlink); - DeathLinkModule.set_enabled(deathlink); + _deathlink!.set_enabled(deathlink); - ImGui.Text($"Deathlinks Queued: {DeathLinkModule.get_deathlinks_queued()}"); + ImGui.Text($"Deathlinks Queued: {_deathlink!.get_deathlinks_queued()}"); - string deathlink_send_type = DeathLinkModule.get_send_type(); + string deathlink_send_type = _deathlink!.get_send_type(); if (ImGui.BeginCombo("Deathlink Send Type", deathlink_send_type)) { foreach (DeathLinkModule.DeathLinkSendType type in Enum.GetValues()) { - string type_name = DeathLinkModule.get_send_type_name(type); + string type_name = _deathlink!.get_send_type_name(type); if (ImGui.Selectable(type_name, type_name == deathlink_send_type)) { deathlink_send_type = type_name; } @@ -1061,12 +944,12 @@ private static void render_settings() { ImGui.EndCombo(); } - DeathLinkModule.set_send_type(deathlink_send_type); + _deathlink!.set_send_type(deathlink_send_type); - string deathlink_receive_type = DeathLinkModule.get_receive_type(); + string deathlink_receive_type = _deathlink!.get_receive_type(); if (ImGui.BeginCombo("Deathlink Receive Type", deathlink_receive_type)) { foreach (DeathLinkModule.DeathLinkReceiveType type in Enum.GetValues()) { - string type_name = DeathLinkModule.get_receive_type_name(type); + string type_name = _deathlink!.get_receive_type_name(type); if (ImGui.Selectable(type_name, type_name == deathlink_receive_type)) { deathlink_receive_type = type_name; } @@ -1074,22 +957,22 @@ private static void render_settings() { ImGui.EndCombo(); } - DeathLinkModule.set_receive_type(deathlink_receive_type); + _deathlink!.set_receive_type(deathlink_receive_type); #if DEBUG if (ImGui.Button("Receive Debug Deathlink")) { - DeathLinkModule.debug_add_queued(); + _deathlink!.debug_add_queued(); } if (ImGui.Button("Apply Deathlink")) { - DeathLinkModule.debug_apply_deathlink(); + _deathlink!.debug_apply_deathlink(); } #endif ImGui.Unindent(); } - private static void render_client() { + private void render_client() { enabled ^= ImGui.IsKeyPressed(archipelago_gui_key); if (!enabled) return; ImGuiStylePtr style = ImGui.GetStyle(); @@ -1120,7 +1003,7 @@ private static void render_client() { } else { foreach ((uint item_id, int amount) in excess_inventory) { if (amount == 0) continue; - string item_name = get_item_name(item_id); + string item_name = _ffx_interop!.get_item_name(item_id); ImGui.Text($"{item_name}: {amount}"); } } @@ -1129,7 +1012,7 @@ private static void render_client() { ImGui.Text("Empty"); } else { foreach ((uint item_id, int amount) in other_inventory) { - string item_name = get_other_item_name(item_id); + string item_name = _ffx_interop!.get_other_item_name(item_id); ImGui.Text($"{item_name}: {amount}"); } } @@ -1146,7 +1029,7 @@ private static void render_client() { } #if DEBUG - if (Globals.SphereGrid.lpamng != null && *Globals.SphereGrid.is_open && ImGui.BeginTabItem("Sphere Grid###Archipelago.GUI.TabBar.SphereGrid")) { + if (SphereGrid.lpamng != null && *SphereGrid.is_open && ImGui.BeginTabItem("Sphere Grid###Archipelago.GUI.TabBar.SphereGrid")) { render_sphere_grid_editor(); ImGui.EndTabItem(); } @@ -1162,5 +1045,4 @@ private static void render_client() { ImGui.End(); } - } diff --git a/src/gui/recent_items.cs b/src/gui/recent_items.cs index c5cbcb5..a30d276 100644 --- a/src/gui/recent_items.cs +++ b/src/gui/recent_items.cs @@ -81,25 +81,27 @@ public enum RecentItemsTextAlignment { // Accessing settings through `FhModule.settings` goes through an array, which is rather unpleasant // So `RecentItemsSettings` exists to provide flat access to all settings public class RecentItemsSettings { + //TODO: Uncomment these when the relevant FhSetting types are implemented + public readonly FhSettingToggle display_items = new("display_items", true); public readonly FhSettingToggle display_only_personal = new("display_only_personal", false); public readonly FhSettingToggle display_locations = new("display_locations", true); public readonly FhSettingNumber item_count = new("item_count", 4, 0, 10, 1); - - //TODO: Implement smooth scrolling - public readonly FhSettingDropdown animation = new("interpolation", RecentItemsInterpolation.SMOOTH); - - //TODO: Implement old items fading away + // + // //TODO: Implement smooth scrolling + // public readonly FhSettingDropdown animation = new("interpolation", RecentItemsInterpolation.SMOOTH); + // + // //TODO: Implement old items fading away public readonly FhSettingNumber fade_after = new("fade_after", 10.0f, 0.0f, 60.0f, 1.0f); - public readonly FhSettingDropdown fade_method = new("fade_method", RecentItemsFadeMethod.SLIDE); - - //TODO: Implement different background behavior - public readonly FhSettingDropdown background = new("background", RecentItemsBackground.NONE); - - //TODO: Implement configurable positioning + // public readonly FhSettingDropdown fade_method = new("fade_method", RecentItemsFadeMethod.SLIDE); + // + // //TODO: Implement different background behavior + // public readonly FhSettingDropdown background = new("background", RecentItemsBackground.NONE); + // + // //TODO: Implement configurable positioning public readonly FhSettingNumber pos_x = new("x", 0.05f, 0.0f, 1.0f, 0.1f); public readonly FhSettingNumber pos_y = new("y", 0.34f, 0.0f, 1.0f, 0.1f); - public readonly FhSettingDropdown alignment = new("alignment", RecentItemsTextAlignment.LEFT); + // public readonly FhSettingDropdown alignment = new("alignment", RecentItemsTextAlignment.LEFT); } public RecentItemsSettings module_settings = new(); @@ -290,7 +292,8 @@ public override void render_imgui() { } // Set up Archipelago's font size - int font_size = ArchipelagoGUI.font_size; + //TODO: Access Archipelago's font size instead of always defaulting + int font_size = -1; if (font_size == -1) font_size = (int)ImGui.GetFontSize(); ImGui.PushFont(null, font_size); diff --git a/src/gui/toast.cs b/src/gui/toast.cs index 0fdbf32..8d3273d 100644 --- a/src/gui/toast.cs +++ b/src/gui/toast.cs @@ -275,7 +275,8 @@ public override void render_imgui() { #endif // Set up Archipelago's font size - int font_size = ArchipelagoGUI.font_size; + //TODO: Access Archipelago's font size instead of always defaulting + int font_size = -1; if (font_size == -1) font_size = (int)ImGui.GetFontSize(); ImGui.PushFont(null, font_size); diff --git a/src/hooks.cs b/src/hooks.cs index 6c1e7ed..0435c7a 100644 --- a/src/hooks.cs +++ b/src/hooks.cs @@ -1,520 +1,243 @@ -using Fahrenheit.Atel; +using ArchipelagoFFX.Client; +using Fahrenheit; +using Fahrenheit.Atel; using Fahrenheit.FFX; using Fahrenheit.FFX.Battle; using Fahrenheit.FFX.Ids; - using System; using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; - -using ArchipelagoFFX.Client; -using ArchipelagoFFX.GUI; - -using Fahrenheit; - -using static Fahrenheit.FFX.Globals; using static ArchipelagoFFX.ArchipelagoData; -using static ArchipelagoFFX.Client.FFXArchipelagoClient; -using static ArchipelagoFFX.delegates; +using static Fahrenheit.FFX.Globals; using Color = Archipelago.MultiClient.Net.Models.Color; -using FhCall = Fahrenheit.FFX.FhCall; +using FhGCall = Fahrenheit.FhCall; +using FhXCall = Fahrenheit.FFX.FhCall; namespace ArchipelagoFFX; + public unsafe partial class ArchipelagoFFXModule { + private FhMethodHandle h_Map_800F + => new(new FhMethodLocation("FFX.exe", 0x51B1A0)); + private FhMethodHandle h_Map_show2DLayerResultInt + => new(new FhMethodLocation("FFX.exe", 0x51B1A0)); + private FhMethodHandle h_Map_hide2DLayerResultInt + => new(new FhMethodLocation("FFX.exe", 0x51B1E0)); + private FhMethodHandle h_Common_obtainBrotherhoodRetInt + => new(new FhMethodLocation("FFX.exe", 0x459A40)); + private FhMethodHandle h_Common_obtainTreasureInit + => new(new FhMethodLocation("FFX.exe", 0x45A740)); + private FhMethodHandle h_Common_removePartyMemberLongTerm + => new(new FhMethodLocation("FFX.exe", 0x45AAF0)); + private FhMethodHandle h_Common_setPrimerCollected + => new(new FhMethodLocation("FFX.exe", 0x45AB30)); + private FhMethodHandle h_Common_pushParty + => new(new FhMethodLocation("FFX.exe", 0x45B350)); + private FhMethodHandle h_Common_popParty + => new(new FhMethodLocation("FFX.exe", 0x45B3C0)); + private FhMethodHandle h_Common_addPartyMember + => new(new FhMethodLocation("FFX.exe", 0x45B5A0)); + private FhMethodHandle h_Common_removePartyMember + => new(new FhMethodLocation("FFX.exe", 0x45B6C0)); + private FhMethodHandle h_Common_putPartyMemberInSlot + => new(new FhMethodLocation("FFX.exe", 0x45BC90)); + private FhMethodHandle h_Common_0043 + => new(new FhMethodLocation("FFX.exe", 0x45C810)); + private FhMethodHandle h_Common_linkFieldToBattleActor + => new(new FhMethodLocation("FFX.exe", 0x45CA00)); + private FhMethodHandle h_Common_playFieldVoiceLineInit + => new(new FhMethodLocation("FFX.exe", 0x45CB70)); + private FhMethodHandle h_Common_playFieldVoiceLineExec + => new(new FhMethodLocation("FFX.exe", 0x45CD30)); + private FhMethodHandle h_Common_loadModel + => new(new FhMethodLocation("FFX.exe", 0x45CE70)); + private FhMethodHandle h_Common_playFieldVoiceLineResultInt + => new(new FhMethodLocation("FFX.exe", 0x45D150)); + private FhMethodHandle h_Common_00D6Init + => new(new FhMethodLocation("FFX.exe", 0x45D520)); + private FhMethodHandle h_Common_00D6Exec + => new(new FhMethodLocation("FFX.exe", 0x45D820)); + private FhMethodHandle h_Common_00D6ResultInt + => new(new FhMethodLocation("FFX.exe", 0x45DCF0)); + private FhMethodHandle h_Common_01D1Init + => new(new FhMethodLocation("FFX.exe", 0x45FB60)); + private FhMethodHandle h_Common_01D1Exec + => new(new FhMethodLocation("FFX.exe", 0x45FDB0)); + private FhMethodHandle h_Common_setWeaponInvisible + => new(new FhMethodLocation("FFX.exe", 0x456770)); + private FhMethodHandle h_Common_obtainTreasureSilentlyInit + => new(new FhMethodLocation("FFX.exe", 0x4579E0)); + private FhMethodHandle h_CT_RetInt_0065 + => new(new FhMethodLocation("FFX.exe", 0x457F60)); + private FhMethodHandle h_Common_transitionToMap + => new(new FhMethodLocation("FFX.exe", 0x4580C0)); + private FhMethodHandle h_Common_warpToMap + => new(new FhMethodLocation("FFX.exe", 0x458370)); + private FhMethodHandle h_CT_RetInt_006A + => new(new FhMethodLocation("FFX.exe", 0x4589F0)); + private FhMethodHandle h_CT_RetInt_01B6 + => new(new FhMethodLocation("FFX.exe", 0x4594D0)); + private FhMethodHandle h_Common_upgradeBrotherhoodRetInt + => new(new FhMethodLocation("FFX.exe", 0x4596A0)); + private FhMethodHandle h_SgEvent_showModularMenuInit + => new(new FhMethodLocation("FFX.exe", 0x678210)); + public static int* takara_pointer => FhUtil.ptr_at(0xD35FEC); public static int* buki_get_pointer => FhUtil.ptr_at(0xD35FF4); + public static char* get_event_name(uint event_id) => FhXCall.AtelGetEventName.fnptr!(event_id); + public static int atel_stack_pop(int* arg1, AtelStack* atelStack) => FhXCall.AtelPopStackInteger.fnptr!(arg1, atelStack); - // AtelEventSetUp - private static FhMethodHandle _AtelEventSetUp; - - public static char* get_event_name(uint event_id) => FhUtil.get_fptr(0x4796e0)(event_id); - public static int atel_stack_pop(int* param_1, AtelStack* atelStack) => FhUtil.get_fptr(0x0046de90)(param_1, atelStack); - - private static FhMethodHandle _Common_obtainTreasureInit; - private static FhMethodHandle _Common_obtainTreasureSilentlyInit; - private static FhMethodHandle _Common_isBrotherhoodUnpoweredRetInt; - private static FhMethodHandle _Common_upgradeBrotherhoodRetInt; - private static FhMethodHandle _Common_obtainBrotherhoodRetInt; - //private static FhMethodHandle _Common_grantCelestialUpgrade; - private static FhMethodHandle _Common_setPrimerCollected; - private static FhMethodHandle _Common_transitionToMap; - private static FhMethodHandle _Common_warpToMap; - - private static FhMethodHandle _TkSetLegendAbility; - - private static FhMethodHandle _SgEvent_showModularMenuInit; - - //private static FhMethodHandle _Common_playFieldVoiceLineInit; - //private static FhMethodHandle _Common_playFieldVoiceLineExec; - //private static FhMethodHandle _Common_playFieldVoiceLineResultInt; - - - - private static delegates.Common_playFieldVoiceLineInit _Common_playFieldVoiceLineInit; - private static delegates.Common_playFieldVoiceLineExec _Common_playFieldVoiceLineExec; - private static delegates.Common_playFieldVoiceLineResultInt _Common_playFieldVoiceLineResultInt; - - private static delegates.Common_00D6Init _Common_00D6Init; - private static delegates.Common_00D6Exec _Common_00D6Exec; - private static delegates.Common_00D6ResultInt _Common_00D6ResultInt; - - - // Common.01D1Init - private static delegates.Common_01D1Init _Common_01D1Init; - // Common.01D1Exec - private static delegates.Common_01D1Exec _Common_01D1Exec; - - private static FhMethodHandle _Common_addPartyMember; - private static FhMethodHandle _Common_removePartyMember; - private static FhMethodHandle _Common_removePartyMemberLongTerm; - private static FhMethodHandle _Common_setWeaponVisibilty; - private static FhMethodHandle _Common_putPartyMemberInSlot; - - private static FhMethodHandle _Common_pushParty; - private static FhMethodHandle _Common_popParty; - - // getCurrentPartySlots - private static FhMethodHandle _MsGetSavePartyMember; - - // Battle releated - private static delegates.MsBtlListGroup _MsBtlListGroup; - private static FhMethodHandle _MsBattleExe; - - - public static delegates.MsBattleLabelExe _MsBattleLabelExe; - private static FhMethodHandle _FUN_00791820; - - private static FhMethodHandle _MsBtlGetPos; - - private static FhMethodHandle _MsBtlReadSetScene; - - // giveItem - private static FhMethodHandle _FUN_007905a0; - // giveKeyItem - // takeGil - - - // readFromBin - private static FhMethodHandle _FUN_007ab890; - - // getWeaponName - private static FhMethodHandle _FUN_007a0d10; - // getWeaponModel - private static FhMethodHandle _FUN_007a0c70; - // obtainTreasureCleanup - private static FhMethodHandle _FUN_007993f0; - - private static delegates.MsGetChr _MsGetChr; - private static FhCall.MsGetComData _MsGetComData; - private static FhCall.MsGetCommandUse _MsGetCommandUse; - private static FhCall.MsGetCommandMP _MsGetCommandMP; - private static FhCall.MsGetRamChrMonster _MsGetRamChrMonster; - private static FhCall.TODrawCrossBoxXYWHC2 _TODrawCrossBoxXYWHC2; - - - private static FhMethodHandle _TkMenuAppearMainCmdWindow; - - // Sphere Grid Experiment - private static FhMethodHandle _eiAbmParaGet; - private static FhMethodHandle _MsSetSaveParam; - private static FhMethodHandle _MsSetRamChrParam; - private static FhMethodHandle _FUN_00a48910; - - private static FhMethodHandle _MsApUp; - - - private static FhMethodHandle _openFile; - private static delegates.readFile _readFile; - private static FhMethodHandle _FUN_0070aec0; - - private static FhCall.ChN_ReadSystemMGRP _ChN_ReadSystemMGRP; - private static delegates.Common_loadModel _Common_loadModel; - private static delegates.Common_0043 _Common_0043; - private static delegates.Common_linkFieldToBattleActor _Common_linkFieldToBattleActor; - private static FhCall.SndSepPlay _SndSepPlay; - - - public static delegates.MsGetExcelData _MsGetExcelData; - - private static FhMethodHandle _Map_800F; - - private static FhMethodHandle _FUN_0086bec0; - private static FhMethodHandle _FUN_0086bea0; - - private static FhMethodHandle _graphicInitFMVPlayer; - - private static FhMethodHandle _FUN_00656c90; - private static delegates.FUN_0065ee30 _FUN_0065ee30; - private static delegates.ClusterManager_loadPCluster _ClusterManager_loadPCluster; - private static delegates.Phyre_PFramework_PApplication_FixupClusters _Phyre_PFramework_PApplication_FixupClusters; - private static delegates.ClusterManager_releasePCluster _ClusterManager_releasePCluster; - private static delegates.ClusterManager_getPClusterByName _ClusterManager_getPClusterByName; - private static delegates.fiosUnifyFilename _fiosUnifyFilename; - - - // ObtainTreasure related - private static FhMethodHandle _TkMsImportantSet; - private static delegates.MsPayGIL _MsPayGIL; - private static delegates.SndSepPlaySimple _SndSepPlaySimple; - private static delegates.MsGetSaveWeapon _MsGetSaveWeapon; - private static delegates.FUN_007ab930 _FUN_007ab930; // giveWeapon? - private static delegates.AtelGetCurCtrlWork _AtelGetCurCtrlWork; - private static delegates.MsFieldItemGet _MsFieldItemGet; - private static delegates.TkMsGetRomItem _TkMsGetRomItem; - private static delegates.MsSaveItemUse _MsSaveItemUse; - private static delegates.MsImportantName _MsImportantName; - private static delegates.CT_RetInt_0065 _CT_RetInt_0065; - private static delegates.CT_RetInt_006A _CT_RetInt_006A; - private static FhCall.MsBtlGetInit _MsBtlGetInit; - private static delegates.AtelGetMesWinWork _AtelGetMesWinWork; - private static delegates.FUN_008b8910 _FUN_008b8910; // setMessageWindowVariableType? (0: text*, 1: int) - private static delegates.FUN_008bda20 _FUN_008bda20; // getMenuText - private static delegates.FUN_008b8930 _FUN_008b8930; // setMessageWindowVariable - private static delegates.FUN_0086a0c0 _FUN_0086a0c0; - - - // Voice related - private static FhMethodHandle _FmodVoice_dataChange; - private static delegates.FMOD_EventSystem_load _FMOD_EventSystem_load; - - private static FhMethodHandle _FfxFmod_soundInit_setLang; - private static FhMethodHandle _LocalizationManager_Initialize; - public static delegates.LocalizationManager_GetInstance _LocalizationManager_GetInstance; - public static delegates.FfxFmod_soundInit _FfxFmod_soundInit; - public static delegates.FmodVoice_initList _FmodVoice_initList; - - - // Custom namespace - private static FhMethodHandle _AtelInitTotal; - public static void AtelSetUpCallFunc(int id, nint nameSpacePtr) => FhUtil.get_fptr(__addr_AtelSetUpCallFunc)(id, nameSpacePtr); - - // Airship menu related - public static delegates.FUN_00867370 _FUN_00867370; - public static delegates.FUN_008671d0 _FUN_008671d0; - public static delegates.Map_show2DLayerResultInt _Map_show2DLayerResultInt; - public static delegates.Map_hide2DLayerResultInt _Map_hide2DLayerResultInt; - - // Drawing - public static delegates.TOMkpCrossExtMesFontLClutTypeRGBA _TOMkpCrossExtMesFontLClutTypeRGBA; - public static delegates.ToMakeBtlEasyFont _ToMakeBtlEasyFont; + public static void AtelSetUpCallFunc(int id, nint nameSpacePtr) => FhXCall.AtelSetUpCallFunc.fnptr!(id, nameSpacePtr); public void init_hooks() { - const string game = "FFX.exe"; - - _AtelEventSetUp = new FhMethodHandle(this, game, __addr_AtelEventSetUp, h_AtelEventSetUp); - - _Common_obtainTreasureInit = new FhMethodHandle(this, game, __addr_Common_obtainTreasureInit, h_Common_obtainTreasureInit); - - _Common_obtainTreasureSilentlyInit = new FhMethodHandle(this, game, __addr_Common_obtainTreasureSilentlyInit, h_Common_obtainTreasureSilentlyInit); - - _Common_isBrotherhoodUnpoweredRetInt = new FhMethodHandle(this, game, __addr_CT_RetInt_01B6, h_Common_isBrotherhoodUnpoweredRetInt); - _Common_upgradeBrotherhoodRetInt = new FhMethodHandle(this, game, __addr_CT_RetInt_01B7, h_Common_upgradeBrotherhoodRetInt); - _Common_obtainBrotherhoodRetInt = new FhMethodHandle(this, game, __addr_Common_obtainBrotherhoodRetInt, h_Common_obtainBrotherhoodRetInt); - - _TkSetLegendAbility = new FhMethodHandle(this, game, __addr_TkSetLegendAbility, h_TkSetLegendAbility); - - _Common_setPrimerCollected = new FhMethodHandle(this, game, __addr_Common_setPrimerCollected, h_Common_setPrimerCollected); - - _Common_transitionToMap = new FhMethodHandle(this, game, __addr_Common_transitionToMap, h_Common_transitionToMap); - _Common_warpToMap = new FhMethodHandle(this, game, __addr_Common_warpToMap, h_Common_warpToMap); - - _SgEvent_showModularMenuInit = new FhMethodHandle(this, game, __addr_SgEvent_showModularMenuInit, h_SgEvent_showModularMenuInit); - - - //_Common_playFieldVoiceLineInit = new FhMethodHandle(this, game, h_Common_playFieldVoiceLineInit, offset: 0x0045cb70); - //_Common_playFieldVoiceLineExec = new FhMethodHandle(this, game, h_Common_playFieldVoiceLineExec, offset: 0x0045cd30); - //_Common_playFieldVoiceLineResultInt = new FhMethodHandle(this, game, h_Common_playFieldVoiceLineResultInt, offset: 0x0045d150); - - _Common_playFieldVoiceLineInit = FhUtil.get_fptr (__addr_Common_playFieldVoiceLineInit ); - _Common_playFieldVoiceLineExec = FhUtil.get_fptr (__addr_Common_playFieldVoiceLineExec ); - _Common_playFieldVoiceLineResultInt = FhUtil.get_fptr(__addr_Common_playFieldVoiceLineResultInt); - - _Common_00D6Init = FhUtil.get_fptr (__addr_Common_00D6Init ); - _Common_00D6Exec = FhUtil.get_fptr (__addr_Common_00D6Exec ); - _Common_00D6ResultInt = FhUtil.get_fptr(__addr_Common_00D6ResultInt); - - - - // Common.01D1Init - //_FUN_0085fb60 = new FhMethodHandle(this, game, h_after_voiceline_init, offset: 0x0045fb60); - // Common.01D1Exec - //_FUN_0085fdb0 = new FhMethodHandle(this, game, h_after_voiceline_exec, offset: 0x0045fdb0); - - // Common.01D1Init - _Common_01D1Init = FhUtil.get_fptr(__addr_Common_01D1Init); - // Common.01D1Exec - _Common_01D1Exec = FhUtil.get_fptr(__addr_Common_01D1Exec); - - - - - _Common_addPartyMember = new FhMethodHandle(this, game, 0x0045b5a0, h_Common_addPartyMember); - _Common_removePartyMember = new FhMethodHandle(this, game, 0x0045b6c0, h_Common_removePartyMember); - _Common_removePartyMemberLongTerm = new FhMethodHandle(this, game, 0x0045aaf0, h_Common_removePartyMemberLongTerm); - _Common_setWeaponVisibilty = new FhMethodHandle(this, game, 0x00456770, h_Common_setWeaponInvisible); - _Common_putPartyMemberInSlot = new FhMethodHandle(this, game, 0x0045bc90, h_Common_putPartyMemberInSlot); - - - _Common_pushParty = new FhMethodHandle(this, game, 0x0045b350, h_Common_pushParty); - _Common_popParty = new FhMethodHandle(this, game, 0x0045b3c0, h_Common_popParty); - - // getCurrentPartySlots - _MsGetSavePartyMember = new FhMethodHandle(this, game, __addr_MsGetSavePartyMember, h_MsGetSavePartyMember); - - - _MsBtlListGroup = FhUtil.get_fptr(__addr_MsBtlListGroup); - _MsBattleExe = new FhMethodHandle(this, game, __addr_MsBattleExe, h_MsBattleExe); - _MsBattleLabelExe = FhUtil.get_fptr(__addr_MsBattleLabelExe); - _FUN_00791820 = new FhMethodHandle(this, game, 0x00391820, h_FUN_00791820); - - _MsBtlGetPos = new FhMethodHandle(this, game, 0x003ac000, h_MsBtlGetPos); - - _MsBtlReadSetScene = new FhMethodHandle(this, game, 0x00383ed0, h_MsBtlReadSetScene); - - // giveItem - _FUN_007905a0 = new FhMethodHandle(this, game, 0x003905a0, h_give_item); - - - - // readFromBin - _FUN_007ab890 = new FhMethodHandle(this, game, 0x003ab890, h_read_from_bin); - - // getWeaponName - _FUN_007a0d10 = new FhMethodHandle(this, game, 0x003a0d10, h_get_weapon_name); - // getWeaponModel - _FUN_007a0c70 = new FhMethodHandle(this, game, 0x003a0c70, h_get_weapon_model); - // obtainTreasureCleanup - _FUN_007993f0 = new FhMethodHandle(this, game, 0x003993f0, h_obtain_treasure_cleanup); - - - _MsGetChr = FhUtil.get_fptr(__addr_MsGetChr); - _MsGetComData = FhUtil.get_fptr(FhCall.__addr_MsGetComData); - _MsGetCommandUse = FhUtil.get_fptr(FhCall.__addr_MsGetCommandUse); - _MsGetCommandMP = FhUtil.get_fptr(FhCall.__addr_MsGetCommandMP); - _MsGetRamChrMonster = FhUtil.get_fptr(FhCall.__addr_MsGetRamChrMonster); - _TODrawCrossBoxXYWHC2 = FhUtil.get_fptr(FhCall.__addr_TODrawCrossBoxXYWHC2); - - _eiAbmParaGet = new FhMethodHandle(this, game, __addr_eiAbmParaGet, h_eiAbmParaGet); - _MsSetSaveParam = new FhMethodHandle(this, game, __addr_MsSetSaveParam, h_MsSetSaveParam); - _MsSetRamChrParam = new FhMethodHandle(this, game, __addr_MsSetRamChrParam, h_MsSetRamChrParam); - _FUN_00a48910 = new FhMethodHandle(this, game, 0x00648910, h_FUN_00a48910); - - _MsApUp = new FhMethodHandle(this, game, 0x00398a10, h_MsApUp); - - //delegate* unmanaged[Thiscall] ph_openFile = &h_openFile; - //openFile p_openFile = (x, y, z) => d_openFile(ph_openFile, x, y, z); - //openFile temp = Marshal.GetDelegateForFunctionPointer((nint)ph_openFile); - _openFile = new FhMethodHandle(this, game, 0x00208100, h_openFile); - _readFile = FhUtil.get_fptr(0x00208250); - - _FUN_0070aec0 = new FhMethodHandle(this, game, 0x0030aec0, h_FUN_0070aec0); - - - _ChN_ReadSystemMGRP = FhUtil.get_fptr(FhCall.__addr_ChN_ReadSystemMGRP); - - _Common_loadModel = FhUtil.get_fptr(0x0045ce70); - _Common_0043 = FhUtil.get_fptr(0x0045c810); - _Common_linkFieldToBattleActor = FhUtil.get_fptr(0x0045ca00); - - _SndSepPlay = FhUtil.get_fptr(FhCall.__addr_SndSepPlay); - - - _Map_800F = new FhMethodHandle(this, game, 0x0051b1a0, h_Map_800F); - - - _MsGetExcelData = FhUtil.get_fptr(__addr_MsGetExcelData); - - - // obtainTreasure related - _TkMsImportantSet = new FhMethodHandle(this, game, __addr_TkMsImportantSet, h_TkMsImportantSet); - _MsPayGIL = FhUtil.get_fptr(__addr_MsPayGIL); // takeGil - _SndSepPlaySimple = FhUtil.get_fptr(__addr_SndSepPlaySimple); - _MsGetSaveWeapon = FhUtil.get_fptr(__addr_MsGetSaveWeapon); - _FUN_007ab930 = FhUtil.get_fptr(0x003ab930); // giveWeapon - _AtelGetCurCtrlWork = FhUtil.get_fptr(__addr_AtelGetCurCtrlWork); - _MsFieldItemGet = FhUtil.get_fptr(__addr_MsFieldItemGet); - _TkMsGetRomItem = FhUtil.get_fptr(__addr_TkMsGetRomItem); - _MsSaveItemUse = FhUtil.get_fptr(__addr_MsSaveItemUse); - _MsImportantName = FhUtil.get_fptr(__addr_MsImportantName); - _CT_RetInt_0065 = FhUtil.get_fptr(__addr_CT_RetInt_0065); - _CT_RetInt_006A = FhUtil.get_fptr(__addr_CT_RetInt_006A); - _MsBtlGetInit = FhUtil.get_fptr(FhCall.__addr_MsBtlGetInit); - _AtelGetMesWinWork = FhUtil.get_fptr(__addr_AtelGetMesWinWork); - _FUN_008b8910 = FhUtil.get_fptr(__addr_FUN_008b8910); - _FUN_008bda20 = FhUtil.get_fptr(__addr_FUN_008bda20); - _FUN_008b8930 = FhUtil.get_fptr(__addr_FUN_008b8930); - _FUN_0086a0c0 = FhUtil.get_fptr(__addr_FUN_0086a0c0); - - - _FUN_0086bec0 = new FhMethodHandle(this, game, 0x0046bec0, h_FUN_0086bec0); - _FUN_0086bea0 = new FhMethodHandle(this, game, 0x0046bea0, h_FUN_0086bea0); - - - _FUN_00656c90 = new FhMethodHandle(this, game, 0x00256c90, h_FUN_00656c90); - - _TkMenuAppearMainCmdWindow = new FhMethodHandle(this, game, __addr_TkMenuAppearMainCmdWindow, h_TkMenuAppearMainCmdWindow); - - // For loading texture from game - _FUN_0065ee30 = FhUtil.get_fptr(__addr_ClusterManager_FUN_0065ee30); - _ClusterManager_loadPCluster = FhUtil.get_fptr(__addr_ClusterManager_loadPCluster); - _Phyre_PFramework_PApplication_FixupClusters = FhUtil.get_fptr(__addr_Phyre_PFramework_PApplication_FixupClusters); - _ClusterManager_releasePCluster = FhUtil.get_fptr(__addr_ClusterManager_releasePCluster); - _ClusterManager_getPClusterByName = FhUtil.get_fptr(__addr_ClusterManager_getPClusterByName); - _fiosUnifyFilename = FhUtil.get_fptr(__addr_fiosUnifyFilename); - - // Non-loading FMV - _graphicInitFMVPlayer = new FhMethodHandle(this, game, __addr_graphicInitFMVPlayer, h_graphicInitFMVPlayer); - foreach (byte[] script in customScripts) { customScriptHandles.Add(GCHandle.Alloc(script, GCHandleType.Pinned)); } - - //for (int i = 0; i < rawCustomStrings.Length; i++) { - // byte[] text = rawCustomStrings[i]; - // customStrings[i] = new CustomString(text); - //} - - _FmodVoice_dataChange = new FhMethodHandle(this, game, __addr_FmodVoice_dataChange, h_FmodVoice_dataChange); - var _FMOD_EventSystem_load_pointer = FhUtil.get_at(__addr_FMOD_EventSystem_load); - _FMOD_EventSystem_load = Marshal.GetDelegateForFunctionPointer(_FMOD_EventSystem_load_pointer); - //_FMOD_EventSystem_load = new FhMethodHandle(this, _FMOD_EventSystem_load_pointer, h_FMOD_EventSystem_load); - - //_FfxFmod_soundInit_setLang = new FhMethodHandle(this, game, __addr_FfxFmod_soundInit_setLang, h_FfxFmod_soundInit_setLang); - - _LocalizationManager_Initialize = new FhMethodHandle(this, game, __addr_LocalizationManager_Initialize, h_LocalizationManager_Initialize); - _LocalizationManager_GetInstance = FhUtil.get_fptr(__addr_LocalizationManager_GetInstance); - _FfxFmod_soundInit = FhUtil.get_fptr(__addr_FfxFmod_soundInit); - _FmodVoice_initList = FhUtil.get_fptr(__addr_FmodVoice_initList); - - - // Custom namespace - _AtelInitTotal = new FhMethodHandle(this, game, __addr_AtelInitTotal, h_AtelInitTotal); - - // Airship - _FUN_00867370 = FhUtil.get_fptr(__addr_FUN_00867370); - _FUN_008671d0 = FhUtil.get_fptr(__addr_FUN_008671d0); - _Map_show2DLayerResultInt = FhUtil.get_fptr(__addr_Map_show2DLayerResultInt); - _Map_hide2DLayerResultInt = FhUtil.get_fptr(__addr_Map_hide2DLayerResultInt); - - // Drawing - _TOMkpCrossExtMesFontLClutTypeRGBA = FhUtil.get_fptr(__addr_TOMkpCrossExtMesFontLClutTypeRGBA); - _ToMakeBtlEasyFont = FhUtil.get_fptr(__addr_ToMakeBtlEasyFont); - - _PrepareMenuList = new FhMethodHandle(this, game, __addr_PrepareMenuList, h_PrepareMenuList); - _UpdateGearCustomizationMenuState = new FhMethodHandle(this, game, __addr_UpdateGearCustomizationMenuState, h_UpdateGearCustomizationMenuState); - _UpdateAeonCustomizationMenuState = new FhMethodHandle(this, game, __addr_UpdateAeonCustomizationMenuState, h_UpdateAeonCustomizationMenuState); - _DrawGearCustomizationMenu = new FhMethodHandle(this, game, __addr_DrawGearCustomizationMenu, h_DrawGearCustomizationMenu); - _DrawAeonCustomizationMenu = new FhMethodHandle(this, game, __addr_DrawAeonCustomizationMenu, h_DrawAeonCustomizationMenu); - _MsGetRomKaizou = FhUtil.get_fptr(__addr_MsGetRomKaizou); - _MsGetRomAbility = FhUtil.get_fptr(__addr_MsGetRomAbility); - _MsGetRomSummonGrow = FhUtil.get_fptr(__addr_MsGetRomSummonGrow); - _TkMn2GetSummonGrowMax = FhUtil.get_fptr(__addr_TkMn2GetSummonGrowMax); - _TkMenuGetCurrentSummon = FhUtil.get_fptr(__addr_TkMenuGetCurrentSummon); - _MsGetSaveCommand = FhUtil.get_fptr(__addr_MsGetSaveCommand); - - _FUN_008c1c70 = FhUtil.get_fptr(__addr_FUN_008c1c70); - _TODrawMenuPlateXYWHType = FhUtil.get_fptr(__addr_TODrawMenuPlateXYWHType); - _FUN_008f8bb0 = FhUtil.get_fptr(__addr_FUN_008f8bb0); - _TODrawScissorXYWH = FhUtil.get_fptr(__addr_TODrawScissorXYWH); - _FUN_008d5d20 = FhUtil.get_fptr(__addr_FUN_008d5d20); - _FUN_008c0f40 = FhUtil.get_fptr(__addr_FUN_008c0f40); - _FUN_008c1350_DrawScissor512x416 = FhUtil.get_fptr(__addr_FUN_008c1350_DrawScissor512x416); - _FUN_008d5dc0 = FhUtil.get_fptr(__addr_FUN_008d5dc0); - _DrawCrossMenuScrollParts = FhUtil.get_fptr(__addr_DrawCrossMenuScrollParts); - _FUN_008d6630 = FhUtil.get_fptr(__addr_FUN_008d6630); - - _TkVU1SyncPath = FhUtil.get_fptr(__addr_TkVU1SyncPath); - _FUN_008e71d0 = FhUtil.get_fptr(__addr_FUN_008e71d0); - _FUN_008ff490 = FhUtil.get_fptr(__addr_FUN_008ff490); - _FUN_008cd960 = FhUtil.get_fptr(__addr_FUN_008cd960); - _FUN_008cd9f0 = FhUtil.get_fptr(__addr_FUN_008cd9f0); - _ToGetCrossExtMesFontWidth = FhUtil.get_fptr(__addr_ToGetCrossExtMesFontWidth); - _FUN_008bee80 = FhUtil.get_fptr(__addr_FUN_008bee80); - _TOMkpShapeXYWHUV = FhUtil.get_fptr(__addr_TOMkpShapeXYWHUV); - _TOMkpCrossExtMesFontLClut = FhUtil.get_fptr(__addr_TOMkpCrossExtMesFontLClut); - _FUN_008d48e0 = FhUtil.get_fptr(__addr_FUN_008d48e0); - _FUN_008d4140 = FhUtil.get_fptr(__addr_FUN_008d4140); - _TkMn2DrawKickSyncPacket = FhUtil.get_fptr(__addr_TkMn2DrawKickSyncPacket); - - _TkMenuMainAllocWindow = FhUtil.get_fptr(__addr_TkMenuMainAllocWindow); - _TkMenuMainRegistWindow = FhUtil.get_fptr(__addr_TkMenuMainRegistWindow); - - _FUN_008e33a0 = FhUtil.get_fptr(__addr_FUN_008e33a0); - _FUN_008b4460 = FhUtil.get_fptr(__addr_FUN_008b4460); - _FUN_008e2de0 = FhUtil.get_fptr(__addr_FUN_008e2de0); - _MsSetSaveParamAll = FhUtil.get_fptr(__addr_MsSetSaveParamAll); - _MsSetWeaponName = FhUtil.get_fptr(__addr_MsSetWeaponName); - _FUN_008c2c40 = FhUtil.get_fptr(__addr_FUN_008c2c40); - _TkMn2DrawCrossCursor = FhUtil.get_fptr(__addr_TkMn2DrawCrossCursor); - - _FUN_008d5720 = new FhMethodHandle(this, game, __addr_FUN_008d5720, h_FUN_008d5720); } public static int ignore_this = 11; - public static int h_Map_800F(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int h_Map_800F_reimpl(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int param_1 = atelStack->values.as_int()[0]; if (param_1 == ignore_this) { atelStack->pop_int(); return 1; } - return _Map_800F.orig_fptr(work, storage, atelStack); + return h_Map_800F.chain_from(h_Map_800F_reimpl).fnptr!(work, storage, atelStack); } - public static bool h_openFile(nint _this, nint filename, bool readOnly, nint unknown_1, nint unknown_2, nint unknown_3) { - string x = Marshal.PtrToStringAnsi(filename); - logger.Debug($"{_this}, {x}, {readOnly}, {unknown_1}, {unknown_2}, {unknown_3}"); - var result = _openFile.orig_fptr(_this, filename, readOnly, unknown_1, unknown_2, unknown_3); - logger.Debug($"{result}, {*(int*)_this}, {*(int*)((int)_this + 4)}"); - return result; + //public bool h_openFile(nint _this, nint filename, bool readOnly, nint unknown_1, nint unknown_2, nint unknown_3) { + // string x = Marshal.PtrToStringAnsi(filename)!; + // _logger.Debug($"{_this}, {x}, {readOnly}, {unknown_1}, {unknown_2}, {unknown_3}"); + // var result = FhXCall.Phyre_PSerialization_PStreamFileWin32_Open.chain_from(h_openFile).fnptr!(_this, filename, readOnly, unknown_1, unknown_2, unknown_3); + // _logger.Debug($"{result}, {*(int*)_this}, {*(int*)((int)_this + 4)}"); + // return result; + //} + + public uint h_FUN_0070aec0(nint _this, uint voice_id, uint param_2) { + return FhXCall.FUN_0070aec0.chain_from(h_FUN_0070aec0).fnptr!(_this, voice_id, param_2); } - public static uint h_FUN_0070aec0(nint _this, uint voice_id, uint param_2) { + private FhGCall.d_CT_RetInt[] custom_ct_retints; + private int turnAroundScriptLength; + private byte* turnAroundScript; + private void init_custom_atel() { + custom_ct_retints = [ + CT_RetInt_PushInt, + CT_RetInt_PushFloat, + CT_RetInt_IsCharacterUnlocked, + CT_RetInt_HasCelestialWeapon, + CT_RetInt_IsOtherLocationChecked, + CT_RetInt_IsTreasureLocationChecked, + CT_RetInt_CollectedPrimers, + CT_RetInt_SendOtherLocation, + CT_RetInt_SendPartyMemberLocation, + CT_RetInt_SendRecruitLocation, + CT_RetInt_BlockWarp, + CT_RetInt_BlockKilikaBoatChoice, + CT_RetInt_RestoreInteraction, + CT_RetInt_SetAirshipDestinations, + CT_RetInt_ShowAirshipDestinations, + CT_RetInt_HideAirshipDestinations, + CT_RetInt_ShowCurrentAirshipLocation, + CT_RetInt_HideCurrentAirshipLocation, + CT_RetInt_TransitionToRegion, + CT_RetInt_Jump, + CT_RetInt_JumpIfFalse, + CT_RetInt_JumpIfTrue, + CT_RetInt_Offset, + CT_RetInt_OffsetIfFalse, + CT_RetInt_OffsetIfTrue, + CT_RetInt_UpdateRegionState, + CT_RetInt_LockPartyMember, + CT_RetInt_LockAllAeons, + CT_RetInt_IsGoalUnlocked, + CT_RetInt_ReplaceEntryPoint, + CT_RetInt_RestoreEntryPoint, + CT_RetInt_LightningDodging, + CT_RetInt_JechtSphere, + CT_RetInt_KickedBlitzballAway, + CT_RetInt_CheckUnlockedAeons, + ]; + + customNameSpace = new AtelCallTarget[custom_ct_retints.Length]; + + for (int i = 0; i < custom_ct_retints.Length; i++) { + customNameSpace[i].ret_int_func = Marshal.GetFunctionPointerForDelegate(custom_ct_retints[i]); + } + + customNameSpaceHandle = GCHandle.Alloc(customNameSpace, GCHandleType.Pinned); + + turnAroundScriptLength = atelTurnAround(Span.Empty, 0, 0, 0, 0, 0, 0); + turnAroundScript = (byte*)NativeMemory.AllocZeroed((uint)turnAroundScriptLength); - return _FUN_0070aec0.orig_fptr(_this, voice_id, param_2); } - public bool hook() { - return _Common_obtainTreasureInit.hook() && _Common_obtainTreasureSilentlyInit.hook() && _Common_obtainBrotherhoodRetInt.hook() - && _TkSetLegendAbility.hook() && _Common_setPrimerCollected.hook() - && _AtelEventSetUp.hook() && _Common_transitionToMap.hook() && _Common_warpToMap.hook() - && _SgEvent_showModularMenuInit.hook() - && _Common_addPartyMember.hook() && _Common_removePartyMember.hook() && _Common_removePartyMemberLongTerm.hook() && _Common_setWeaponVisibilty.hook() - && _Common_putPartyMemberInSlot.hook() && _Common_pushParty.hook() && _Common_popParty.hook() && _MsBattleExe.hook() && _FUN_00791820.hook() - && _MsApUp.hook() && _MsBtlReadSetScene.hook() // && _Map_800F.hook() //_MsBtlGetPos.hook() - && _eiAbmParaGet.hook() && _MsSetSaveParam.hook() && _MsSetRamChrParam.hook() // && _FUN_00a48910.hook() - && _FUN_0086bec0.hook() && _FUN_0086bea0.hook() // Custom strings - && _graphicInitFMVPlayer.hook() && _FmodVoice_dataChange.hook() - && _AtelInitTotal.hook() - && _LocalizationManager_Initialize.hook() - && _TkMenuAppearMainCmdWindow.hook() - && _PrepareMenuList.hook() && _UpdateGearCustomizationMenuState.hook() && _DrawGearCustomizationMenu.hook() - && _UpdateAeonCustomizationMenuState.hook() && _DrawAeonCustomizationMenu.hook() && _FUN_008d5720.hook(); - //&& _FUN_00656c90.hook() && _FUN_0065ee30.hook(); - //&& _openFile.hook() && _FUN_0070aec0.hook(); - //&& _MsCheckLeftWindow.hook() && _MsCheckUseCommand.hook() && _TOBtlDrawStatusLimitGauge.hook(); + private bool hook() { + FhApi.Events.Common.GameLoop.PreUpdate.subscribe(handle_input); + + return h_Common_obtainTreasureInit.hook(this, Common_obtainTreasureInit) + && h_Common_obtainTreasureSilentlyInit.hook(this, Common_obtainTreasureSilentlyInit) + && h_Common_obtainBrotherhoodRetInt.hook(this, Common_obtainBrotherhoodRetInt) + && h_Common_setPrimerCollected.hook(this, Common_setPrimerCollected) + && h_Common_transitionToMap.hook(this, Common_transitionToMap) + && h_Common_warpToMap.hook(this, Common_warpToMap) + && h_SgEvent_showModularMenuInit.hook(this, SgEvent_showModularMenuInit) + && h_Common_addPartyMember.hook(this, Common_addPartyMember) + && h_Common_removePartyMember.hook(this, Common_removePartyMember) + && h_Common_removePartyMemberLongTerm.hook(this, Common_removePartyMemberLongTerm) + && h_Common_setWeaponInvisible.hook(this, Common_setWeaponInvisible) + && h_Common_putPartyMemberInSlot.hook(this, Common_putPartyMemberInSlot) + && h_Common_pushParty.hook(this, Common_pushParty) + && h_Common_popParty.hook(this, Common_popParty) + && FhXCall.TkSetLegendAbility.hook(this, TkSetLegendAbility) + && FhXCall.AtelEventSetUp.hook(this, AtelEventSetUp) + && FhXCall.MsBattleExe.hook(this, MsBattleExe) + && FhXCall.FUN_00791820.hook(this, FUN_00791820) + && FhXCall.MsApUp.hook(this, MsApUp) + && FhXCall.MsBtlReadSetScene.hook(this, MsBtlReadSetScene) + && FhXCall.eiAbmParaGet.hook(this, eiAbmParaGet) + && FhXCall.MsSetSaveParam.hook(this, MsSetSaveParam) + && FhXCall.MsSetRamChrParam.hook(this, MsSetRamChrParam) + && FhXCall.FUN_0086bec0.hook(this, FUN_0086bec0) + && FhXCall.FUN_0086bea0.hook(this, FUN_0086bea0) // Custom strings + && FhXCall.graphicInitFMVPlayer.hook(this, graphicInitFMVPlayer) + && FhXCall.FmodVoice_dataChange.hook(this, FmodVoice_dataChange) + && FhXCall.AtelInitTotal.hook(this, AtelInitTotal) + && FhXCall.LocalizationManager_Initialize.hook(this, LocalizationManager_Initialize) + && FhXCall.TkMenuAppearMainCmdWindow.hook(this, TkMenuAppearMainCmdWindow) + && FhXCall.FUN_008c2370.hook(this, PrepareMenuList) + && FhXCall.UpdateGearCustomizationMenuState.hook(this, UpdateGearCustomizationMenuState) + && FhXCall.DrawGearCustomizationMenu.hook(this, DrawGearCustomizationMenu) + && FhXCall.TkMenuCtrlSummon.hook(this, TkMenuCtrlSummon) + && FhXCall.FUN_008cdb70.hook(this, DrawAeonCustomizationMenu) + && FhXCall.FUN_008d5720.hook(this, FUN_008d5720) + && FhXCall.TODrawWindow.hook(this, render_game); + // && _FUN_00656c90.hook() && _FUN_0065ee30.hook(); + // && _openFile.hook() && _FUN_0070aec0.hook(); + // && _MsCheckLeftWindow.hook() && _MsCheckUseCommand.hook() && _TOBtlDrawStatusLimitGauge.hook(); + // && Map_800F //MsBtlGetPos + // && FUN_00a48910 } - private static void set(byte* code_ptr, uint offset, AtelInst opcode) { + private void set(byte* code_ptr, uint offset, AtelInst opcode) { byte* ptr = code_ptr + offset; foreach (byte b in opcode.to_bytes()) { *ptr = b; ptr++; } } - private static void set(byte* code_ptr, uint[] offsets, AtelInst opcode) { + private void set(byte* code_ptr, uint[] offsets, AtelInst opcode) { foreach (uint offset in offsets) { set(code_ptr, offset, opcode); } } - private static void set(byte* code_ptr, uint offset, AtelInst[] opcodes) { + private void set(byte* code_ptr, uint offset, AtelInst[] opcodes) { byte* ptr = code_ptr + offset; foreach (AtelInst op in opcodes) { foreach (byte b in op.to_bytes()) { @@ -523,13 +246,13 @@ private static void set(byte* code_ptr, uint offset, AtelInst[] opcodes) { } } } - private static void set(byte* code_ptr, uint[] offsets, AtelInst[] opcodes) { + private void set(byte* code_ptr, uint[] offsets, AtelInst[] opcodes) { foreach (uint offset in offsets) { set(code_ptr, offset, opcodes); } } - private static void move(byte* code_ptr, uint sourceOffset, int moveBy, int size) { + private void move(byte* code_ptr, uint sourceOffset, int moveBy, int size) { Span source = new(code_ptr + sourceOffset , size); Span destination = new(code_ptr + sourceOffset + moveBy, size); @@ -551,9 +274,7 @@ private static void move(byte* code_ptr, uint sourceOffset, int moveBy, int size temp.CopyTo(destinationDestination); } - - - private static byte* h_FUN_0086bec0(int param_1) { + private byte* FUN_0086bec0(int param_1) { byte* result; if ((param_1 & 0x8000) != 0) { int custom_index = param_1 & 0x7FFF; @@ -561,22 +282,23 @@ private static void move(byte* code_ptr, uint sourceOffset, int moveBy, int size //result = (byte*)customStringHandles[custom_index].AddrOfPinnedObject(); //FhEncoding.compute_decode_buffer_size(result); //string decoded = FhEncoding.Us.to_string(result); - logger.Debug(customStrings[custom_index].decoded); + _logger.Debug(customStrings[custom_index].decoded); } else { // May crash if called with invalid index - result = _FUN_0086bec0.orig_fptr(param_1); + result = FhXCall.FUN_0086bec0.chain_from(FUN_0086bec0).fnptr!(param_1); } return result; } - private static short h_FUN_0086bea0(int param_1) { + + private short FUN_0086bea0(int param_1) { short result; if ((param_1 & 0x8000) != 0) { int custom_index = param_1 & 0x7FFF; result = customStrings[custom_index].metadata; } else { - result = _FUN_0086bea0.orig_fptr(param_1); + result = FhXCall.FUN_0086bea0.chain_from(FUN_0086bea0).fnptr!(param_1); } return result; @@ -730,6 +452,7 @@ AtelOp.PUSHII .build((ushort)(value >> 16)), AtelOp.CALLPOPA.build((ushort)CustomCallTarget.PUSH_INT), ]; } + private static AtelInst[] atelPushFloat(float value) { int as_int = BitConverter.SingleToInt32Bits(value); return [ @@ -738,6 +461,7 @@ AtelOp.PUSHII .build((ushort)(as_int >> 16)), AtelOp.CALLPOPA.build((ushort)CustomCallTarget.PUSH_FLOAT), ]; } + private static AtelInst[] atelPushIntAsFloat(uint value) { return [ AtelOp.PUSHII .build((ushort)(value & 0xffff)), @@ -755,8 +479,8 @@ private static AtelInst[] atelNOPArray(uint n) { return temp; } - private static readonly List customScriptHandles = []; - private static readonly byte[][] customScripts = { + private readonly List customScriptHandles = []; + private readonly byte[][] customScripts = { // Cid talk hook ((AtelInst[])[ // 0 // If GameMoment < 2970 or GameMoment >= 3120: Jump to j01 (return) @@ -1173,7 +897,7 @@ AtelOp.RET .build( ), // Check Nemesis requirements ((AtelInst[])[ // C - + // !!!(MonsterArenaOriginalCreationUnlockFlags[0] & 128 [80h]) AtelOp.PUSHII .build(0x0000), AtelOp.PUSHAR .build(0x000C), @@ -1435,8 +1159,8 @@ AtelOp.PUSHII .build(0x50AB), private static Dictionary<(int, int), uint> originalEntryPoints = new(); private static string current_event_name = ""; - private static void h_AtelEventSetUp(int event_id) { - _AtelEventSetUp.orig_fptr(event_id); + private void AtelEventSetUp(int event_id) { + FhXCall.AtelEventSetUp.chain_from(AtelEventSetUp).fnptr!(event_id); foreach (NativeCustomString customString in cached_strings) { customString.Free(); @@ -1450,7 +1174,7 @@ private static void h_AtelEventSetUp(int event_id) { } string event_name = Marshal.PtrToStringAnsi((nint)get_event_name((uint)event_id))!; - logger.Debug($"atel_event_setup: {event_name}"); + _logger.Debug($"atel_event_setup: {event_name}"); byte* code_ptr = Globals.Atel.controllers[0].worker(0)->code_ptr; switch (event_name) { case "bjyt1200": @@ -1475,7 +1199,7 @@ .. atelNOPArray(1), ]); break; case "hiku2100": - logger.Debug($"atel_event_setup: Inject set_airship_destinations call"); + _logger.Debug($"atel_event_setup: Inject set_airship_destinations call"); set(code_ptr, 0x26D1, [ .. atelNOPArray(3), AtelOp.CALLPOPA.build((ushort)CustomCallTarget.SET_AIRSHIP_DESTINATIONS), @@ -1570,7 +1294,7 @@ AtelOp.PUSHII .build((ushort)region), break; case "hiku0801": - logger.Debug($"atel_event_setup: Inject Cid talk hook"); + _logger.Debug($"atel_event_setup: Inject Cid talk hook"); set(code_ptr, 0x4DC5, [ AtelOp.PUSHII .build(0x0000), AtelOp.CALLPOPA.build((ushort)CustomCallTarget.JUMP), // Common.Jump(0000) = jump to customScripts[0] @@ -1581,11 +1305,11 @@ AtelOp.PUSHII .build(0x0000), set(code_ptr, 0x5869, AtelOp.CALL.build((ushort)CustomCallTarget.COLLECTED_PRIMERS)); break; case "ssbt0300": - logger.Debug($"atel_event_setup: Redirect Overdrive Sin post-battle warp"); + _logger.Debug($"atel_event_setup: Redirect Overdrive Sin post-battle warp"); set(code_ptr, 0x500E, AtelOp.PUSHII.build(382)); break; case "sins0700": - logger.Debug($"atel_event_setup: Handle removing Aeons"); + _logger.Debug($"atel_event_setup: Handle removing Aeons"); // Lock all Aeons and skip Contest of Aeons if (seed.Options.SkipContestOfAeons == 1) { @@ -1611,7 +1335,7 @@ AtelOp.PUSHII .build(0x000A), ]); break; case "luca0400": - logger.Debug($"atel_event_setup: Wait longer"); + _logger.Debug($"atel_event_setup: Wait longer"); set(code_ptr, 0x68F9, [ AtelOp.PUSHII .build(10), AtelOp.CALLPOPA.build( 0), @@ -2134,7 +1858,7 @@ AtelOp.NOP .build(), // Inject save sphere hook if (event_name == "nagi0000") { uint save_sphere_offset = 0x1BB69; - logger.Info($"Save sphere init at {save_sphere_offset}"); + _logger.Info($"Save sphere init at {save_sphere_offset}"); set(code_ptr, save_sphere_offset + 0x48, AtelOp.JMP.build(0x0007)); // Always all options // Update region state. Also skips save sphere tutorial @@ -2160,7 +1884,7 @@ AtelOp.PUSHII .build( 0), } else if (event_name == "cdsp0700") { uint save_sphere_offset = 0x2AA3; - logger.Info($"Underwater save sphere init at {save_sphere_offset}"); + _logger.Info($"Underwater save sphere init at {save_sphere_offset}"); set(code_ptr, save_sphere_offset + 0x5A, AtelOp.JMP.build(0x0002)); // Always all options // Update region state. Also skips save sphere tutorial @@ -2186,7 +1910,7 @@ AtelOp.PUSHII .build( 0), } else if (event_name == "stbv0000") { uint save_sphere_offset = 0x2982; - logger.Info($"Underwater save sphere init at {save_sphere_offset}"); + _logger.Info($"Underwater save sphere init at {save_sphere_offset}"); set(code_ptr, save_sphere_offset + 0x5A, AtelOp.JMP.build(0x0002)); // Always all options // Update region state. Also skips save sphere tutorial @@ -2211,7 +1935,7 @@ AtelOp.PUSHII .build( 0), save_sphere_offset = 0x3168; - logger.Info($"Underwater save sphere init at {save_sphere_offset}"); + _logger.Info($"Underwater save sphere init at {save_sphere_offset}"); set(code_ptr, save_sphere_offset + 0x5A, AtelOp.JMP.build(0x0002)); // Always all options // Update region state. Also skips save sphere tutorial @@ -2236,7 +1960,7 @@ AtelOp.PUSHII .build( 0), } else if (false && event_name == "stbv0100") { uint save_sphere_offset = 0xF07F; - logger.Info($"Save sphere init at {save_sphere_offset}"); + _logger.Info($"Save sphere init at {save_sphere_offset}"); set(code_ptr, save_sphere_offset + 0x48, AtelOp.JMP.build(0x0007)); // Always all options // Update region state. Also skips save sphere tutorial @@ -2261,7 +1985,7 @@ AtelOp.PUSHII .build( 0), save_sphere_offset = 0xFCF1; - logger.Info($"Save sphere init at {save_sphere_offset}"); + _logger.Info($"Save sphere init at {save_sphere_offset}"); set(code_ptr, save_sphere_offset + 0x48, AtelOp.JMP.build(0x0007)); // Always all options // Update region state. Also skips save sphere tutorial @@ -2302,7 +2026,7 @@ AtelOp.JMP .build(0x0000), AtelBasicWorker* save_sphere_worker_1 = Globals.Atel.current_controller->worker(0x13); // Custom switch save_sphere_worker_1->table_jump[1] = (uint)(customScriptHandles[6].AddrOfPinnedObject() - (nint)save_sphere_worker_1->code_ptr); - logger.Debug($"{save_sphere_worker_1->table_var[1].raw}"); + _logger.Debug($"{save_sphere_worker_1->table_var[1].raw}"); save_sphere_worker_1->table_var[1].raw = 0x0000000100000A98; AtelBasicWorker* save_sphere_worker_2 = Globals.Atel.current_controller->worker(0x14); @@ -2342,15 +2066,15 @@ AtelOp.JMP .build(0x0000), } else if (save_spheres_detected > 1) { // Potentially incorrect offsets - logger.Info("Potentially incorrect Save Sphere offsets"); + _logger.Info("Potentially incorrect Save Sphere offsets"); } save_spheres_detected++; - logger.Info($"Detected save sphere init at {i - 6}"); + _logger.Info($"Detected save sphere init at {i - 6}"); uint save_sphere_offset = i - 6; AtelOp someInst = (AtelOp)code_ptr[save_sphere_offset + sphere_level_offset]; if (!someInst.has_operand() || someInst.build(*(ushort*)(code_ptr + save_sphere_offset + sphere_level_offset + 1)) != AtelOp.PUSHV.build(0x0000)) { - logger.Warning($"Unexpected instruction at {save_sphere_offset + sphere_level_offset}"); + _logger.Warning($"Unexpected instruction at {save_sphere_offset + sphere_level_offset}"); } set(code_ptr, save_sphere_offset + sphere_level_offset, AtelOp.JMP.build(0x0007)); // Always all options @@ -2358,7 +2082,7 @@ AtelOp.JMP .build(0x0000), someInst = (AtelOp)code_ptr[save_sphere_offset + tutorial_offset + 13]; if (!someInst.has_operand() || someInst.build(*(ushort*)(code_ptr + save_sphere_offset + tutorial_offset + 13 + 1)) != AtelOp.POPXNCJMP.build(tutorial_jump)) { - logger.Warning($"Unexpected instruction at {save_sphere_offset + tutorial_offset + 13}"); + _logger.Warning($"Unexpected instruction at {save_sphere_offset + tutorial_offset + 13}"); } // Update region state. Also skips save sphere tutorial set(code_ptr, save_sphere_offset + tutorial_offset, [ @@ -2369,7 +2093,7 @@ AtelOp.JMP .build(tutorial_jump), someInst = (AtelOp)code_ptr[save_sphere_offset + airship_warp_offset]; if (!someInst.has_operand() || someInst.build(*(ushort*)(code_ptr + save_sphere_offset + airship_warp_offset + 1)) != AtelOp.PUSHV.build(0x0000)) { - logger.Warning($"Unexpected instruction at {save_sphere_offset + airship_warp_offset}"); + _logger.Warning($"Unexpected instruction at {save_sphere_offset + airship_warp_offset}"); } // Board Airship option set(code_ptr, save_sphere_offset + airship_warp_offset, [ @@ -2393,44 +2117,43 @@ AtelOp.PUSHII .build( 0), current_event_name = event_name; } - private static void h_Common_obtainTreasureInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + private void Common_obtainTreasureInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int treasure_id = atelStack->values.as_int()[1]; - logger.Info($"obtain_treasure: {treasure_id}"); - //_Common_obtainTreasureInit.orig_fptr(work, storage, atelStack); + _logger.Info($"obtain_treasure: {treasure_id}"); + //FhXCall.Common_obtainTreasureInit.chain_from(h_Common_obtainTreasureInit).fnptr!(work, storage, atelStack); obtainTreasureInitReimplement(work, storage, atelStack); } - private static void obtainTreasureInitReimplement(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + private void obtainTreasureInitReimplement(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { byte* item_name = (byte*)0; int treasure_id = atelStack->pop_int(); int window_id = atelStack->pop_int(); - logger.Debug($"window_id:{window_id}, treasure_id:{treasure_id}"); + _logger.Debug($"window_id:{window_id}, treasure_id:{treasure_id}"); - _SndSepPlaySimple(0x80000026); - AtelWorkerController* pAVar2 = (AtelWorkerController*)_AtelGetCurCtrlWork(); + FhXCall.SndSepPlaySimple.fnptr!(0x80000026); + AtelWorkerController* pAVar2 = (AtelWorkerController*)FhXCall.AtelGetCurCtrlWork.fnptr!(); ((byte*)pAVar2)[3] |= 4; - _MsFieldItemGet(treasure_id); - _FUN_008b8910(window_id, 0, 0); - _FUN_008b8910(window_id, 1, 1); + FhXCall.MsFieldItemGet.fnptr!(treasure_id); + FhXCall.FUN_008b8910.fnptr!(window_id, 0, 0); + FhXCall.FUN_008b8910.fnptr!(window_id, 1, 1); bool gear_inv_is_full = false; uint weapon_id = 0; - byte* message_text = _FUN_008bda20(0x401d); // "Nothing" - + byte* message_text = FhXCall.TkBtlEndGetText.fnptr!(0x401d); // "Nothing" if (item_locations.treasure.TryGetValue(treasure_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(treasure_id, FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { + if (_client!.sendLocation(treasure_id, ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { obtain_item(item.id); NativeCustomString name = new NativeCustomString(item.id != 0 ? item.name : $"{item.name} to {item.player}", encodingFlags: FhEncodingFlags.IGNORE_EXPRESSIONS); //CustomString name = new CustomString(item.name, encodingFlags: FhEncodingFlags.IGNORE_EXPRESSIONS); - logger.Info(item.name); + _logger.Info(item.name); cached_strings.Add(name); item_name = name.encoded; if (item.id != 0) { - message_text = _FUN_008bda20(0x4018); // "Obtained %0!" + message_text = FhXCall.TkBtlEndGetText.fnptr!(0x4018); // "Obtained %0!" } else { NativeCustomString sent_text = new NativeCustomString("Sent {VAR:00}!"); //CustomString sent_text = new CustomString("Sent {VAR:00} to {VAR:01}!"); @@ -2449,50 +2172,50 @@ private static void obtainTreasureInitReimplement(AtelBasicWorker* work, int* st } else if (Battle.reward_data->item_count != 0) { - _TkMsGetRomItem(Battle.reward_data->items[0], (int*)&item_name); - _FUN_008b8930(window_id, 1, Battle.reward_data->items_amounts[0]); + FhXCall.TkMsGetRomItem.fnptr!(Battle.reward_data->items[0], (int*)&item_name); + FhXCall.FUN_008b8930.fnptr!(window_id, 1, Battle.reward_data->items_amounts[0]); if (Battle.reward_data->items_amounts[0] == 1) { - message_text = _FUN_008bda20(0x4018); // "Obtained %0!" + message_text = FhXCall.TkBtlEndGetText.fnptr!(0x4018); // "Obtained %0!" } else { - message_text = _FUN_008bda20(0x4019); // "Obtained %0 x%1!" + message_text = FhXCall.TkBtlEndGetText.fnptr!(0x4019); // "Obtained %0 x%1!" } byte[] decoded = new byte[FhEncoding.compute_decode_buffer_size(new ReadOnlySpan(item_name, 1000))]; int decoded_length = FhEncoding.decode(new ReadOnlySpan(item_name, 1000), decoded, flags:FhEncodingFlags.IMPLICIT_END); //string decoded = FhEncoding.Us.to_string(item_name); - logger.Info(Encoding.UTF8.GetString(decoded, 0, decoded_length)); + _logger.Info(Encoding.UTF8.GetString(decoded, 0, decoded_length)); - _MsSaveItemUse(Battle.reward_data->items[0], Battle.reward_data->items_amounts[0]); + FhXCall.MsSaveItemUse.fnptr!(Battle.reward_data->items[0], Battle.reward_data->items_amounts[0]); } else if (Battle.reward_data->key_item_count != 0) { - item_name = _MsImportantName(Battle.reward_data->key_item); - message_text = _FUN_008bda20(0x4017); // "Obtained %0!" - _TkMsImportantSet.hook_fptr(Battle.reward_data->key_item); + item_name = FhXCall.MsImportantName.fnptr!(Battle.reward_data->key_item); + message_text = FhXCall.TkBtlEndGetText.fnptr!(0x4017); // "Obtained %0!" + FhXCall.TkMsImportantSet.fnptr!(Battle.reward_data->key_item); } else if (Battle.reward_data->gear_count != 0) { weapon_id = Battle.reward_data->gear_inv_idx; - message_text = _FUN_008bda20(0x4016); // "Obtained %0!" - Equipment* weapon = (Equipment*)_MsGetSaveWeapon(weapon_id, (nint)(&item_name)); - int inv_id = _FUN_007ab930(weapon); // giveWeapon? + message_text = FhXCall.TkBtlEndGetText.fnptr!(0x4016); // "Obtained %0!" + Equipment* weapon = (Equipment*)FhXCall.MsGetSaveWeapon.fnptr!(weapon_id, (nint)(&item_name)); + int inv_id = FhXCall.FUN_007ab930.fnptr!(weapon); // giveWeapon? gear_inv_is_full = inv_id == 0; } else if (Battle.reward_data->gil != 0) { - _FUN_008b8930(window_id, 1, (int)Battle.reward_data->gil); - message_text = _FUN_008bda20(0x401a); // "Obtained %1 Gil!" - _MsPayGIL(-(int)Battle.reward_data->gil); + FhXCall.FUN_008b8930.fnptr!(window_id, 1, (int)Battle.reward_data->gil); + message_text = FhXCall.TkBtlEndGetText.fnptr!(0x401a); // "Obtained %1 Gil!" + FhXCall.MsPayGIL.fnptr!(-(int)Battle.reward_data->gil); } - _FUN_008b8930(window_id, 0, (int)item_name); + FhXCall.FUN_008b8930.fnptr!(window_id, 0, (int)item_name); atelStack->push_int(window_id); atelStack->push_int(0x100); atelStack->push_int(0xd0); atelStack->push_int(4); - _CT_RetInt_0065((nint)work, storage, (nint)atelStack); + h_CT_RetInt_0065.fnptr!(work, storage, atelStack); - delegates.TOMesWinWork* mesageWindowWorker = _AtelGetMesWinWork(window_id); + TOMesWinWork* mesageWindowWorker = FhXCall.AtelGetMesWinWork.fnptr!(window_id); mesageWindowWorker->_0x20 = 0; mesageWindowWorker->text = message_text; mesageWindowWorker->_0xc = message_text; @@ -2501,7 +2224,7 @@ private static void obtainTreasureInitReimplement(AtelBasicWorker* work, int* st atelStack->push_int(window_id); atelStack->push_int(0); - _CT_RetInt_006A((nint)work, storage, (nint)atelStack); + h_CT_RetInt_006A.fnptr!(work, storage, atelStack); *storage = window_id; storage[1] = 1; @@ -2509,58 +2232,58 @@ private static void obtainTreasureInitReimplement(AtelBasicWorker* work, int* st storage[3] = (int)weapon_id; if (!gear_inv_is_full) { - _MsBtlGetInit(); + FhXCall.MsBtlGetInit.fnptr!(); } - _FUN_0086a0c0(); + FhXCall.FUN_0086a0c0.fnptr!(); mesageWindowWorker->_0x1d |= 0x10; } - private static void h_Common_obtainTreasureSilentlyInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + private void Common_obtainTreasureSilentlyInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int treasure_id = atelStack->values.as_int()[0]; - logger.Info($"obtain_treasure_silently: {treasure_id}"); - //_Common_obtainTreasureSilentlyInit.orig_fptr(work, storage, atelStack); + _logger.Info($"obtain_treasure_silently: {treasure_id}"); + //FhXCall.Common_obtainTreasureSilentlyInit.chain_from(h_Common_obtainTreasureSilentlyInit).fnptr!(work, storage, atelStack); obtainTreasureSilentlyInitReimplement(work, storage, atelStack); } - private static void obtainTreasureSilentlyInitReimplement(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + private void obtainTreasureSilentlyInitReimplement(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int treasure_id = atelStack->pop_int(); - _MsFieldItemGet(treasure_id); + FhXCall.MsFieldItemGet.fnptr!(treasure_id); bool gear_inv_is_full = false; uint weapon_id = 0; if (item_locations.treasure.TryGetValue(treasure_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(treasure_id, FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) { + if (_client!.sendLocation(treasure_id, ArchipelagoClientModule.ArchipelagoLocationType.Treasure)) { obtain_item(item.id); } } else if (Battle.reward_data->item_count != 0) { - _MsSaveItemUse(Battle.reward_data->items[0], Battle.reward_data->items_amounts[0]); + FhXCall.MsSaveItemUse.fnptr!(Battle.reward_data->items[0], Battle.reward_data->items_amounts[0]); } else if (Battle.reward_data->key_item_count != 0) { - _TkMsImportantSet.hook_fptr(Battle.reward_data->key_item); + FhXCall.TkMsImportantSet.fnptr!(Battle.reward_data->key_item); } else if (Battle.reward_data->gear_count != 0) { weapon_id = Battle.reward_data->gear_inv_idx; - Equipment* weapon = (Equipment*)_MsGetSaveWeapon(weapon_id, 0); - int inv_id = _FUN_007ab930(weapon); // giveWeapon? + Equipment* weapon = FhXCall.MsGetSaveWeapon.fnptr!(weapon_id, 0); + int inv_id = FhXCall.FUN_007ab930.fnptr!(weapon); // giveWeapon? gear_inv_is_full = inv_id == 0; } else if (Battle.reward_data->gil != 0) { - _MsPayGIL(-(int)Battle.reward_data->gil); + FhXCall.MsPayGIL.fnptr!(-(int)Battle.reward_data->gil); } storage[2] = gear_inv_is_full ? 1 : 0; storage[3] = (int)weapon_id; if (!gear_inv_is_full) { - _MsBtlGetInit(); + FhXCall.MsBtlGetInit.fnptr!(); } } - private static int h_Common_obtainBrotherhoodRetInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { - logger.Debug($"obtain_brotherhoodRetInt"); + private int Common_obtainBrotherhoodRetInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + _logger.Debug("obtain_brotherhoodRetInt"); if (atelStack->size > 0) { throw new Exception($"Too many parameters ({atelStack->size}) passed to obtainBrotherhood!"); } @@ -2568,26 +2291,26 @@ private static int h_Common_obtainBrotherhoodRetInt(AtelBasicWorker* work, int* obtain_item(item.id); return 1; } - return _Common_obtainBrotherhoodRetInt.orig_fptr(work, storage, atelStack); + return h_Common_obtainBrotherhoodRetInt.chain_from(Common_obtainBrotherhoodRetInt).fnptr!(work, storage, atelStack); } - private static int h_Common_upgradeBrotherhoodRetInt(nint work, int* storage, nint atelStack) { - logger.Debug($"upgrade_brotherhoodRetInt"); + private int Common_upgradeBrotherhoodRetInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + _logger.Debug("upgrade_brotherhoodRetInt"); if (item_locations.other.TryGetValue(37, out var item)) { obtain_item(item.id); return 1; } - return _Common_upgradeBrotherhoodRetInt.orig_fptr(work, storage, atelStack); + return h_Common_upgradeBrotherhoodRetInt.chain_from(Common_upgradeBrotherhoodRetInt).fnptr!(work, storage, atelStack); } - private static int h_Common_isBrotherhoodUnpoweredRetInt(nint work, int* storage, nint atelStack) { - logger.Debug($"isBrotherhoodUnpoweredRetInt"); + private int Common_isBrotherhoodUnpoweredRetInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + _logger.Debug("isBrotherhoodUnpoweredRetInt"); - return _Common_isBrotherhoodUnpoweredRetInt.orig_fptr(work, storage, atelStack); + return h_CT_RetInt_01B6.chain_from(Common_isBrotherhoodUnpoweredRetInt).fnptr!(work, storage, atelStack); } //private static int h_Common_grantCelestialUpgrade(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { // int character = atelStack->values.as_int()[0]; // int level = atelStack->values.as_int()[1]; - // logger.Debug($"grant_celestial_upgrade: character={id_to_character[character]}, level={level}"); + // _logger.Debug($"grant_celestial_upgrade: character={id_to_character[character]}, level={level}"); // // // if (0 <= character && character <= 6 && item_locations.other.TryGetValue(36 + level + character*2, out var item)) { @@ -2600,48 +2323,48 @@ private static int h_Common_isBrotherhoodUnpoweredRetInt(nint work, int* storage // return _Common_grantCelestialUpgrade.orig_fptr(work, storage, atelStack); //} - private static int h_TkSetLegendAbility(int chr_id, int level) { - logger.Debug($"grant_celestial_upgrade: character={id_to_character[chr_id]}, level={level}"); + private int TkSetLegendAbility(int chr_id, int level) { + _logger.Debug($"grant_celestial_upgrade: character={id_to_character[chr_id]}, level={level}"); int other_id = 37 + level + chr_id * 2; if (0 <= chr_id && chr_id <= 6 && item_locations.other.TryGetValue(other_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(other_id, FFXArchipelagoClient.ArchipelagoLocationType.Other)) { + if (_client!.sendLocation(other_id, ArchipelagoClientModule.ArchipelagoLocationType.Other)) { obtain_item(item.id); } return level; } - return _TkSetLegendAbility.orig_fptr(chr_id, level); + return FhXCall.TkSetLegendAbility.chain_from(TkSetLegendAbility).fnptr!(chr_id, level); } - private static int h_Common_setPrimerCollected(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + private int Common_setPrimerCollected(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int primer = atelStack->values.as_int()[0]; - logger.Debug($"set_primer_collected: Al Bhed Primer {primer + 1}"); + _logger.Debug($"set_primer_collected: Al Bhed Primer {primer + 1}"); if (item_locations.other.TryGetValue(primer + 1, out var item)) { - if (FFXArchipelagoClient.sendLocation(primer + 1, FFXArchipelagoClient.ArchipelagoLocationType.Other)) { + if (_client!.sendLocation(primer + 1, ArchipelagoClientModule.ArchipelagoLocationType.Other)) { obtain_item(item.id); } atelStack->pop_int(); return 1; } - return _Common_setPrimerCollected.orig_fptr(work, storage, atelStack); + return h_Common_setPrimerCollected.chain_from(Common_setPrimerCollected).fnptr!(work, storage, atelStack); } - private static void update_region_state() { + private void update_region_state() { update_region_state(save_data->current_room_id, save_data->current_spawnpoint); } - private static void update_region_state(int map, int entrance) { - logger.Info($"Update region state"); + private void update_region_state(int map, int entrance) { + _logger.Info("Update region state"); // Update region state - if (current_region != ArchipelagoData.RegionEnum.None && region_states.TryGetValue(current_region, out ArchipelagoData.ArchipelagoRegion? current_state)) { + if (current_region != RegionEnum.None && region_states.TryGetValue(current_region, out ArchipelagoRegion? current_state)) { current_state = region_states[current_region]; for (int i = 0; i < current_state.savedata.Length; i++) { - ref ArchipelagoData.ArchipelagoRegionSaveData data = ref current_state.savedata[i]; + ref ArchipelagoRegionSaveData data = ref current_state.savedata[i]; new Span((byte*)((int)save_data + data.offset), data.size).CopyTo(data.bytes); } @@ -2654,8 +2377,8 @@ private static void update_region_state(int map, int entrance) { } } - private static void restore_region_state(ref int map, ref int entrance) { - ArchipelagoData.ArchipelagoRegion current_state = region_states[current_region]; + private void restore_region_state(ref int map, ref int entrance) { + ArchipelagoRegion current_state = region_states[current_region]; save_data->story_progress = current_state.story_progress; map = current_state.room_id; entrance = (byte)current_state.entrance; @@ -2665,7 +2388,7 @@ private static void restore_region_state(ref int map, ref int entrance) { } } - private static void on_map_change() { + private void on_map_change() { int map = save_data->current_room_id; int entrance = save_data->current_spawnpoint; handle_warp_transition(save_data->last_room_id, save_data->last_spawnpoint, ref map, ref entrance); // We can ignore return value? @@ -2675,7 +2398,7 @@ private static void on_map_change() { save_data->current_spawnpoint = (byte)entrance; } } - private static bool handle_warp_transition(int current_map, int current_entrance, ref int next_map, ref int next_entrance) { + private bool handle_warp_transition(int current_map, int current_entrance, ref int next_map, ref int next_entrance) { if (next_map == -1) { // Loading a save next_map = save_data->saved_current_room_id; @@ -2685,20 +2408,20 @@ private static bool handle_warp_transition(int current_map, int current_entrance save_data->saved_current_spawnpoint = 0; if (id_to_regions.Contains(next_map)) { var regions = id_to_regions[next_map]; - ArchipelagoData.RegionEnum region = regions.Any(r => current_region == r) ? current_region : regions.Last(); + RegionEnum region = regions.Any(r => current_region == r) ? current_region : regions.Last(); current_region = region; restore_region_state(ref next_map, ref next_entrance); } } - if (id_to_regions.Contains(next_map)) { + if (id_to_regions.Contains(next_map)) { // New Game if (save_data->current_room_id == 0 && next_map == 132) { - current_region = ArchipelagoData.RegionEnum.DreamZanarkand; - FFXArchipelagoClient.local_checked_locations.Clear(); - FFXArchipelagoClient.received_items = 0; - FFXArchipelagoClient.remote_locations_updated = true; + current_region = RegionEnum.DreamZanarkand; + _client!.local_checked_locations.Clear(); + _client!.received_items = 0; + _client!.remote_locations_updated = true; // Load seed here? if (!loadSeed()) { next_map = 23; @@ -2709,6 +2432,7 @@ private static bool handle_warp_transition(int current_map, int current_entrance foreach (uint item in seed.Locations.StartingItems) obtain_item(item); OverdriveModule.OverdriveProvider.set_overdrive_modes(); } + if (seed.Options.SeedId is null) { // In-game with no seed next_map = 23; @@ -2718,80 +2442,78 @@ private static bool handle_warp_transition(int current_map, int current_entrance } var regions = id_to_regions[next_map]; - ArchipelagoData.RegionEnum region = regions.Any(r => current_region == r) ? current_region : regions.Last(); + RegionEnum region = regions.Any(r => current_region == r) ? current_region : regions.Last(); if (current_region != region) { next_map = 382; next_entrance = 0; return false; } - else { - // Skip crystal collecting - if (next_map == 324 && save_data->story_progress == 3250) { - logger.Info($"Skipping crystal collecting"); - next_map = 325; - next_entrance = 0; - save_data->story_progress = 3260; - return handle_warp_transition(current_map, current_entrance, ref next_map, ref next_entrance); - } + + // Skip crystal collecting + if (next_map == 324 && save_data->story_progress == 3250) { + _logger.Info("Skipping crystal collecting"); + next_map = 325; + next_entrance = 0; + save_data->story_progress = 3260; + return handle_warp_transition(current_map, current_entrance, ref next_map, ref next_entrance); } - } - else { + } else { if (next_map == 23) { - logger.Debug("Enter main menu"); + _logger.Debug("Enter main menu"); // Main Menu initalize_states(); seed = default; } + if (next_map == 382) update_region_state(current_map, current_entrance); // Airship Menu - current_region = ArchipelagoData.RegionEnum.None; + current_region = RegionEnum.None; skip_state_updates = false; } return true; } - private static void refill_inventory() { - logger.Debug($"Refill inventory"); + private void refill_inventory() { + _logger.Debug("Refill inventory"); foreach ((var item_id, var amount) in excess_inventory.ToList()) { if (amount > 0 && save_data->get_item_count((int)item_id) < 99) { excess_inventory[item_id] = 0; - h_give_item(item_id, amount); + give_item(item_id, amount); } } } - private static int h_Common_transitionToMap(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + private int Common_transitionToMap(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { ref int map = ref atelStack->values.as_int()[0]; ref int entrance = ref atelStack->values.as_int()[1]; - logger.Debug($"transition_to_map: map={map}, entrance={entrance}"); + _logger.Debug($"transition_to_map: map={map}, entrance={entrance}"); if (handle_warp_transition(save_data->current_room_id, save_data->current_spawnpoint, ref map, ref entrance)) { - return _Common_transitionToMap.orig_fptr(work, storage, atelStack); - } - else { - return blockWarp(work, storage, atelStack); + return h_Common_transitionToMap.chain_from(Common_transitionToMap).fnptr!(work, storage, atelStack); } + + return blockWarp(work, storage, atelStack); } - private static int h_Common_warpToMap(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + private int Common_warpToMap(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { ref int map = ref atelStack->values.as_int()[0]; ref int entrance = ref atelStack->values.as_int()[1]; - logger.Debug($"warp_to_map: map={map}, entrance={entrance}"); + _logger.Debug($"warp_to_map: map={map}, entrance={entrance}"); // Skip intro if (map == 348) { - logger.Debug("Skip intro"); + _logger.Debug("Skip intro"); map = 23; } if (handle_warp_transition(save_data->current_room_id, save_data->current_spawnpoint, ref map, ref entrance)) { - return _Common_warpToMap.orig_fptr(work, storage, atelStack); - } else { - return blockWarp(work, storage, atelStack); + return h_Common_warpToMap.chain_from(Common_warpToMap).fnptr!(work, storage, atelStack); } + + return blockWarp(work, storage, atelStack); } - private static void h_SgEvent_showModularMenuInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + private void SgEvent_showModularMenuInit(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int menu = atelStack->values.as_int()[0]; int unknown1 = menu >> 24 & 0xFF; int menuType = menu >> 16 & 0xFF; @@ -2813,7 +2535,7 @@ private static void h_SgEvent_showModularMenuInit(AtelBasicWorker* work, int* st // TODO: Investigate why Magus Sisters naming menus (0x4008000F, 0x40080010, 0x40080011) need to be skipped if (menu == 0x40800001 || menu == 0x40800002 || menu == 0x40800003 || menu == 0x40800004 || menu == 0x40800005 || menu == 0x4008000F || menu == 0x40080010 || menu == 0x40080011) { - logger.Debug($"Skipping menu: type={menuTypeString}, index={index} {(unknown1 == 0x40 ? "" : $", Unknown1={unknown1}")} {(unknown2 == 0x00 ? "" : $", Unknown2={unknown2}")}"); + _logger.Debug($"Skipping menu: type={menuTypeString}, index={index} {(unknown1 == 0x40 ? "" : $", Unknown1={unknown1}")} {(unknown2 == 0x00 ? "" : $", Unknown2={unknown2}")}"); //FhUtil.set_at(0x00efbbf0, 0x40080000); //FhUtil.set_at(0x00efbbf4, 0xffffffff); atelStack->pop_int(); @@ -2822,15 +2544,15 @@ private static void h_SgEvent_showModularMenuInit(AtelBasicWorker* work, int* st } if (menuType == 0x80) { - logger.Info($"Unknown tutorial?"); + _logger.Info($"Unknown tutorial?"); } - logger.Info($"Opening menu: type={menuTypeString}, index={index} {(unknown1 == 0x40 ? "" : $", Unknown1={unknown1}")} {(unknown2 == 0x00 ? "" : $", Unknown2={unknown2}")}"); - _SgEvent_showModularMenuInit.orig_fptr(work, storage, atelStack); + _logger.Info($"Opening menu: type={menuTypeString}, index={index} {(unknown1 == 0x40 ? "" : $", Unknown1={unknown1}")} {(unknown2 == 0x00 ? "" : $", Unknown2={unknown2}")}"); + h_SgEvent_showModularMenuInit.chain_from(SgEvent_showModularMenuInit).fnptr!(work, storage, atelStack); } - public static int h_Common_addPartyMember(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int Common_addPartyMember(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int character = atelStack->values.as_int()[0]; //if (!party_overridden && !(save_data->atel_is_push_member == 1)) { @@ -2842,9 +2564,10 @@ public static int h_Common_addPartyMember(AtelBasicWorker* work, int* storage, A } //logger.Debug($"add_party_member: character={id_to_character[character]}"); - return _Common_addPartyMember.orig_fptr(work, storage, atelStack); + return h_Common_addPartyMember.chain_from(Common_addPartyMember).fnptr!(work, storage, atelStack); } - public static int h_Common_removePartyMember(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int Common_removePartyMember(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int character = atelStack->values.as_int()[0]; //if (!party_overridden && !(save_data->atel_is_push_member == 1)) { @@ -2856,9 +2579,10 @@ public static int h_Common_removePartyMember(AtelBasicWorker* work, int* storage } //logger.Debug($"remove_party_member: character={id_to_character[character]}"); - return _Common_removePartyMember.orig_fptr(work, storage, atelStack); + return h_Common_removePartyMember.chain_from(Common_removePartyMember).fnptr!(work, storage, atelStack); } - public static int h_Common_removePartyMemberLongTerm(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int Common_removePartyMemberLongTerm(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int character = atelStack->values.as_int()[0]; //if (!party_overridden && !(save_data->atel_is_push_member == 1)) { @@ -2870,20 +2594,22 @@ public static int h_Common_removePartyMemberLongTerm(AtelBasicWorker* work, int* } //logger.Debug($"remove_party_member_long_term: character={id_to_character[character]}"); - return _Common_removePartyMemberLongTerm.orig_fptr(work, storage, atelStack); + return h_Common_removePartyMemberLongTerm.chain_from(Common_removePartyMemberLongTerm).fnptr!(work, storage, atelStack); } - public static int h_Common_setWeaponInvisible(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int Common_setWeaponInvisible(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int character = (byte)atelStack->values.as_int()[0]; int state = atelStack->values.as_int()[1]; - logger.Debug($"character={id_to_character[character]}, state={state}"); + _logger.Debug($"character={id_to_character[character]}, state={state}"); if (state != 0 && is_character_unlocked(character)) { atelStack->pop_int(); atelStack->pop_int(); return 0; } - return _Common_setWeaponVisibilty.orig_fptr(work, storage, atelStack); + return h_Common_setWeaponInvisible.chain_from(Common_setWeaponInvisible).fnptr!(work, storage, atelStack); } - public static int h_Common_putPartyMemberInSlot(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int Common_putPartyMemberInSlot(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int slot = atelStack->values.as_int()[0]; int character = (byte)atelStack->values.as_int()[1]; //if (!party_overridden && !(save_data->atel_is_push_member == 1)) { @@ -2897,49 +2623,51 @@ public static int h_Common_putPartyMemberInSlot(AtelBasicWorker* work, int* stor } //logger.Debug($"put_party_member_in_slot: slot={slot}, character={(character != 0xff ? id_to_character[character] : "Empty")}"); - return _Common_putPartyMemberInSlot.orig_fptr(work, storage, atelStack); + return h_Common_putPartyMemberInSlot.chain_from(Common_putPartyMemberInSlot).fnptr!(work, storage, atelStack); } - public static int h_Common_pushParty(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int Common_pushParty(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { //logger.Debug($"push_party"); - //if (party_overridden) return _Common_pushParty.orig_fptr(work, storage, atelStack); + //if (party_overridden) return FhXCall.Common_pushParty.chain_from(h_Common_pushParty).fnptr!(work, storage, atelStack); //save_party(); return 0; } - public static int h_Common_popParty(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int Common_popParty(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { //logger.Debug($"pop_party"); - //if (party_overridden) return _Common_popParty.orig_fptr(work, storage, atelStack); + //if (party_overridden) return FhXCall.Common_popParty.chain_from(h_Common_popParty).fnptr!(work, storage, atelStack); //reset_party(); return 1; } // TODO: Get function pointer instead of hook for most of these - public static void h_MsGetSavePartyMember(uint* param_1, uint* param_2, uint* param_3) { + public void h_MsGetSavePartyMember(uint* param_1, uint* param_2, uint* param_3) { //logger.Debug($"get_current_party_slots"); - _MsGetSavePartyMember.orig_fptr(param_1, param_2, param_3); + FhXCall.MsGetSavePartyMember.chain_from(h_MsGetSavePartyMember).fnptr!(param_1, param_2, param_3); //logger.Debug($"get_current_party_slots: slot_0={*param_1}, slot_1={*param_2}, slot_2={*param_3}"); } // Pre-battle - public static void h_MsBattleExe(uint param_1, int field_idx, int group_idx, int formation_idx) { + public void MsBattleExe(uint param_1, int field_idx, int group_idx, int formation_idx) { // Evrae is 52, 0, 0 // Penance is 52, 1, 0 if (field_idx == 52 && group_idx == 1 && formation_idx == 0) { // Try to avoid getting Penance'd by setting the group to Evrae manually group_idx = 0; - logger.Info("Tried to avoid getting Penance'd!"); + _logger.Info("Tried to avoid getting Penance'd!"); } var field_ptr = Battle.btl->ptr_btl_bin_fields + field_idx * 0xe; - string field_name = Marshal.PtrToStringAnsi((nint)(field_ptr+6)); + string field_name = Marshal.PtrToStringAnsi((nint)(field_ptr+6))!; - var group_ptr = _MsBtlListGroup(field_idx, group_idx); + var group_ptr = FhXCall.MsBtlListGroup.fnptr!(field_idx, group_idx); byte group_name = *(byte*)(group_ptr+5 + formation_idx * 2); string encounter_name = $"{field_name}_{group_name:00}"; - logger.Debug($"{encounter_name}: param_1={param_1}, ({field_idx}, {group_idx}, {formation_idx})"); + _logger.Debug($"{encounter_name}: param_1={param_1}, ({field_idx}, {group_idx}, {formation_idx})"); /* if (encounterToPartyDict.TryGetValue(encounter_name, out List characters)) { if (characters.Count > 0) { @@ -2951,20 +2679,19 @@ public static void h_MsBattleExe(uint param_1, int field_idx, int group_idx, int } } */ - if (encounterToActionDict.TryGetValue(encounter_name, out Action? action)) { - action(); - } - else { + if (encounterToActionDict.TryGetValue(encounter_name, out Action? action)) { + action(_client!, this); + } else { save_party(); // Probably? reset_party(); } - _MsBattleExe.orig_fptr(param_1, field_idx, group_idx, formation_idx); + FhXCall.MsBattleExe.chain_from(MsBattleExe).fnptr!(param_1, field_idx, group_idx, formation_idx); } // Battle loop? - public static void h_FUN_00791820() { - _FUN_00791820.orig_fptr(); - string encounter_name = Marshal.PtrToStringAnsi((nint)(&Battle.btl->field_name)); + public void FUN_00791820() { + FhXCall.FUN_00791820.chain_from(FUN_00791820).fnptr!(); + string encounter_name = Marshal.PtrToStringAnsi((nint)(&Battle.btl->field_name))!; byte battle_end_type = Battle.btl->battle_end_type; byte battle_state = Battle.btl->battle_state; @@ -2982,36 +2709,36 @@ public static void h_FUN_00791820() { } switch (battle_end_type) { case 2: // Battle Victory - logger.Info($"Victory: type={battle_end_type}, encounter={encounter_name}"); - if (encounterVictoryActions.TryGetValue(encounter_name!, out Action? victoryAction)) { - victoryAction(); + _logger.Info($"Victory: type={battle_end_type}, encounter={encounter_name}"); + if (encounterVictoryActions.TryGetValue(encounter_name!, out Action? victoryAction)) { + victoryAction(_client!, this); } if (encounterToLocationDict.TryGetValue(encounter_name!, out int[]? boss_locations)) { foreach (int location_id in boss_locations) { // Sending all locations even if they don't exist - if (sendLocation(location_id, FFXArchipelagoClient.ArchipelagoLocationType.Boss) && item_locations.boss.TryGetValue(location_id, out var item)) { - ArchipelagoFFXModule.obtain_item(item.id); + if (_client!.sendLocation(location_id, ArchipelagoClientModule.ArchipelagoLocationType.Boss) && item_locations.boss.TryGetValue(location_id, out var item)) { + obtain_item(item.id); } } } break; case 3: // Battle Escape - logger.Info($"Escape: type={battle_end_type}, encounter={encounter_name}"); - if (encounterEscapeActions.TryGetValue(encounter_name!, out Action? escapeAction)) { - escapeAction(); + _logger.Info($"Escape: type={battle_end_type}, encounter={encounter_name}"); + if (encounterEscapeActions.TryGetValue(encounter_name!, out Action? escapeAction)) { + escapeAction(_client!, this); } break; default: - logger.Info($"Battle End: type={battle_end_type}, encounter={encounter_name}"); + _logger.Info($"Battle End: type={battle_end_type}, encounter={encounter_name}"); break; } } } - private static void* curr_pos_area_ptr = null; - public static byte h_MsBtlReadSetScene() { - byte result = _MsBtlReadSetScene.orig_fptr(); - logger.Info($"Battle Name: {Marshal.PtrToStringAnsi((nint)FhUtil.ptr_at(0xD2C25A))}"); + private void* curr_pos_area_ptr = null; + public byte MsBtlReadSetScene() { + byte result = FhXCall.MsBtlReadSetScene.chain_from(MsBtlReadSetScene).fnptr!(); + _logger.Info($"Battle Name: {Marshal.PtrToStringAnsi((nint)FhUtil.ptr_at(0xD2C25A))}"); //ref BtlAreas original_pos_struct = ref *Battle.btl->ptr_pos_def; BtlAreasHelper original_pos_struct = new BtlAreasHelper(Battle.btl->ptr_pos_def); if (original_pos_struct.areas.Length == 0) return result; @@ -3187,7 +2914,7 @@ public static byte h_MsBtlReadSetScene() { return result; } - public static int h_MsBtlGetPos(int param_1, Chr* chr, int btl_pos_a, int btl_pos_b, int btl_pos_c, Vector4* out_pos) { + public int h_MsBtlGetPos(int param_1, Chr* chr, int btl_pos_a, int btl_pos_b, int btl_pos_c, Vector4* out_pos) { // btl_pos_a: position group/set/area // btl_pos_b = 3: party_pos[btl_pos_c] // btl_pos_b = 4: aeon_pos[btl_pos_c] @@ -3197,11 +2924,11 @@ public static int h_MsBtlGetPos(int param_1, Chr* chr, int btl_pos_a, int btl_po // btl_pos_b = 8: enemy_run_pos[btl_pos_c]? // btl_pos_b = 9: b? // btl_pos_b = 10: c? - return _MsBtlGetPos.orig_fptr(param_1, chr, btl_pos_a, btl_pos_b, btl_pos_c, out_pos); + return FhXCall.MsBtlGetPos.chain_from(h_MsBtlGetPos).fnptr!(param_1, chr, btl_pos_a, btl_pos_b, btl_pos_c, out_pos); } - private static uint h_give_item(uint item_id, int amount) { - logger.Debug($"give_item: {amount} x {item_id}"); + private int give_item(uint item_id, int amount) { + _logger.Debug($"give_item: {amount} x {item_id}"); int new_amount = (int)(save_data->get_item_count((int)item_id) + amount); if (new_amount > 99) { @@ -3211,43 +2938,48 @@ private static uint h_give_item(uint item_id, int amount) { amount -= excess; } - return _FUN_007905a0.orig_fptr(item_id, amount); + return FhXCall.MsSaveItemUse.chain_from(give_item).fnptr!(item_id, amount); } - private static void h_TkMsImportantSet(uint param_1) { - logger.Debug($"give_key_item: {param_1}"); - _TkMsImportantSet.orig_fptr(param_1); + private void h_TkMsImportantSet(uint param_1) { + _logger.Debug($"give_key_item: {param_1}"); + + FhXCall.TkMsImportantSet.chain_from(h_TkMsImportantSet).fnptr!(param_1); } - private static byte* h_read_from_bin(int param_1, short* param_2, int param_3) { - logger.Debug($"get_from_bin: {param_1}, {(int)param_2}, {param_3}"); - logger.Debug($"bin_pointers: {(uint)param_2}, {(uint)(*takara_pointer)}, {(uint)(*buki_get_pointer)}"); - if (param_2 == (short*)*takara_pointer) { - logger.Debug($"get_from_bin: takara.bin"); + + private nint h_read_from_bin(int param_1, nint param_2, int* param_3) { + _logger.Debug($"get_from_bin: {param_1}, {(int)param_2}, {*param_3}"); + _logger.Debug($"bin_pointers: {(uint)param_2}, {(uint)(*takara_pointer)}, {(uint)(*buki_get_pointer)}"); + if (param_2 == *takara_pointer) { + _logger.Debug("get_from_bin: takara.bin"); } - else if (param_2 == (short*)*buki_get_pointer) { - logger.Debug($"get_from_bin: buki_get.bin"); + else if (param_2 == *buki_get_pointer) { + _logger.Debug("get_from_bin: buki_get.bin"); } - var result = _FUN_007ab890.orig_fptr(param_1, param_2, param_3); - logger.Debug($"get_from_bin: result = {((uint)result).ToString("X")}"); + var result = FhXCall.MsGetExcelData.chain_from(h_read_from_bin).fnptr!(param_1, param_2, param_3); + _logger.Debug($"get_from_bin: result = {((uint)result).ToString("X")}"); return result; } - private static ushort h_get_weapon_name(Equipment* param_1) { - logger.Debug($"get_weapon_name: {(int)param_1}"); - return _FUN_007a0d10.orig_fptr(param_1); + private ushort h_get_weapon_name(Equipment* param_1) { + _logger.Debug($"get_weapon_name: {(int)param_1}"); + + return FhXCall.MsWeaponNameNum.chain_from(h_get_weapon_name).fnptr!(param_1); } - private static void h_get_weapon_model(ushort name_id, byte owner, int unknown, ushort* model_id_pointer) { - logger.Debug($"get_weapon_model: {name_id}, {owner}, {unknown}, {*model_id_pointer}, "); - _FUN_007a0c70.orig_fptr(name_id, owner, unknown, model_id_pointer); + private void h_get_weapon_model(ushort name_id, byte owner, int unknown, ushort* model_id_pointer) { + _logger.Debug($"get_weapon_model: {name_id}, {owner}, {unknown}, {*model_id_pointer}, "); + + FhXCall.MsWeaponName.chain_from(h_get_weapon_model).fnptr!(name_id, owner, unknown, model_id_pointer); } - private static void h_obtain_treasure_cleanup(BtlRewardData* param_1, int param_2) { - logger.Debug($"obtain_treasure_cleanup"); - _FUN_007993f0.orig_fptr(param_1, param_2); + private void h_obtain_treasure_cleanup(BtlRewardData* param_1, int param_2) { + _logger.Debug("obtain_treasure_cleanup"); + + FhXCall.FUN_007993f0.chain_from(h_obtain_treasure_cleanup).fnptr!(param_1, param_2); } - public static void obtain_item(uint item_id, int amount=-1) { + public void obtain_item(uint item_id, int amount=-1) { if (item_id == 0) return; var item_type = (item_id & 0xF000) >> 12; if (amount == -1) amount = (int)((item_id & 0xFF0000) >> 16); @@ -3258,16 +2990,16 @@ public static void obtain_item(uint item_id, int amount=-1) { // Key Item // Progressive Mirror - if (item_id == 0xA002 && Globals.save_data->key_items.get((int)item_id)) { + if (item_id == 0xA002 && save_data->key_items.get((int)item_id)) { //Globals.save_data->key_items.set((int)item_id, false); item_id = 0xA003; } // Al Bhed Primers - if (item_id == 0xA004 && Globals.save_data->key_items.get((int)item_id)) { + if (item_id == 0xA004 && save_data->key_items.get((int)item_id)) { for (byte i = 0; i < 26; i++) { - if (!Globals.save_data->unlocked_primers.get_bit(i)) + if (!save_data->unlocked_primers.get_bit(i)) { item_id += i; break; @@ -3280,20 +3012,20 @@ public static void obtain_item(uint item_id, int amount=-1) { save_data->jecht_spheres.collected_amount++; if (save_data->jecht_spheres.collected_amount >= 1) - OverdriveModule.send_overdrive(PlayerCommandId.PCOM_SHOOTING_STAR); + _overdrives!.send_overdrive(PlayerCommandId.PCOM_SHOOTING_STAR); if (save_data->jecht_spheres.collected_amount >= 3) - OverdriveModule.send_overdrive(PlayerCommandId.PCOM_BANISHING_BLADE); + _overdrives!.send_overdrive(PlayerCommandId.PCOM_BANISHING_BLADE); if (save_data->jecht_spheres.collected_amount >= 10) - OverdriveModule.send_overdrive(PlayerCommandId.PCOM_TORNADO); + _overdrives!.send_overdrive(PlayerCommandId.PCOM_TORNADO); } h_TkMsImportantSet(item_id); break; case 0x2: // Item - h_give_item(item_id, amount); + give_item(item_id, amount); break; case 0x5: // Equipment @@ -3301,7 +3033,7 @@ public static void obtain_item(uint item_id, int amount=-1) { //UnownedEquipment* weapon_data = (UnownedEquipment*)h_read_from_bin((int)item_id, (short*)(*buki_get_pointer), 0); if (!seed.Gear.TryGetValue((int)item_id, out ArchipelagoGear? gear)) { - logger.Error($"Gear {item_id} doesn't exist"); + _logger.Error($"Gear {item_id} doesn't exist"); break; } @@ -3320,18 +3052,18 @@ public static void obtain_item(uint item_id, int amount=-1) { //var data = get_from_bin((int)item_id, (short*)0x12000C00, 0); if (weapon_data.is_celestial) { - foreach (var equip in Globals.save_data->equipment) { + foreach (var equip in save_data->equipment) { if (equip.exists && equip.owner == weapon_data.owner && equip.is_celestial) { // Upgrade celestial if (celestial_level[equip.owner] < 2) { celestial_level[equip.owner] += 1; - _TkSetLegendAbility.orig_fptr(equip.owner, celestial_level[equip.owner]); + FhXCall.TkSetLegendAbility.chain_from(TkSetLegendAbility).fnptr!(equip.owner, celestial_level[equip.owner]); } return; } } } else if (weapon_data.is_brotherhood) { - foreach (ref var equip in Globals.save_data->equipment) { + foreach (ref var equip in save_data->equipment) { if (equip.exists && equip.is_brotherhood) { if (equip.is_hidden) { // Obtain @@ -3379,7 +3111,7 @@ public static void obtain_item(uint item_id, int amount=-1) { new_weapon.slot_count = (byte)Math.Max(weapon_data.slot_count, count); new_weapon.name_id = h_get_weapon_name(&new_weapon); h_get_weapon_model(new_weapon.name_id, new_weapon.owner, 0, &new_weapon.model_id); - var result = _FUN_007ab930(&new_weapon); // giveWeapon? + var result = FhXCall.FUN_007ab930.fnptr!(&new_weapon); // giveWeapon? if (result != 0) { h_obtain_treasure_cleanup(&rewardData, 7); } @@ -3387,18 +3119,18 @@ public static void obtain_item(uint item_id, int amount=-1) { case 0x1: // Gil if (amount == -1) amount = (int)((item_id & 0xFF0000) >> 16) * 1000; - _MsPayGIL(-amount); + FhXCall.MsPayGIL.fnptr!(-amount); break; case 0xE: // Region Unlock item_id &= 0xff; - logger.Debug($"Region: {(ArchipelagoData.RegionEnum)item_id}"); - region_is_unlocked[(ArchipelagoData.RegionEnum)item_id] = true; + _logger.Debug($"Region: {(RegionEnum)item_id}"); + region_is_unlocked[(RegionEnum)item_id] = true; break; case 0xF: // Party Member int char_id = (int)(item_id & 0xFF); - logger.Debug($"Character: {id_to_character[char_id]}"); + _logger.Debug($"Character: {id_to_character[char_id]}"); unlocked_characters[char_id] = true; if (char_id == 0xF) { // Magus sisters @@ -3407,10 +3139,10 @@ public static void obtain_item(uint item_id, int amount=-1) { } save_party(); reset_party(); - if (seed.Options.GoalRequirement == ArchipelagoData.GoalRequirement.PartyMembers || seed.Options.GoalRequirement == ArchipelagoData.GoalRequirement.PartyMembersAndAeons) { + if (seed.Options.GoalRequirement == GoalRequirement.PartyMembers || seed.Options.GoalRequirement == GoalRequirement.PartyMembersAndAeons) { int num_unlocked; int num_required; - if (seed.Options.GoalRequirement == ArchipelagoData.GoalRequirement.PartyMembers) { + if (seed.Options.GoalRequirement == GoalRequirement.PartyMembers) { num_unlocked = unlocked_characters.Where(x => x.Key < 8 && x.Value).Count(); num_required = Math.Min(seed.Options.RequiredPartyMembers, 8); } else { @@ -3422,20 +3154,20 @@ public static void obtain_item(uint item_id, int amount=-1) { if (unlocked_characters.Count(x => x.Value) >= seed.Options.RequiredPartyMembers) { color = Color.Green; } - ArchipelagoGUI.add_log_message([(message, color)]); + _gui!.add_log_message([(message, color)]); } break; case 0x9: // Trap item_id &= 0xfff; - logger.Debug($"Trap: {item_id}"); + _logger.Debug($"Trap: {item_id}"); if (item_id == 0) { queued_voice_lines.Enqueue(voicelines[rng.Next(voicelines.Length)]); } break; case 0x3: // Overdrive - logger.Debug($"Overdrive: {item_id}"); + _logger.Debug($"Overdrive: {item_id}"); other_inventory.TryGetValue(item_id, out count); other_inventory[item_id] = count + 1; @@ -3464,36 +3196,37 @@ public static void obtain_item(uint item_id, int amount=-1) { break; case 0xC: // Other - logger.Debug($"Other: {item_id}"); + _logger.Debug($"Other: {item_id}"); other_inventory.TryGetValue(item_id, out count); other_inventory[item_id] = count+1; break; } } - private static Random rng = new Random(); - public static void call_obtain_brotherhood() { + private Random rng = new Random(); + + public void call_obtain_brotherhood() { AtelStack stack = new AtelStack(); int param_1 = 0; int param_2 = 0; - h_Common_obtainBrotherhoodRetInt((AtelBasicWorker*)¶m_1, ¶m_2, &stack); + h_Common_obtainBrotherhoodRetInt.fnptr!((AtelBasicWorker*)¶m_1, ¶m_2, &stack); } - public static void receive_treasure(int id) { + public void receive_treasure(int id) { AtelStack stack = new AtelStack(); stack.push_int(id); int param_1 = 0; int param_2 = 0; - _Common_obtainTreasureSilentlyInit.orig_fptr((AtelBasicWorker*)¶m_1, ¶m_2, &stack); + h_Common_obtainTreasureSilentlyInit.chain_from(Common_obtainTreasureSilentlyInit).fnptr!((AtelBasicWorker*)¶m_1, ¶m_2, &stack); } - public static void set_airship_destinations() { - logger.Debug("set_airship_destinations"); - AtelBasicWorker* worker = Globals.Atel.controllers[0].worker(0); + public void set_airship_destinations() { + _logger.Debug("set_airship_destinations"); + AtelBasicWorker* worker = Atel.controllers[0].worker(0); var var_table = worker->table_event_data; uint* airshipDestinationCount = &var_table[11]; uint* airshipDestinationLength = &var_table[12]; @@ -3519,10 +3252,10 @@ public static void set_airship_destinations() { // Sphere Grid Experiment - public static void h_eiAbmParaGet() { + public void eiAbmParaGet() { // TODO: Replace normal calculation with custom Archipelago-based calculation (if option enabled) - logger.Debug("Calculating stats"); - _eiAbmParaGet.orig_fptr(); + _logger.Debug("Calculating stats"); + FhXCall.eiAbmParaGet.chain_from(eiAbmParaGet).fnptr!(); //foreach (ref PlySave ply in save_data->ply_saves) { // ply.abi_map.has_extract_power = true; @@ -3532,20 +3265,20 @@ public static void h_eiAbmParaGet() { //} } - private static void h_MsSetRamChrParam(uint chr_id) { - logger.Debug($"MsSetRamChrParam: {chr_id}"); - _MsSetRamChrParam.orig_fptr(chr_id); + private void MsSetRamChrParam(uint chr_id) { + _logger.Debug($"MsSetRamChrParam: {chr_id}"); + FhXCall.MsSetRamChrParam.chain_from(MsSetRamChrParam).fnptr!(chr_id); - Chr* chr = _MsGetChr(chr_id); + Chr* chr = FhXCall.MsGetChr.fnptr!((int)chr_id); if (seed.Options.AlwaysSensor == 1) { chr->ram.auto_ability_effects.has_sensor = true; } } - private static void h_MsSetSaveParam(uint chr_id) { - logger.Debug("Calculating base stats and equipment"); - _MsSetSaveParam.orig_fptr(chr_id); + private void MsSetSaveParam(uint chr_id) { + _logger.Debug("Calculating base stats and equipment"); + FhXCall.MsSetSaveParam.chain_from(MsSetSaveParam).fnptr!(chr_id); // Does nothing?? if (seed.Options.AlwaysSensor == 1) { @@ -3556,8 +3289,8 @@ private static void h_MsSetSaveParam(uint chr_id) { //PlySave ply = save_data->ply_saves[(int)chr_id]; //Equipment*[] equips = //[ - // (Equipment*)_MsGetSaveWeapon(ply.wpn_inv_idx, 0x0), - // (Equipment*)_MsGetSaveWeapon(ply.arm_inv_idx, 0x0), + // (Equipment*)FhXCall.MsGetSaveWeapon.fnptr!(ply.wpn_inv_idx, 0x0), + // (Equipment*)FhXCall.MsGetSaveWeapon.fnptr!(ply.arm_inv_idx, 0x0), //]; //int strength_mult = 0; //int defense_mult = 0; @@ -3577,7 +3310,7 @@ private static void h_MsSetSaveParam(uint chr_id) { //foreach (Equipment* equip in equips) { // for (int i = 0; i < 4; i++) { // if (equip->abilities[i] == 0 || equip->abilities[i] == 0xFF) continue; - // AutoAbility* a_ability = (AutoAbility*)_MsGetExcelData(equip->abilities[i] & 0xFFF, Battle.btl->ptr_a_ability_bin, (int*)0x0); + // AutoAbility* a_ability = (AutoAbility*)FhXCall.MsGetExcelData.fnptr!(equip->abilities[i] & 0xFFF, Battle.btl->ptr_a_ability_bin, (int*)0x0); // strength_mult += a_ability->stat_inc_flags.strength() ? a_ability->stat_inc_amount : 0; // defense_mult += a_ability->stat_inc_flags.defense() ? a_ability->stat_inc_amount : 0; // magic_mult += a_ability->stat_inc_flags.magic() ? a_ability->stat_inc_amount : 0; @@ -3607,28 +3340,28 @@ private static void h_MsSetSaveParam(uint chr_id) { //ply.mp = (uint)Math.Clamp(ply.mp * mp_mult / 100, 0, ply.auto_ability_effects.has_break_mp_limit ? 9999 : 999); } - public static void h_FUN_00a48910(uint chr_id, int node_idx) { + public void h_FUN_00a48910(uint chr_id, int node_idx) { // TODO: Send Archipelago location when node is unlocked (if option enabled) - logger.Debug($"Unlock node {node_idx} for {id_to_character[chr_id]}"); - _FUN_00a48910.orig_fptr(chr_id, node_idx); + _logger.Debug($"Unlock node {node_idx} for {id_to_character[chr_id]}"); + FhXCall.FUN_00a48910.chain_from(h_FUN_00a48910).fnptr!(chr_id, node_idx); } - private static uint h_MsApUp(int chr_id, Chr* chr, int base_ap_add, uint param_4) { - logger.Debug($"AP gain: character={id_to_character[chr_id]}, ap={base_ap_add}"); + private uint MsApUp(int chr_id, Chr* chr, int base_ap_add, uint param_4) { + _logger.Debug($"AP gain: character={id_to_character[chr_id]}, ap={base_ap_add}"); int new_ap = (int)Math.Min(Math.BigMul(base_ap_add, ap_multiplier), 999_999_999); - return _MsApUp.orig_fptr(chr_id, chr, new_ap, param_4); + return FhXCall.MsApUp.chain_from(MsApUp).fnptr!(chr_id, chr, new_ap, param_4); } // Non-loading FMV - private static bool h_graphicInitFMVPlayer(int movie_id, int param_2) { - bool result = _graphicInitFMVPlayer.orig_fptr(movie_id, param_2); + private bool graphicInitFMVPlayer(int movie_id, int param_2) { + bool result = FhXCall.graphicInitFMVPlayer.chain_from(graphicInitFMVPlayer).fnptr!(movie_id, param_2); return !result; } // Texture experiments - private static void h_FUN_00656c90(int param_1, int param_2, char* fileName) { + private void h_FUN_00656c90(int param_1, int param_2, char* fileName) { //logger.Debug($"{param_1}, {param_2}, {(nint)fileName}"); // //string nameString = Marshal.PtrToStringAnsi((nint)fileName); @@ -3636,48 +3369,51 @@ private static void h_FUN_00656c90(int param_1, int param_2, char* fileName) { //logger.Debug(nameString); - _FUN_00656c90.orig_fptr(param_1, param_2, fileName); + FhXCall.FUN_00656c90.chain_from(h_FUN_00656c90).fnptr!(param_1, param_2, fileName); } - private static void h_TkMenuAppearMainCmdWindow(int param_1, int param_2) { + private void TkMenuAppearMainCmdWindow(int param_1, int param_2) { // All menu options are enabled at progress 0 ushort progress = save_data->story_progress; save_data->story_progress = 0; - _TkMenuAppearMainCmdWindow.orig_fptr(param_1, param_2); + FhXCall.TkMenuAppearMainCmdWindow.chain_from(TkMenuAppearMainCmdWindow).fnptr!(param_1, param_2); save_data->story_progress = progress; } // Voice related - //public static nint h_FMOD_EventSystem_load(nint param_1, nint file_path, nint param_3, nint param_4) { + //public nint h_FMOD_EventSystem_load(nint param_1, nint file_path, nint param_3, nint param_4) { // string path = Marshal.PtrToStringAnsi(file_path); // nint result = _FMOD_EventSystem_load.orig_fptr(param_1, file_path, param_3, param_4); - // logger.Debug($"{path}, {param_1}, {param_3} -> {result}"); + // _logger.Debug($"{path}, {param_1}, {param_3} -> {result}"); // return result; //} - public static void h_FfxFmod_soundInit_setLang(nint ffxFmod, int lang) { - _FfxFmod_soundInit_setLang.orig_fptr(ffxFmod, lang); + public void h_FfxFmod_soundInit_setLang(nint ffxFmod, int lang) { + FhXCall.FfxFmod_soundInit_setLang.chain_from(h_FfxFmod_soundInit_setLang).fnptr!(ffxFmod, lang); *(byte*)(ffxFmod + 4) = 0; } // Unsure if there are side effects - public static void h_LocalizationManager_Initialize(delegates.FFXLocalizationManager* localizationManager) { - _LocalizationManager_Initialize.orig_fptr(localizationManager); + public void LocalizationManager_Initialize(LocalizationManager* localizationManager) { + FhXCall.LocalizationManager_Initialize.chain_from(LocalizationManager_Initialize).fnptr!(localizationManager); if (TextLanguage.HasValue) { - logger.Debug($"Text: {TextLanguage.Value}"); - localizationManager->text = (int)TextLanguage; + _logger.Debug($"Text: {TextLanguage.Value}"); + localizationManager->lang_text = TextLanguage.Value; } if (VoiceLanguage.HasValue) { - logger.Debug($"Voice: {VoiceLanguage.Value}"); - localizationManager->video = (int)VoiceLanguage; - localizationManager->voice = (int)VoiceLanguage; + _logger.Debug($"Voice: {VoiceLanguage.Value}"); + localizationManager->lang_video = VoiceLanguage.Value; + localizationManager->lang_voice = VoiceLanguage.Value; } } - public static int h_FmodVoice_dataChange(nint FmodVoice, int event_id, nint param_2) { - logger.Debug($"{FmodVoice}, {event_id}, {param_2}"); - int result = _FmodVoice_dataChange.orig_fptr(FmodVoice, event_id, param_2); + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + public unsafe delegate nint FMOD_Bank_Post_Load(nint param_1, nint param_2, nint param_3, nint param_4); + + public int FmodVoice_dataChange(nint FmodVoice, int event_id, nint param_2) { + _logger.Debug($"{FmodVoice}, {event_id}, {param_2}"); + int result = FhXCall.FmodVoice_dataChange.chain_from(FmodVoice_dataChange).fnptr!(FmodVoice, event_id, param_2); //string bank_name = "ffx_us_voice03"; // Contains "Stay away from the summoner!" (136815042) foreach (string bank_name in (string[])["ffx_us_voice03", "ffx_us_voice07", "ffx_us_voice11", "ffx_us_voice12", "ffx_us_voice20"]) { string path = $"../../../FFX_Data/GameData/PS3Data/Sound_PC/Voice/US/{bank_name}.fev"; @@ -3686,18 +3422,18 @@ public static int h_FmodVoice_dataChange(nint FmodVoice, int event_id, nint para int bank_index = bank_name[^1] + (bank_name[^2] * 5 - 0x108)*2; nint bank = *(int*)(FmodVoice+0x18) + bank_index*4; - nint load_result = _FMOD_EventSystem_load(param_2, file_path, 0, bank); + nint load_result = FhXCall.FMOD_EventSystem_load.fnptr!(param_2, file_path, 0, bank); Marshal.FreeHGlobal(file_path); if (load_result == 0) { int* piVar5 = *(int**)bank; if (piVar5 != null) { - delegates.FMOD_Bank_Post_Load _FMOD_Bank_Post_Load = Marshal.GetDelegateForFunctionPointer(*(nint*)(*piVar5 + 8)); + FMOD_Bank_Post_Load _FMOD_Bank_Post_Load = Marshal.GetDelegateForFunctionPointer(*(nint*)(*piVar5 + 8)); nint s_voice = Marshal.StringToHGlobalAnsi("voice"); load_result = _FMOD_Bank_Post_Load((nint)piVar5, s_voice, 0, *(int*)(FmodVoice + 0xc) + bank_index*4); Marshal.FreeHGlobal(s_voice); - logger.Debug($"{bank_name}: {load_result}"); + _logger.Debug($"{bank_name}: {load_result}"); } } @@ -3706,33 +3442,33 @@ public static int h_FmodVoice_dataChange(nint FmodVoice, int event_id, nint para return result; } - public static Queue queued_voice_lines = []; - public static void play_voice_line(int voice_line) { + public Queue queued_voice_lines = []; + public void play_voice_line(int voice_line) { AtelStack stack = new AtelStack(); stack.push_int(voice_line); - logger.Debug($"stack_size = {stack.size}, voice_line = {stack.values.as_int()[0]}"); + _logger.Debug($"stack_size = {stack.size}, voice_line = {stack.values.as_int()[0]}"); int work = 0; int[] storage_array = [0,0,0,0]; fixed (int* storage = storage_array) { - _Common_playFieldVoiceLineInit((AtelBasicWorker*)&work, storage, &stack); - _Common_playFieldVoiceLineExec((AtelBasicWorker*)&work, &stack); - _Common_playFieldVoiceLineResultInt((AtelBasicWorker*)&work, storage, &stack); + h_Common_playFieldVoiceLineInit.fnptr!((AtelBasicWorker*)&work, storage, &stack); + h_Common_playFieldVoiceLineExec.fnptr!((AtelBasicWorker*)&work, &stack); + h_Common_playFieldVoiceLineResultInt.fnptr!((AtelBasicWorker*)&work, storage, &stack); - _Common_00D6Init((AtelBasicWorker*)&work, storage, &stack); - _Common_00D6Exec((AtelBasicWorker*)&work, &stack); - _Common_00D6ResultInt((AtelBasicWorker*)&work, storage, &stack); + h_Common_00D6Init.fnptr!((AtelBasicWorker*)&work, storage, &stack); + h_Common_00D6Exec.fnptr!((AtelBasicWorker*)&work, &stack); + h_Common_00D6ResultInt.fnptr!((AtelBasicWorker*)&work, storage, &stack); } } - private static Dictionary item_name_cache = []; - public static string get_item_name(uint item_id) { + private Dictionary item_name_cache = []; + public string get_item_name(uint item_id) { if (item_name_cache.TryGetValue(item_id, out var name)) return name; byte* item_name; - _TkMsGetRomItem(item_id, (int*)&item_name); + FhXCall.TkMsGetRomItem.fnptr!(item_id, (int*)&item_name); byte[] decoded = new byte[FhEncoding.compute_decode_buffer_size(new ReadOnlySpan(item_name, 1000))]; int decoded_length = FhEncoding.decode(new ReadOnlySpan(item_name, 1000), decoded, flags:FhEncodingFlags.IMPLICIT_END); string decoded_string = Encoding.UTF8.GetString(decoded, 0, decoded_length); @@ -3740,7 +3476,7 @@ public static string get_item_name(uint item_id) { return decoded_string; } - public static string get_other_item_name(uint item_id) { + public string get_other_item_name(uint item_id) { var item_type = (item_id & 0xF000) >> 0xC; var id = item_id & 0xFFF; @@ -3753,48 +3489,50 @@ public static string get_other_item_name(uint item_id) { return $"Unnamed item ({item_id})"; } - private static Dictionary cached_CT_Execs = new(); - private static Dictionary cached_CT_RetInts = new(); - private static Dictionary cached_CT_RetFloats = new(); - public static delegates.CT_Exec get_CT_Exec(int id) { + private Dictionary cached_CT_Execs = new(); + private Dictionary cached_CT_RetInts = new(); + private Dictionary cached_CT_RetFloats = new(); + + public FhGCall.d_CT_Exec get_CT_Exec(int id) { if (cached_CT_Execs.TryGetValue(id, out var result)) { return result; } AtelCallTargetNamespace nmsp = (AtelCallTargetNamespace)(id >> 0xC); AtelCallTarget* internal_ct = nmsp.get_internal() + (id & 0xFFF); - delegates.CT_Exec ct = Marshal.GetDelegateForFunctionPointer(internal_ct->ret_float_func); + FhGCall.d_CT_Exec ct = Marshal.GetDelegateForFunctionPointer(internal_ct->ret_float_func); cached_CT_Execs[id] = ct; return ct; } - public static delegates.CT_RetInt get_CT_RetInt(int id) { + + public FhGCall.d_CT_RetInt get_CT_RetInt(int id) { if (cached_CT_RetInts.TryGetValue(id, out var result)) { return result; } AtelCallTargetNamespace nmsp = (AtelCallTargetNamespace)(id >> 0xC); AtelCallTarget* internal_ct = nmsp.get_internal() + (id & 0xFFF); - delegates.CT_RetInt ct = Marshal.GetDelegateForFunctionPointer(internal_ct->ret_float_func); + FhGCall.d_CT_RetInt ct = Marshal.GetDelegateForFunctionPointer(internal_ct->ret_float_func); cached_CT_RetInts[id] = ct; return ct; } - public static delegates.CT_RetFloat get_CT_RetFloat(int id) { + + public FhGCall.d_CT_RetFloat get_CT_RetFloat(int id) { if (cached_CT_RetFloats.TryGetValue(id, out var result)) { return result; } AtelCallTargetNamespace nmsp = (AtelCallTargetNamespace)(id >> 0xC); AtelCallTarget* internal_ct = nmsp.get_internal() + (id & 0xFFF); - delegates.CT_RetFloat ct = Marshal.GetDelegateForFunctionPointer(internal_ct->ret_float_func); + FhGCall.d_CT_RetFloat ct = Marshal.GetDelegateForFunctionPointer(internal_ct->ret_float_func); cached_CT_RetFloats[id] = ct; return ct; } - // Custom namespace - public void h_AtelInitTotal() { + public void AtelInitTotal() { _logger.Debug("Initializing Atel namespaces"); - _AtelInitTotal.orig_fptr(); + FhXCall.AtelInitTotal.chain_from(AtelInitTotal).fnptr!(); AtelSetUpCallFunc(0xF, customNameSpaceHandle.AddrOfPinnedObject()); } @@ -3837,155 +3575,110 @@ enum CustomCallTarget : ushort { CHECK_UNLOCKED_AEONS, } - static AtelCallTarget[] customNameSpace = { - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_PushInt)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_PushFloat)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_IsCharacterUnlocked)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_HasCelestialWeapon)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_IsOtherLocationChecked)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_IsTreasureLocationChecked)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_CollectedPrimers)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_SendOtherLocation)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_SendPartyMemberLocation)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_SendRecruitLocation)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_BlockWarp)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_blockKilikaBoatChoice)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_RestoreInteraction)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_SetAirshipDestinations)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_ShowAirshipDestinations)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_HideAirshipDestinations)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_ShowCurrentAirshipLocation)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_HideCurrentAirshipLocation)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_TransitionToRegion)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_Jump)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_JumpIfFalse)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_JumpIfTrue)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_Offset)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_OffsetIfFalse)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_OffsetIfTrue)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_UpdateRegionState)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_LockPartyMember)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_LockAllAeons)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_IsGoalUnlocked)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_ReplaceEntryPoint)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_RestoreEntryPoint)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_LightningDodging)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_JechtSphere)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_KickedBlitzballAway)}, - new() { ret_int_func = (nint)(delegate* unmanaged[Cdecl])(&CT_RetInt_CheckUnlockedAeons)}, - }; - static GCHandle customNameSpaceHandle = GCHandle.Alloc(customNameSpace, GCHandleType.Pinned); + private GCHandle customNameSpaceHandle; + private AtelCallTarget[] customNameSpace; + - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_PushInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_PushInt(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int high = atelStack->pop_int(); int low = atelStack->pop_int(); int result = (high << 16) | low; - logger.Debug($"PushInt: ({high}, {low}) => {result}"); + _logger.Debug($"PushInt: ({high}, {low}) => {result}"); atelStack->push_int(result); return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_PushFloat(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_PushFloat(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { uint high = (uint)atelStack->pop_int() & 0xFFFF; uint low = (uint)atelStack->pop_int() & 0xFFFF; float result = BitConverter.Int32BitsToSingle((int)((high << 16) | low)); - logger.Debug($"PushFloat: ({high}, {low}) => {result}"); + _logger.Debug($"PushFloat: ({high}, {low}) => {result}"); atelStack->push_float(result); return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_IsCharacterUnlocked(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_IsCharacterUnlocked(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int character_id = atelStack->pop_int(); - logger.Debug($"IsCharacterUnlocked: {id_to_character[character_id]}"); + _logger.Debug($"IsCharacterUnlocked: {id_to_character[character_id]}"); return is_character_unlocked(character_id) ? 1 : 0; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_HasCelestialWeapon(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_HasCelestialWeapon(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int character_id = atelStack->pop_int(); - logger.Debug($"HasCelestialWeapon: {id_to_character[character_id]}"); + _logger.Debug($"HasCelestialWeapon: {id_to_character[character_id]}"); - foreach (var equip in Globals.save_data->equipment) { + foreach (var equip in save_data->equipment) { if (equip.exists && equip.owner == character_id && equip.is_celestial) return 1; } return 0; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_IsOtherLocationChecked(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_IsOtherLocationChecked(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int other_id = atelStack->pop_int(); - logger.Debug($"IsOtherLocationChecked: {other_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Other}"); + _logger.Debug($"IsOtherLocationChecked: {other_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Other}"); - return local_checked_locations.Contains(other_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Other) ? 1 : 0; + return _client!.local_checked_locations.Contains(other_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Other) ? 1 : 0; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_IsTreasureLocationChecked(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_IsTreasureLocationChecked(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int other_id = atelStack->pop_int(); - logger.Debug($"IsTreasureLocationChecked: {other_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure}"); + _logger.Debug($"IsTreasureLocationChecked: {other_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Treasure}"); - return local_checked_locations.Contains(other_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure) ? 1 : 0; + return _client!.local_checked_locations.Contains(other_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Treasure) ? 1 : 0; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_CollectedPrimers(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_CollectedPrimers(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int collected_primers = 0; for (int i = 0; i < 26; i++) { - collected_primers += Globals.save_data->unlocked_primers.get_bit(i) ? 1 : 0; + collected_primers += save_data->unlocked_primers.get_bit(i) ? 1 : 0; } - logger.Debug($"CollectedPrimers: {collected_primers}"); + _logger.Debug($"CollectedPrimers: {collected_primers}"); return collected_primers; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_SendOtherLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_SendOtherLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int other_id = atelStack->pop_int(); - if (!FFXArchipelagoClient.local_checked_locations.Contains(other_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Other)) { + if (!(_client!.local_checked_locations.Contains(other_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Other))) { if (ArchipelagoFFXModule.item_locations.other.TryGetValue(other_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(other_id, FFXArchipelagoClient.ArchipelagoLocationType.Other)) { - ArchipelagoFFXModule.obtain_item(item.id); + if (_client!.sendLocation(other_id, ArchipelagoClientModule.ArchipelagoLocationType.Other)) { + obtain_item(item.id); } } } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_SendPartyMemberLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_SendPartyMemberLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int partyMember_id = atelStack->pop_int(); - if (!FFXArchipelagoClient.local_checked_locations.Contains(partyMember_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { + if (!(_client!.local_checked_locations.Contains(partyMember_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember))) { if (ArchipelagoFFXModule.item_locations.party_member.TryGetValue(partyMember_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(partyMember_id, FFXArchipelagoClient.ArchipelagoLocationType.PartyMember)) { - ArchipelagoFFXModule.obtain_item(item.id); + if (_client!.sendLocation(partyMember_id, ArchipelagoClientModule.ArchipelagoLocationType.PartyMember)) { + obtain_item(item.id); } } } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_SendRecruitLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_SendRecruitLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int recruit_id = atelStack->pop_int(); - if (!FFXArchipelagoClient.local_checked_locations.Contains(recruit_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Recruit)) { + if (!(_client!.local_checked_locations.Contains(recruit_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Recruit))) { if (ArchipelagoFFXModule.item_locations.recruit.TryGetValue(recruit_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(recruit_id, FFXArchipelagoClient.ArchipelagoLocationType.Recruit)) { - ArchipelagoFFXModule.obtain_item(item.id); + if (_client!.sendLocation(recruit_id, ArchipelagoClientModule.ArchipelagoLocationType.Recruit)) { + obtain_item(item.id); } } } return 1; } - public static int atelTurnAround(Span dest, float x, float y, float z, ushort current_worker, ushort target_worker, ushort entry_point, float movementSpeed = 34.0f, float rotationSpeed1 = 0.10471976f, float rotationSpeed2 = 0.17453294f) { - logger?.Debug($"x={x}, y={y}, z={z}"); + public int atelTurnAround(Span dest, float x, float y, float z, ushort current_worker, ushort target_worker, ushort entry_point, float movementSpeed = 34.0f, float rotationSpeed1 = 0.10471976f, float rotationSpeed2 = 0.17453294f) { + _logger.Debug($"x={x}, y={y}, z={z}"); uint rotationFlags = 0x0000D002; uint motionFlags = 0x0000C001; byte[] script = ((AtelInst[])[ // 5 @@ -4063,46 +3756,42 @@ AtelOp.RET .build( ), } return script.Length; } - private static int turnAroundScriptLength = atelTurnAround(Span.Empty, 0, 0, 0, 0, 0, 0); - private static byte* turnAroundScript = (byte*)NativeMemory.AllocZeroed((uint)turnAroundScriptLength); - private static bool savedCrossInteractionStatus; - private static byte savedInteractionFlags; + private bool savedCrossInteractionStatus; + private byte savedInteractionFlags; - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_BlockWarp(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_BlockWarp(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { return blockWarp(work, storage, atelStack); } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_blockKilikaBoatChoice(AtelBasicWorker* worker, int* storage, AtelStack* stack) { + public int CT_RetInt_BlockKilikaBoatChoice(AtelBasicWorker* worker, int* storage, AtelStack* stack) { return blockKilikaBoatChoice(worker, storage, stack); } - public static int blockWarp(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int blockWarp(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int entrance = atelStack->pop_int(); int map = atelStack->pop_int(); - logger.Info($"Exit leads to other Region!"); + _logger.Info("Exit leads to other Region!"); - Chr* tidus = (Chr*)((int)Globals.Atel.controllers[0].worker(0) + 0x9c); + Chr* tidus = (Chr*)((int)Atel.controllers[0].worker(0) + 0x9c); if (tidus != null && tidus->actor != null) { Vector3 playerPos = tidus->actor->chr_pos_vec.AsVector3(); - var entrances = Globals.Atel.controllers[0].worker(0)->script_chunk->map_entrances.ToArray(); - var closestEntrance = Globals.Atel.controllers[0].worker(0)->script_chunk->map_entrances.ToArray() + var entrances = Atel.controllers[0].worker(0)->script_chunk->map_entrances.ToArray(); + var closestEntrance = Atel.controllers[0].worker(0)->script_chunk->map_entrances.ToArray() .Select((e, i) => new {Index=i, Entrance=e, Distance=(playerPos - e.pos).Length()}) .MinBy(tuple => tuple.Distance); if (closestEntrance?.Distance < 200) { - logger.Debug($"Entrance within 200: pos:({closestEntrance.Entrance.x}, {closestEntrance.Entrance.y}, {closestEntrance.Entrance.z}) distance:{closestEntrance.Distance}"); + _logger.Debug($"Entrance within 200: pos:({closestEntrance.Entrance.x}, {closestEntrance.Entrance.y}, {closestEntrance.Entrance.z}) distance:{closestEntrance.Distance}"); Vector3 target_pos = closestEntrance.Entrance.pos; - ushort entry_point = (ushort)(Globals.Atel.controllers[0].worker(0)->script_header->entry_point_count - 1); + ushort entry_point = (ushort)(Atel.controllers[0].worker(0)->script_header->entry_point_count - 1); if (turnAroundScript == null) turnAroundScript = (byte*)NativeMemory.AllocZeroed((uint)turnAroundScriptLength); atelTurnAround(new Span(turnAroundScript, turnAroundScriptLength), target_pos.X, target_pos.Y, target_pos.Z, work->worker_idx, 0, entry_point, 17, 1f, 1f); - AtelBasicWorker* targetWorker = Globals.Atel.controllers[0].worker(0); + AtelBasicWorker* targetWorker = Atel.controllers[0].worker(0); if (!originalEntryPoints.ContainsKey((0, entry_point))) { originalEntryPoints[(0, entry_point)] = targetWorker->table_entry_points[entry_point]; } @@ -4119,24 +3808,24 @@ public static int blockWarp(AtelBasicWorker* work, int* storage, AtelStack* atel atelStack->push_int(2); // signal priority? atelStack->push_int(0); // worker atelStack->push_int(entry_point); // entrypoint - _FUN_00867370((byte)AtelOp.REQEW & 0x7F, work, &work->threads[work->current_thread_priority], atelStack, 0); + FhXCall.FUN_00867370.fnptr!((byte)AtelOp.REQEW & 0x7F, work, &work->threads[work->current_thread_priority], atelStack, 0); work->__0x34 = (ushort)(work->__0x34 & 0xEBFF | 0x800); //work->__0x34 = (ushort)(work->__0x34 | 0x800); atelStack->pop_int(); - //_FUN_008671d0((byte)AtelOp.REQ & 0x7F, &work->threads[work->current_thread_priority], work, atelStack); + //FhXCall.FUN_008671d0.fnptr!((byte)AtelOp.REQ & 0x7F, &work->threads[work->current_thread_priority], work, atelStack); return 1; } - logger.Debug($"Closest entrance: pos:({closestEntrance?.Entrance.x}, {closestEntrance?.Entrance.y}, {closestEntrance?.Entrance.z}) distance:{closestEntrance?.Distance}"); + _logger.Debug($"Closest entrance: pos:({closestEntrance?.Entrance.x}, {closestEntrance?.Entrance.y}, {closestEntrance?.Entrance.z}) distance:{closestEntrance?.Distance}"); } + // Warp atelStack->push_int(382); atelStack->push_int(0); - h_Common_warpToMap(work, storage, atelStack); + Common_warpToMap(work, storage, atelStack); return 1; - } - public static int blockKilikaBoatChoice(AtelBasicWorker* worker, int* storage, AtelStack* stack) { + public int blockKilikaBoatChoice(AtelBasicWorker* worker, int* storage, AtelStack* stack) { uint choice = (uint)worker->current_thread.reg_a; if (choice == 0) { @@ -4149,22 +3838,20 @@ public static int blockKilikaBoatChoice(AtelBasicWorker* worker, int* storage, A return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_RestoreInteraction(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_RestoreInteraction(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int target_worker_index = atelStack->pop_int(); - AtelBasicWorker* target_worker = Globals.Atel.controllers[0].worker(target_worker_index); + AtelBasicWorker* target_worker = Atel.controllers[0].worker(target_worker_index); //if (savedCrossInteractionStatus) target_worker->field_interaction_flags |= 1 << 2; // Enable cross interaction target_worker->field_interaction_flags = savedInteractionFlags; return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_SetAirshipDestinations(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_SetAirshipDestinations(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { set_airship_destinations(); return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_ShowAirshipDestinations(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_ShowAirshipDestinations(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { var var_table = work->table_event_data; uint* airshipDestinations = &var_table[13]; uint airshipDestinationsOffset = var_table[50]; @@ -4185,73 +3872,68 @@ public static int CT_RetInt_ShowAirshipDestinations(AtelBasicWorker* work, int* return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_HideAirshipDestinations(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_HideAirshipDestinations(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { for (uint i = 0; i < 15; i++) { customStringDrawInfos.Remove($"destination {i}"); } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_ShowCurrentAirshipLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { - logger.Debug("ShowCurrentAirshipLocation"); + public int CT_RetInt_ShowCurrentAirshipLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + _logger.Debug("ShowCurrentAirshipLocation"); customStringDrawInfos[$"current destination"] = new CustomStringDrawInfo(airship_destination_names[save_data->current_airship_location], new(52f, 73f), 1f); // AE0300 D80F80 call Map.?show2DLayer [800Fh](layerIndex=3 [03h]); atelStack->push_int(3); - _Map_show2DLayerResultInt(work, storage, atelStack); + h_Map_show2DLayerResultInt.fnptr!(work, storage, atelStack); return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_HideCurrentAirshipLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { - logger.Debug("HideCurrentAirshipLocation"); + public int CT_RetInt_HideCurrentAirshipLocation(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + _logger.Debug("HideCurrentAirshipLocation"); customStringDrawInfos.Remove($"current destination"); // AE0300 D81080 call Map.?hide2DLayer [8010h](layerIndex=3 [03h]); atelStack->push_int(3); - _Map_hide2DLayerResultInt(work, storage, atelStack); + h_Map_hide2DLayerResultInt.fnptr!(work, storage, atelStack); return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_TransitionToRegion(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { - ArchipelagoData.RegionEnum region = (ArchipelagoData.RegionEnum)atelStack->pop_int(); + public int CT_RetInt_TransitionToRegion(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + RegionEnum region = (RegionEnum)atelStack->pop_int(); - if (current_region != ArchipelagoData.RegionEnum.None) { + if (current_region != RegionEnum.None) { update_region_state(); - current_region = ArchipelagoData.RegionEnum.None; + current_region = RegionEnum.None; skip_state_updates = false; } current_region = region; int map = 0, entrance = 0; restore_region_state(ref map, ref entrance); - logger.Debug($"Entering {region}: map={map}, entrance={entrance}"); + _logger.Debug($"Entering {region}: map={map}, entrance={entrance}"); // Unlock locked characters. May not be necessary - foreach (var character in ArchipelagoFFXModule.locked_characters) { - ArchipelagoFFXModule.locked_characters[character.Key] = false; + foreach (var character in locked_characters) { + locked_characters[character.Key] = false; } save_party(); reset_party(); atelStack->push_int(map); atelStack->push_int(entrance); - h_Common_transitionToMap(work, storage, atelStack); + Common_transitionToMap(work, storage, atelStack); return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_Jump(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_Jump(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int jump_index = atelStack->pop_int(); work->current_thread.pc = (byte*)customScriptHandles[jump_index].AddrOfPinnedObject() - 3; return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_JumpIfFalse(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_JumpIfFalse(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int jump_index = atelStack->pop_int(); int val = atelStack->pop_int(); if (val == 0) { @@ -4259,8 +3941,8 @@ public static int CT_RetInt_JumpIfFalse(AtelBasicWorker* work, int* storage, Ate } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_JumpIfTrue(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_JumpIfTrue(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int jump_index = atelStack->pop_int(); int val = atelStack->pop_int(); if (val == 1) { @@ -4268,14 +3950,14 @@ public static int CT_RetInt_JumpIfTrue(AtelBasicWorker* work, int* storage, Atel } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_Offset(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_Offset(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int offset = atelStack->pop_int(); work->current_thread.pc += offset; return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_OffsetIfFalse(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_OffsetIfFalse(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int offset = atelStack->pop_int(); int val = atelStack->pop_int(); if (val == 0) { @@ -4283,8 +3965,8 @@ public static int CT_RetInt_OffsetIfFalse(AtelBasicWorker* work, int* storage, A } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_OffsetIfTrue(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_OffsetIfTrue(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int offset = atelStack->pop_int(); int val = atelStack->pop_int(); if (val == 1) { @@ -4292,23 +3974,23 @@ public static int CT_RetInt_OffsetIfTrue(AtelBasicWorker* work, int* storage, At } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_UpdateRegionState(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { - Vector3 playerPos = Globals.actors->chr_pos_vec.AsVector3(); - var closestEntrance = Globals.Atel.controllers[0].worker(0)->script_chunk->map_entrances.ToArray() + + public int CT_RetInt_UpdateRegionState(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + Vector3 playerPos = actors->chr_pos_vec.AsVector3(); + var closestEntrance = Atel.controllers[0].worker(0)->script_chunk->map_entrances.ToArray() .Select((entrance, index) => new {Index=index, Entrance=entrance, Distance=(playerPos - entrance.pos).Length()}) .MinBy(tuple => tuple.Distance); if (closestEntrance?.Distance < 100) { save_data->current_spawnpoint = (byte)closestEntrance.Index; - logger.Debug($"Entrance within 100: pos:({closestEntrance.Entrance.x}, {closestEntrance.Entrance.y}, {closestEntrance.Entrance.z}) distance:{closestEntrance.Distance}"); + _logger.Debug($"Entrance within 100: pos:({closestEntrance.Entrance.x}, {closestEntrance.Entrance.y}, {closestEntrance.Entrance.z}) distance:{closestEntrance.Distance}"); } update_region_state(save_data->current_room_id, save_data->current_spawnpoint); refill_inventory(); return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_LockPartyMember(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_LockPartyMember(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int party_member = atelStack->pop_int(); locked_characters[party_member] = true; if (party_member == PlySaveId.PC_MAGUS1) { @@ -4317,45 +3999,48 @@ public static int CT_RetInt_LockPartyMember(AtelBasicWorker* work, int* storage, } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_LockAllAeons(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_LockAllAeons(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { for (int chr_id = PlySaveId.PC_VALEFOR; chr_id <= PlySaveId.PC_MAGUS3; chr_id++) { locked_characters[chr_id] = true; } + return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_IsGoalUnlocked(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_IsGoalUnlocked(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { bool goal_requirement = false; bool primer_requirement = false; switch (seed.Options.GoalRequirement) { - case ArchipelagoData.GoalRequirement.None: + case GoalRequirement.None: goal_requirement = true; break; - case ArchipelagoData.GoalRequirement.PartyMembers: - if (unlocked_characters.Where(x => x.Key < 8 && x.Value).Count() >= Math.Min(seed.Options.RequiredPartyMembers, 8)) + case GoalRequirement.PartyMembers: + if (unlocked_characters.Count(x => x.Key < 8 && x.Value) >= Math.Min(seed.Options.RequiredPartyMembers, 8)) goal_requirement = true; //if (unlocked_characters.All(c => c.Value)) { // return 1; //} break; - case ArchipelagoData.GoalRequirement.PartyMembersAndAeons: - if (unlocked_characters.Where(x => x.Key < 16 && x.Value).Count() >= seed.Options.RequiredPartyMembers) + case GoalRequirement.PartyMembersAndAeons: + if (unlocked_characters.Count(x => x.Key < 16 && x.Value) >= seed.Options.RequiredPartyMembers) goal_requirement = true; break; - case ArchipelagoData.GoalRequirement.Pilgrimage: - if (local_checked_locations.Contains(8 | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember) && - local_checked_locations.Contains(9 | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember) && - local_checked_locations.Contains(10 | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember) && - local_checked_locations.Contains(11 | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember) && - local_checked_locations.Contains(12 | (long)FFXArchipelagoClient.ArchipelagoLocationType.PartyMember) && - local_checked_locations.Contains(37 | (long)FFXArchipelagoClient.ArchipelagoLocationType.Boss)) { + case GoalRequirement.Pilgrimage: + if ( + _client!.local_checked_locations.Contains(8 | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember) + && _client!.local_checked_locations.Contains(9 | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember) + && _client!.local_checked_locations.Contains(10 | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember) + && _client!.local_checked_locations.Contains(11 | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember) + && _client!.local_checked_locations.Contains(12 | (long)ArchipelagoClientModule.ArchipelagoLocationType.PartyMember) + && _client!.local_checked_locations.Contains(37 | (long)ArchipelagoClientModule.ArchipelagoLocationType.Boss) + ) { goal_requirement = true; } break; - case ArchipelagoData.GoalRequirement.Nemesis: - if (local_checked_locations.Contains(83 | (long)FFXArchipelagoClient.ArchipelagoLocationType.Boss)) { + case GoalRequirement.Nemesis: + if (_client!.local_checked_locations.Contains(83 | (long)ArchipelagoClientModule.ArchipelagoLocationType.Boss)) { goal_requirement = true; } break; @@ -4364,7 +4049,7 @@ public static int CT_RetInt_IsGoalUnlocked(AtelBasicWorker* work, int* storage, if (seed.Options.RequiredPrimers > 0) { int collected_primers = 0; for (int i = 0; i < 26; i++) { - collected_primers += Globals.save_data->unlocked_primers.get_bit(i) ? 1 : 0; + collected_primers += save_data->unlocked_primers.get_bit(i) ? 1 : 0; } if (collected_primers >= seed.Options.RequiredPrimers) @@ -4376,13 +4061,13 @@ public static int CT_RetInt_IsGoalUnlocked(AtelBasicWorker* work, int* storage, return goal_requirement && primer_requirement ? 1 : 0; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_ReplaceEntryPoint(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_ReplaceEntryPoint(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int script_index = atelStack->pop_int(); int entryPoint = atelStack->pop_int(); int workerIndex = atelStack->pop_int(); - AtelBasicWorker* targetWorker = Globals.Atel.controllers[0].worker(workerIndex); + AtelBasicWorker* targetWorker = Atel.controllers[0].worker(workerIndex); if (!originalEntryPoints.ContainsKey((workerIndex, entryPoint))) { originalEntryPoints[(workerIndex, entryPoint)] = targetWorker->table_entry_points[entryPoint]; @@ -4395,18 +4080,17 @@ public static int CT_RetInt_ReplaceEntryPoint(AtelBasicWorker* work, int* storag targetWorker->table_entry_points[entryPoint] = (uint)addressOffset; return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_RestoreEntryPoint(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + + public int CT_RetInt_RestoreEntryPoint(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int entryPoint = atelStack->pop_int(); int workerIndex = atelStack->pop_int(); if (originalEntryPoints.TryGetValue((workerIndex, entryPoint), out uint value)) { - Globals.Atel.controllers[0].worker(workerIndex)->table_entry_points[entryPoint] = value; + Atel.controllers[0].worker(workerIndex)->table_entry_points[entryPoint] = value; } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_LightningDodging(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_LightningDodging(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int southNorth = atelStack->pop_int(); ushort highestDodged = save_data->lightning_dodging_highest_consecutive_dodges; byte* table = (byte*)work->table_event_data; @@ -4433,27 +4117,26 @@ public static int CT_RetInt_LightningDodging(AtelBasicWorker* work, int* storage string currentString = $"Dodged: {current}"; customStringDrawInfos["Lightning Streak"] = new CustomStringDrawInfo(new ManagedCustomString(currentString), new(40f, 140f), 0.5f); - logger.Info($"Lightning Dodged: {current}"); + _logger.Info($"Lightning Dodged: {current}"); if (current > save_data->lightning_dodging_highest_consecutive_dodges) highestDodged = (ushort)current; string highestString = $"Highest: {highestDodged}"; customStringDrawInfos["Lightning Highest Streak"] = new CustomStringDrawInfo(new ManagedCustomString(highestString), new(40f, 150f), 0.5f); - logger.Info($"Highest Consecutive Dodged: {highestDodged}"); + _logger.Info($"Highest Consecutive Dodged: {highestDodged}"); return *dodged == 1 ? 1 : 0; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_JechtSphere(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_JechtSphere(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int jecht_sphere = atelStack->pop_int(); int other_id = atelStack->pop_int(); - if (!FFXArchipelagoClient.local_checked_locations.Contains(other_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Other)) { + if (!(_client!.local_checked_locations.Contains(other_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Other))) { if (ArchipelagoFFXModule.item_locations.other.TryGetValue(other_id, out var item)) { - if (FFXArchipelagoClient.sendLocation(other_id, FFXArchipelagoClient.ArchipelagoLocationType.Other)) { - ArchipelagoFFXModule.obtain_item(item.id); + if (_client!.sendLocation(other_id, ArchipelagoClientModule.ArchipelagoLocationType.Other)) { + obtain_item(item.id); } } } @@ -4462,39 +4145,33 @@ public static int CT_RetInt_JechtSphere(AtelBasicWorker* work, int* storage, Ate return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_KickedBlitzballAway(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_KickedBlitzballAway(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { byte* table = (byte*)work->table_event_data; table[0x0008] = 1; int treasure_id = 312; - if (!FFXArchipelagoClient.local_checked_locations.Contains(treasure_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure)) - { - if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) - { - lock (client_lock) - { - if (FFXArchipelagoClient.is_connected) - { - FFXArchipelagoClient.current_session!.Locations.ScoutLocationsAsync(Archipelago.MultiClient.Net.Enums.HintCreationPolicy.CreateAndAnnounceOnce, - treasure_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure); + if (!(_client!.local_checked_locations.Contains(treasure_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Treasure))) { + if (ArchipelagoFFXModule.item_locations.treasure.TryGetValue(treasure_id, out var item)) { + lock (_client!.client_lock) { + if (_client!.is_connected) { + _client!.current_session!.Locations.ScoutLocationsAsync(Archipelago.MultiClient.Net.Enums.HintCreationPolicy.CreateAndAnnounceOnce, + treasure_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Treasure); } } - FFXArchipelagoClient.SayAsync($"kicked away {item.player}'s {item.name}!"); + _client!.SayAsync($"kicked away {item.player}'s {item.name}!"); } } return 1; } - [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvCdecl) })] - public static int CT_RetInt_CheckUnlockedAeons(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + public int CT_RetInt_CheckUnlockedAeons(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { uint aeon_bitfield = work->table_priv_data[0]; - logger.Info($"aeon_bitfield: {aeon_bitfield}"); + _logger.Info($"aeon_bitfield: {aeon_bitfield}"); uint temp = aeon_bitfield; for (int i = 0; i < PlySaveId.PC_DUMMY; i++) { - logger.Info($"{id_to_character[i]}: {(temp & 1) == 1}"); + _logger.Info($"{id_to_character[i]}: {(temp & 1) == 1}"); temp >>= 1; } @@ -4502,13 +4179,33 @@ public static int CT_RetInt_CheckUnlockedAeons(AtelBasicWorker* work, int* stora return 1; } - if (!FFXArchipelagoClient.local_checked_locations.Contains(41 | (long)FFXArchipelagoClient.ArchipelagoLocationType.Boss)) { + if (!(_client!.local_checked_locations.Contains(41 | (long)ArchipelagoClientModule.ArchipelagoLocationType.Boss))) { if (ArchipelagoFFXModule.item_locations.boss.TryGetValue(41, out var item)) { - if (FFXArchipelagoClient.sendLocation(41, FFXArchipelagoClient.ArchipelagoLocationType.Boss)) { - ArchipelagoFFXModule.obtain_item(item.id); + if (_client!.sendLocation(41, ArchipelagoClientModule.ArchipelagoLocationType.Boss)) { + obtain_item(item.id); } } } return 0; } + + public struct CustomStringDrawInfo(ManagedCustomString customString, Vector2 pos, float scale = 0.65f, byte color = 0, bool persistent = false) { + public ManagedCustomString customString = customString; + public Vector2 pos = pos; + public float scale = scale; + public byte color = color; + public bool persistent = persistent; + } + + public Dictionary customStringDrawInfos = []; + + public void render_game() { + FhXCall.TODrawWindow.chain_from(render_game).fnptr!(); + + foreach ((string key, CustomStringDrawInfo drawInfo) in customStringDrawInfos) { + fixed (byte* text = drawInfo.customString.encoded) { + FhXCall.TOMkpCrossExtMesFontLClutTypeRGBA.fnptr!(0, text, drawInfo.pos.X, drawInfo.pos.Y, drawInfo.color, 0, 0x80, 0x80, 0x80, 0x80, drawInfo.scale, 0); + } + } + } } diff --git a/src/modules/captures.cs b/src/modules/captures.cs index 063e666..17be65d 100644 --- a/src/modules/captures.cs +++ b/src/modules/captures.cs @@ -1,103 +1,51 @@ -using System; - -using Archipelago.MultiClient.Net.Enums; +using Archipelago.MultiClient.Net.Enums; +using ArchipelagoFFX.Client; +using Fahrenheit; using Fahrenheit.Atel; using Fahrenheit.FFX; using Fahrenheit.FFX.Battle; - +using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; - -using ArchipelagoFFX.Client; - -using Fahrenheit; - +using static ArchipelagoFFX.Client.ArchipelagoClientModule; using static Fahrenheit.FFX.Globals; -using static ArchipelagoFFX.Client.FFXArchipelagoClient; -using static ArchipelagoFFX.delegates; +using FhGCall = Fahrenheit.FhCall; +using FhXCall = Fahrenheit.FFX.FhCall; namespace ArchipelagoFFX; [FhLoad(FhGameId.FFX)] -public unsafe partial class CaptureModule : FhModule { - // Some structs that Fahrenheit is currently missing - [StructLayout(LayoutKind.Sequential)] - private struct BtlBinField { - [InlineArray(8)] - public struct FieldName { - private byte _data; - } - - public short id; - public short data_offset; - public short __0x4; - public FieldName name; - } - - [StructLayout(LayoutKind.Explicit, Size = 0x2)] - private struct BtlBinEncounter { - [FieldOffset(0x0)] public byte total_formation_count; - [FieldOffset(0x1)] public byte group_count; +public unsafe class CaptureModule : FhModule { + private FhModuleHandle _client_handle; + private ArchipelagoClientModule? _client; - [FieldOffset(0x2)] private BtlBinGroup _first_group; - - [UnscopedRef] - public Span groups => MemoryMarshal.CreateSpan(ref _first_group, group_count); - } - - [StructLayout(LayoutKind.Explicit, Size = 0x5)] - private struct BtlBinGroup { - [FieldOffset(0x0)] public byte formation_count; - [FieldOffset(0x1)] public short battlefield; - [FieldOffset(0x3)] public byte grace; - [FieldOffset(0x4)] public byte total_weight; - - [FieldOffset(0x5)] private BtlBinFormation _first_formation; - - [UnscopedRef] - public Span formations => MemoryMarshal.CreateSpan(ref _first_formation, formation_count); - } - - [StructLayout(LayoutKind.Sequential)] - private struct BtlBinFormation { - public byte index; - public byte weight; - } - - private FhModContext? _mod_context; - private FileStream? _global_state; + private FhModuleHandle _ffx_interop_handle; + private ArchipelagoFFXModule? _ffx_interop; public CaptureModule() { - const string GAME = "FFX.exe"; - - _MsMonsterCapture = new FhMethodHandle(this, GAME, __addr_MsMonsterCapture, h_MsMonsterCapture); - _FUN_00783bb0 = new FhMethodHandle(this, GAME, __addr_FUN_00783bb0, h_FUN_00783bb0); - _AtelEventSetUp = new FhMethodHandle(this, GAME, __addr_AtelEventSetUp, h_AtelEventSetUp); - _ret_hasKeyItem = new FhMethodHandle(this, GAME, __addr_ret_hasKeyItem, h_ret_hasKeyItem); - _MsDamageCheckDeath = new FhMethodHandle(this, GAME, __addr_MsDamageCheckDeath, h_MsDamageCheckDeath); - _MsSetRamChrParam = new FhMethodHandle(this, GAME, __addr_MsSetRamChrParam, h_MsSetRamChrParam); - _MsSetSaveParam = new FhMethodHandle(this, GAME, __addr_MsSetSaveParam, h_MsSetSaveParam); - _MsCalcCommand = new FhMethodHandle(this, GAME, __addr_MsCalcCommand, h_MsCalcCommand); - _MsBattleEncountExe = new FhMethodHandle(this, GAME, __addr_MsBattleEncountExe, h_MsBattleEncountExe); + _client_handle = new(this); + _ffx_interop_handle = new(this); } + // TODO: Remove once Fahrenheit adds Atel call targets to FhCall + // Mars Sigil location check (Atel CT_RetInt hook); not yet a curated FhCall entry, so kept as a local handle. + private FhMethodHandle h_ret_hasKeyItem_handle + => new( new FhMethodLocation("FFX.exe", 0x45B7A0) ); + public override bool init(FhModContext mod_context, FileStream global_state_file) { - _mod_context = mod_context; - _global_state = global_state_file; - - return _MsMonsterCapture.hook() - && _FUN_00783bb0.hook() - && _AtelEventSetUp.hook() - && _ret_hasKeyItem.hook() - && _MsDamageCheckDeath.hook() - && _MsSetRamChrParam.hook() - && _MsSetSaveParam.hook() - && _MsCalcCommand.hook() - && _MsBattleEncountExe.hook(); + return _client_handle.try_get_module(out _client) + && _ffx_interop_handle.try_get_module(out _ffx_interop) + && FhXCall.MsMonsterCapture.hook(this, h_MsMonsterCapture) + && FhXCall.FUN_00783bb0.hook(this, h_FUN_00783bb0) + && FhXCall.AtelEventSetUp.hook(this, h_AtelEventSetUp) + && h_ret_hasKeyItem_handle.hook(this, ret_hasKeyItem) + && FhXCall.MsDamageCheckDeath.hook(this, h_MsDamageCheckDeath) + && FhXCall.MsSetRamChrParam.hook(this, h_MsSetRamChrParam) + && FhXCall.MsSetSaveParam.hook(this, h_MsSetSaveParam) + && FhXCall.MsCalcCommand.hook(this, h_MsCalcCommand) + && FhXCall.MsBattleEncountExe.hook(this, h_MsBattleEncountExe); } private static void set(byte* code_ptr, uint offset, AtelInst[] opcodes) { @@ -117,30 +65,30 @@ private static void set(byte* code_ptr, uint[] offsets, AtelInst[] opcodes) { } private bool h_MsMonsterCapture(int target_id, int arena_idx) { - bool captured = _MsMonsterCapture.orig_fptr(target_id, arena_idx); + bool captured = FhXCall.MsMonsterCapture.chain_from(h_MsMonsterCapture).fnptr!(target_id, arena_idx); _logger.Info($"Fiend Capture: Target={target_id}, Arena Index={arena_idx}, Captured={captured}"); // Send AP Location if successfully captured if (captured) { - if (sendLocation(arena_idx, FFXArchipelagoClient.ArchipelagoLocationType.Capture) && ArchipelagoFFXModule.item_locations.capture.TryGetValue(arena_idx, out var item)) { - ArchipelagoFFXModule.obtain_item(item.id); - } + lock (_client!.client_lock) { + if (_client!.sendLocation(arena_idx, ArchipelagoLocationType.Capture) && ArchipelagoFFXModule.item_locations.capture.TryGetValue(arena_idx, out var item)) { + _ffx_interop!.obtain_item(item.id); + } - int amount = save_data->monsters_captured[arena_idx]; - lock (FFXArchipelagoClient.client_lock) { - if (FFXArchipelagoClient.is_connected) { + int amount = save_data->monsters_captured[arena_idx]; + if (_client!.is_connected) { if (amount > 0) - FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_CAPTURE_" + arena_idx] = amount; + _client!.current_session!.DataStorage[Scope.Slot, "FFX_CAPTURE_" + arena_idx] = amount; else - FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_CAPTURE_" + arena_idx] = 0; + _client!.current_session!.DataStorage[Scope.Slot, "FFX_CAPTURE_" + arena_idx] = 0; } } } return captured; } - private HashSet initialized_monsters = []; + private readonly HashSet initialized_monsters = []; private static readonly HashSet _incorrect_arena_idx = [ 041, // Sahagin 042, // Sahagin @@ -162,11 +110,11 @@ private void h_FUN_00783bb0(byte mon_idx) { byte num_initialized = FhUtil.get_at(0xD2CA80); if (num_initialized == 0) initialized_monsters.Clear(); - _FUN_00783bb0.orig_fptr(mon_idx); + FhXCall.FUN_00783bb0.chain_from(h_FUN_00783bb0).fnptr!(mon_idx); - Chr* mon = _MsGetMon(mon_idx); + Chr* mon = FhXCall.MsGetMon.fnptr!(mon_idx); if (initialized_monsters.Add(mon->chr_id)) { - MonStats* stats = (MonStats*)mon->ptr_base_stats; + MonStats* stats = mon->ptr_base_stats; // Corrects incorrect monster arena indexes to be uncapturable if (_incorrect_arena_idx.Contains((short)(mon->chr_id & 0xFFF))) { @@ -180,11 +128,11 @@ private void h_FUN_00783bb0(byte mon_idx) { private string? _event_name; private void h_AtelEventSetUp(int event_id) { - _AtelEventSetUp.orig_fptr(event_id); + FhXCall.AtelEventSetUp.chain_from(h_AtelEventSetUp).fnptr!(event_id); - _event_name = Marshal.PtrToStringAnsi((nint)get_event_name((uint)event_id))!; + _event_name = Marshal.PtrToStringAnsi((nint)FhXCall.AtelGetEventName.fnptr!((uint)event_id))!; _logger.Debug($"atel_event_setup: {_event_name}"); - byte* code_ptr = Globals.Atel.controllers[0].worker(0)->code_ptr; + byte* code_ptr = Atel.controllers[0].worker(0)->code_ptr; switch (_event_name) { case "nagi0700": @@ -206,24 +154,26 @@ private void h_AtelEventSetUp(int event_id) { } //Check Mars Sigil location instead of inventory - private int h_ret_hasKeyItem(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { + private int ret_hasKeyItem(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { if (_event_name == "nagi0700") { int item_id = atelStack->pop_int(); if (item_id == 0xA028) { - return local_checked_locations.Contains(276 | (long)FFXArchipelagoClient.ArchipelagoLocationType.Treasure) ? 1 : 0; + lock (_client!.client_lock) { + return _client!.local_checked_locations.Contains(276 | (long)ArchipelagoLocationType.Treasure) ? 1 : 0; + } } else { atelStack->push_int(item_id); } } - return _ret_hasKeyItem.orig_fptr(work, storage, atelStack); + return h_ret_hasKeyItem_handle.chain_from(ret_hasKeyItem).fnptr!(work, storage, atelStack); } - private int h_MsDamageCheckDeath(int attacker_id, int target_id, int param_3, uint param_4) { - Chr* target = _MsGetChr((uint)target_id); - MonStats* mon_stats = (MonStats*)target->ptr_base_stats; + private int h_MsDamageCheckDeath(int attacker_id, int target_id, int param_3, int param_4) { + Chr* target = FhXCall.MsGetChr.fnptr!(target_id); + MonStats* mon_stats = target->ptr_base_stats; ushort capture_index = mon_stats is not null ? mon_stats->monster_arena_idx : (ushort)0xFF; @@ -236,13 +186,13 @@ private int h_MsDamageCheckDeath(int attacker_id, int target_id, int param_3, ui target->should_try_capture = true; } - return _MsDamageCheckDeath.orig_fptr(attacker_id, target_id, param_3, param_4); + return FhXCall.MsDamageCheckDeath.chain_from(h_MsDamageCheckDeath).fnptr!(attacker_id, target_id, param_3, param_4); } private void h_MsSetRamChrParam(uint chr_id) { - _MsSetRamChrParam.orig_fptr(chr_id); + FhXCall.MsSetRamChrParam.chain_from(h_MsSetRamChrParam).fnptr!(chr_id); - Chr* chr = _MsGetChr(chr_id); + Chr* chr = FhXCall.MsGetChr.fnptr!((int)chr_id); if (ArchipelagoFFXModule.seed.Options.AlwaysCapture == 1) { chr->ram.auto_ability_effects.has_capture = true; @@ -250,7 +200,7 @@ private void h_MsSetRamChrParam(uint chr_id) { } private void h_MsSetSaveParam(uint chr_id) { - _MsSetSaveParam.orig_fptr(chr_id); + FhXCall.MsSetSaveParam.chain_from(h_MsSetSaveParam).fnptr!(chr_id); // Does nothing?? if (ArchipelagoFFXModule.seed.Options.AlwaysCapture == 1) { @@ -259,19 +209,19 @@ private void h_MsSetSaveParam(uint chr_id) { } private void h_MsCalcCommand(AttackCue* param_1, int param_2) { - _MsCalcCommand.orig_fptr(param_1, param_2); + FhXCall.MsCalcCommand.chain_from(h_MsCalcCommand).fnptr!(param_1, param_2); if (param_1 == null) return; uint local_6c; - Command* command = _MsGetCommand(param_1->attacker_id, 0, -1, ¶m_1->command_list[param_2], &local_6c); + Command* command = FhXCall.MsGetCommand.fnptr!(param_1->attacker_id, 0, -1, ¶m_1->command_list[param_2], &local_6c); if (param_1->command_count <= param_2 || command == null) return; - Chr* attacker = _MsGetChr(param_1->attacker_id); + Chr* attacker = FhXCall.MsGetChr.fnptr!(param_1->attacker_id); int[] local_7c = [0, 0, 0, param_2]; if (command->absorbs_dmg) { - local_7c[2] = (int)_FUN_0078d100(attacker); + local_7c[2] = (int)FhXCall.FUN_0078d100.fnptr!(attacker); } //TODO: Figure out a way not to duplicate affection in _FUN_0078bb30 @@ -280,7 +230,7 @@ private void h_MsCalcCommand(AttackCue* param_1, int param_2) { fixed (byte* p_targets = targets) { fixed (byte* p_local_48 = local_48) { fixed (int* p_local_7c = local_7c) { - _FUN_0078bb30(param_1->attacker_id, p_targets, p_local_48, command, local_6c, ¶m_1->command_list[param_2].targets, p_local_7c + 1); + FhXCall.FUN_0078bb30.fnptr!(param_1->attacker_id, p_targets, p_local_48, command, local_6c, ¶m_1->command_list[param_2].targets, p_local_7c + 1); } } } @@ -288,8 +238,8 @@ private void h_MsCalcCommand(AttackCue* param_1, int param_2) { for (uint target_id = 0; target_id < 32; target_id++) { if (targets[target_id] != 0) { if (local_7c[2] == 0 || target_id != param_1->attacker_id) { - Chr* target = _MsGetChr(target_id); - uint iVar6 = _FUN_0078d100(target); + Chr* target = FhXCall.MsGetChr.fnptr!((int)target_id); + uint iVar6 = FhXCall.FUN_0078d100.fnptr!(target); if (iVar6 != 0) { if (attacker->ram.auto_ability_effects.has_capture && Battle.btl->battle_type == 0 && (ArchipelagoFFXModule.seed.Options.CaptureDamage > 0 || command->uses_weapon_properties)) { target->should_try_capture = true; @@ -307,19 +257,19 @@ private int get_monster_arena_idx(int monster_id) { byte[] filename = Encoding.UTF8.GetBytes($"host0:/ffx/master/jppc/battle/mon/_m{monster_id:D3}/m{monster_id:D3}.bin"); fixed (byte* filename_ptr = &filename[0]) { - void* filestream = _sceOpen(filename_ptr, 1); + void* filestream = FhXCall.sceOpen.fnptr!(filename_ptr, 1); if (filestream is null) { _logger.Info("Failed to open monster file"); return -1; } - int filesize = _sceLseek(filestream, 0, 2); - _sceLseek(filestream, 0, 0); + int filesize = FhXCall.sceLseek.fnptr!(filestream, 0, 2); + FhXCall.sceLseek.fnptr!(filestream, 0, 0); void* file = NativeMemory.Alloc((nuint)filesize); - _sceRead(filestream, file, filesize); - _sceClose(filestream); + FhXCall.sceRead.fnptr!(filestream, file, filesize); + FhXCall.sceClose.fnptr!(filestream); int stats_offset = *(int*)((int)file + 0xC); MonStats* mon_stats = (MonStats*)((int)file + stats_offset); @@ -517,16 +467,16 @@ private int get_extra_weight_for_formation(BtlBinField* field, BtlBinFormation f float extra_weight = 0.0f; fixed (byte* filepath_ptr = &filepath[0]) { - void* open_result = _sceOpen(filepath_ptr, 1); + void* open_result = FhXCall.sceOpen.fnptr!(filepath_ptr, 1); if (open_result is null) return 0; - int file_size = _sceLseek(open_result, 0, 2); - _sceLseek(open_result, 0, 0); + int file_size = FhXCall.sceLseek.fnptr!(open_result, 0, 2); + FhXCall.sceLseek.fnptr!(open_result, 0, 0); void* file = NativeMemory.Alloc((nuint)file_size); - _sceRead(open_result, file, file_size); - _sceClose(open_result); + FhXCall.sceRead.fnptr!(open_result, file, file_size); + FhXCall.sceClose.fnptr!(open_result); int chunk_ptr = *(int*)((nint)file + 0xC); if (chunk_ptr != 0) { @@ -575,7 +525,7 @@ private int get_extra_weight_for_formation(BtlBinField* field, BtlBinFormation f private int h_MsBattleEncountExe(int field_id, int group_idx, float walked_delta) { if (ArchipelagoFFXModule.seed.Options.CaptureRequirement == 0 || ArchipelagoFFXModule.seed.Options.EncounterWeighting == 0) { - return _MsBattleEncountExe.orig_fptr(field_id, group_idx, walked_delta); + return FhXCall.MsBattleEncountExe.chain_from(h_MsBattleEncountExe).fnptr!(field_id, group_idx, walked_delta); } // Globals @@ -591,14 +541,14 @@ private int h_MsBattleEncountExe(int field_id, int group_idx, float walked_delta // _logger.Info($" g_encounter_level = {*g_encounter_level}"); // _logger.Info($" EnableBattle = {*EnableBattle}"); - int field_idx = _MsBtlListFieldNum(field_id); + int field_idx = FhXCall.MsBtlListFieldNum.fnptr!(field_id); if (*g_keybattle != 0 && *g_keydown_R != 0) { Battle.btl->group_idx = (byte)group_idx; Battle.btl->formation_idx = (byte)*DAT_0112ca28; *(byte*)((nint)Battle.btl + 0x12) = 1; Battle.btl->field_idx = (ushort)field_idx; - _ResetEncountExe(1); + FhXCall.ResetEncountExe.fnptr!(1); return -1; } @@ -620,15 +570,15 @@ private int h_MsBattleEncountExe(int field_id, int group_idx, float walked_delta if (field_idx < 0) return 0; if (walked_delta <= 0.0f || !can_encounter) return 0; - BtlBinField* field = _MsBtlListField(field_idx); - BtlBinEncounter* encounter = _MsBtlListEncount(field_idx); + BtlBinField* field = FhXCall.MsBtlListField.fnptr!(field_idx); + BtlBinEncounter* encounter = FhXCall.MsBtlListEncount.fnptr!(field_idx); // _logger.Info($" encounter->group_count: {encounter->group_count}"); if (group_idx < 0 || group_idx >= encounter->group_count) return 0; if (*EnableBattle == 0) return 0; - BtlBinGroup* group = _MsBtlListGroup(field_idx, group_idx); + BtlBinGroup* group = FhXCall.MsBtlListGroup.fnptr!(field_idx, group_idx); if (group->grace == 0 || group->total_weight == 0 || group->formation_count == 0) return 0; @@ -649,7 +599,7 @@ private int h_MsBattleEncountExe(int field_id, int group_idx, float walked_delta *(float*)((nint)Battle.btl + 0x110) *= 256.0f - encounter_chance; *(float*)((nint)Battle.btl + 0x114) *= 256.0f; - if ((_brnd(0) & 0xFF) >= encounter_chance) continue; + if ((FhXCall.brnd.fnptr!(0) & 0xFF) >= encounter_chance) continue; // We have to prepare weights first int total_weight = group->total_weight; @@ -657,7 +607,8 @@ private int h_MsBattleEncountExe(int field_id, int group_idx, float walked_delta bool all_complete = true; for (int formation_idx = 0; formation_idx < group->formation_count; formation_idx++) { - BtlBinFormation formation = group->formations[formation_idx]; + //BtlBinFormation formation = group->formations[formation_idx]; + BtlBinFormation formation = MemoryMarshal.CreateSpan(ref group->first_formation, group->formation_count)[formation_idx]; if (formation.weight == 0) { weights[formation_idx] = 0; @@ -687,13 +638,14 @@ private int h_MsBattleEncountExe(int field_id, int group_idx, float walked_delta total_weight = group->total_weight; for (int formation_idx = 0; formation_idx < group->formation_count; formation_idx++) { - BtlBinFormation formation = group->formations[formation_idx]; + //BtlBinFormation formation = group->formations[formation_idx]; + BtlBinFormation formation = MemoryMarshal.CreateSpan(ref group->first_formation, group->formation_count)[formation_idx]; weights[formation_idx] = formation.weight / 17; } } // Let's figure out which formation we should encounter! - int formation_rng = _brnd(1) % total_weight; + int formation_rng = FhXCall.brnd.fnptr!(1) % total_weight; int iVar7 = 0; _logger.Debug( "Encounter!"); @@ -709,14 +661,14 @@ private int h_MsBattleEncountExe(int field_id, int group_idx, float walked_delta if (*(byte*)((nint)Battle.btl + 0x27) == 0) { *(byte*)((nint)Battle.btl + 0x12) = 1; } else { - _Sg_FadeInW(3); + FhXCall.Sg_FadeInW.fnptr!(3); save_data->battle_count += 1; } Battle.btl->field_idx = (ushort)field_idx; Battle.btl->group_idx = (byte)group_idx; Battle.btl->formation_idx = (byte)formation_idx; - _ResetEncountExe(1); + FhXCall.ResetEncountExe.fnptr!(1); return -1; } diff --git a/src/modules/deathlink.cs b/src/modules/deathlink.cs index 7a22fce..c761119 100644 --- a/src/modules/deathlink.cs +++ b/src/modules/deathlink.cs @@ -1,22 +1,20 @@ -using System; -using System.IO; -using System.Numerics; -using System.Runtime.InteropServices; -using System.Text; - using Archipelago.MultiClient.Net.BounceFeatures.DeathLink; - using ArchipelagoFFX.Client; - using Fahrenheit; using Fahrenheit.FFX; using Fahrenheit.FFX.Battle; using Fahrenheit.FFX.Ids; +using System; +using System.IO; +using System.Numerics; +using System.Runtime.InteropServices; +using System.Text; +using FhXCall = Fahrenheit.FFX.FhCall; namespace ArchipelagoFFX; [FhLoad(FhGameId.FFX)] -public unsafe partial class DeathLinkModule : FhModule { +public unsafe class DeathLinkModule : FhModule { public enum DeathLinkSendType { GameOver, KO, @@ -32,11 +30,10 @@ public enum DeathLinkReceiveType { public static readonly Vector4 DEATHLINK_COLOR = new(1.0f, 0.18f, 0.21f, 1.0f); - // This is annoying but necessary for now because `FFXArchipelagoClient` wants everything to be static - //TODO: Remove this once it's no longer necessary - private static DeathLinkModule _this; + private ArchipelagoFFXModule.NativeCustomString _deathlink_announcement; - private static ArchipelagoFFXModule.NativeCustomString _deathlink_announcement; + private FhModuleHandle _client_handle; + private ArchipelagoClientModule? _client; private readonly FhModuleHandle _toasts_handle; private ToastModule? _toasts; @@ -52,75 +49,68 @@ public enum DeathLinkReceiveType { private bool deathlink_grace = false; public DeathLinkModule() { - _this = this; - _deathlink_announcement = new("Deathlink!"); + _client_handle = new(this); _toasts_handle = new(this); - - const string GAME = "FFX.exe"; - - _MsBtlReadManage = new(this, GAME, __addr_MsBtlReadManage, _h_MsBtlReadManage); - _MsDamageCheckDeath = new(this, GAME, __addr_MsDamageCheckDeath, _h_MsDamageCheckDeath); - _MsGetBattleEndStatus = new(this, GAME, __addr_MsGetBattleEndStatus, _h_MsGetBattleEndStatus); } - public static bool get_enabled() { - return _this._deathlink_enabled; + public bool get_enabled() { + return _deathlink_enabled; } - public static void set_enabled(bool value) { - _this._deathlink_enabled = value; + public void set_enabled(bool value) { + _deathlink_enabled = value; - if (!_this._deathlink_enabled) { + if (!_deathlink_enabled) { // Clear remaining deathlinks - _this._deathlinks_queued = 0; + _deathlinks_queued = 0; } - if (_this._deathlink_enabled) { - FFXArchipelagoClient.current_death_link?.EnableDeathLink(); + if (_deathlink_enabled) { + _client!.current_death_link_service?.EnableDeathLink(); } else { - FFXArchipelagoClient.current_death_link?.DisableDeathLink(); + _client!.current_death_link_service?.DisableDeathLink(); } } - public static string get_send_type() { - return get_send_type_name(_this.deathlink_send_type); + public string get_send_type() { + return get_send_type_name(deathlink_send_type); } - public static string get_send_type_name(DeathLinkSendType send_type) { + public string get_send_type_name(DeathLinkSendType send_type) { return send_type switch { DeathLinkSendType.GameOver => "Game Over", DeathLinkSendType.KO => "KO", - _ => throw new NotImplementedException($"Unknown deathlink type: {(int)_this.deathlink_receive_type}"), + _ => throw new NotImplementedException($"Unknown deathlink type: {(int)deathlink_receive_type}"), }; } - public static void set_send_type(string type) { - _this.deathlink_send_type = type switch { + public void set_send_type(string type) { + deathlink_send_type = type switch { "Game Over" => DeathLinkSendType.GameOver, "KO" => DeathLinkSendType.KO, _ => throw new NotImplementedException($"Unknown deathlink type: {type}"), }; } - public static string get_receive_type() { - return get_receive_type_name(_this.deathlink_receive_type); + public string get_receive_type() { + return get_receive_type_name(deathlink_receive_type); } - public static string get_receive_type_name(DeathLinkReceiveType receive_type) { + public string get_receive_type_name(DeathLinkReceiveType receive_type) { return receive_type switch { DeathLinkReceiveType.DOOM_STRICT => "Doom (1 turn)", DeathLinkReceiveType.DOOM_LENIENT => "Doom (3 turns)", DeathLinkReceiveType.GRAVE_HP => "Grave HP", DeathLinkReceiveType.BAD_BREATH => "Bad Breath", DeathLinkReceiveType.RANDOM => "Random", - _ => throw new NotImplementedException($"Unknown deathlink type: {(int)_this.deathlink_receive_type}"), + _ => throw new NotImplementedException($"Unknown deathlink type: {(int)deathlink_receive_type}"), }; } - public static void set_receive_type(string type) { - _this.deathlink_receive_type = type switch { + public void set_receive_type(string type) { + deathlink_receive_type = type switch { "Doom (1 turn)" => DeathLinkReceiveType.DOOM_STRICT, "Doom (3 turns)" => DeathLinkReceiveType.DOOM_LENIENT, "Grave HP" => DeathLinkReceiveType.GRAVE_HP, @@ -130,23 +120,24 @@ public static void set_receive_type(string type) { }; } - public static uint get_deathlinks_queued() { - return _this._deathlinks_queued; + public uint get_deathlinks_queued() { + return _deathlinks_queued; } - public static void debug_add_queued() { - _this._deathlinks_queued += 1; + public void debug_add_queued() { + _deathlinks_queued += 1; } - public static void debug_apply_deathlink() { - _this.apply_death_link(); + public void debug_apply_deathlink() { + apply_death_link(); } public override bool init(FhModContext mod_context, FileStream global_state_file) { - return _toasts_handle.try_get_module(out _toasts) - && _MsBtlReadManage.hook() - && _MsDamageCheckDeath.hook() - && _MsGetBattleEndStatus.hook(); + return _client_handle.try_get_module(out _client) + && _toasts_handle.try_get_module(out _toasts) + && FhXCall.MsBtlReadManage.hook(this, _h_MsBtlReadManage) + && FhXCall.MsDamageCheckDeath.hook(this, _h_MsDamageCheckDeath) + && FhXCall.MsGetBattleEndStatus.hook(this, _h_MsGetBattleEndStatus); } private void apply_death_link() { @@ -211,7 +202,7 @@ private void apply_death_link() { private void _h_MsBtlReadManage() { int old_state = Globals.Battle.btl->battle_state; - _MsBtlReadManage.orig_fptr(); + FhXCall.MsBtlReadManage.chain_from(_h_MsBtlReadManage).fnptr!(); if (Globals.Battle.btl->battle_state != 13 || old_state == Globals.Battle.btl->battle_state) return; @@ -230,13 +221,14 @@ private void _h_MsBtlReadManage() { apply_death_link(); - _MsMessageCueRegist(MessageCueType.FH_CUSTOM, (int)_deathlink_announcement.encoded, 0, 27, 35); + FhXCall.MsMessageCueRegist.fnptr!((uint)MessageCueType.FH_CUSTOM, (int)_deathlink_announcement.encoded, 0, 27, 35); _logger.Info(" Disabling Escape and Flee..."); for (int chr_id = 0; chr_id <= PlySaveId.PC_SEYMOUR; chr_id++) { - _set_command_disabled(chr_id, PlayerCommandId.PCOM_ESCAPE, 1); - _set_command_disabled(chr_id, PlayerCommandId.PCOM_FLEE, 1); + // Disable Escape & Flee commands + FhXCall.FUN_0079b480.fnptr!(chr_id, PlayerCommandId.PCOM_ESCAPE, 1); + FhXCall.FUN_0079b480.fnptr!(chr_id, PlayerCommandId.PCOM_FLEE, 1); } _deathlinks_queued -= 1; @@ -245,7 +237,7 @@ private void _h_MsBtlReadManage() { } private int _h_MsDamageCheckDeath(int attacker_id, int target_id, int p3, int targetting_self) { - int result = _MsDamageCheckDeath.orig_fptr(attacker_id, target_id, p3, targetting_self); + int result = FhXCall.MsDamageCheckDeath.chain_from(_h_MsDamageCheckDeath).fnptr!(attacker_id, target_id, p3, targetting_self); if (result == 0 || target_id > PlySaveId.PC_MAGUS3) { return result; @@ -259,16 +251,16 @@ private int _h_MsDamageCheckDeath(int attacker_id, int target_id, int p3, int ta _logger.Info(" Sending deathlink..."); - string player = FFXArchipelagoClient.active_player?.Alias ?? "Someone"; + string player = _client!.active_player?.Alias ?? "Someone"; - Chr* target = _MsGetChr(target_id); + Chr* target = FhXCall.MsGetChr.fnptr!(target_id); byte[] decoded = new byte[FhEncoding.compute_decode_buffer_size(target->ram.name, null, null, FhEncodingFlags.IMPLICIT_END)]; FhEncoding.decode(target->ram.name, decoded, null, null, FhEncodingFlags.IMPLICIT_END); string target_name = Encoding.UTF8.GetString(decoded); string message = _get_deathlink_send_text($"{player}'s {target_name}"); - FFXArchipelagoClient.current_death_link?.SendDeathLink(new(player, message)); + _client!.current_death_link_service?.SendDeathLink(new(player, message)); ToastModule.Toast deathlink_toast = new( [ @@ -285,7 +277,7 @@ private int _h_MsDamageCheckDeath(int attacker_id, int target_id, int p3, int ta } private uint _h_MsGetBattleEndStatus() { - uint battle_end_type = _MsGetBattleEndStatus.orig_fptr(); + uint battle_end_type = FhXCall.MsGetBattleEndStatus.chain_from(_h_MsGetBattleEndStatus).fnptr!(); if (!_deathlink_enabled || battle_end_type != 1 || Globals.Battle.btl->battle_state != 0x17) { return battle_end_type; @@ -299,10 +291,10 @@ private uint _h_MsGetBattleEndStatus() { _logger.Info(" Sending deathlink..."); - string player = FFXArchipelagoClient.active_player?.Alias ?? "Someone"; + string player = _client!.active_player?.Alias ?? "Someone"; string message = _get_deathlink_send_text(player); - FFXArchipelagoClient.current_death_link?.SendDeathLink(new(player, message)); + _client!.current_death_link_service?.SendDeathLink(new(player, message)); ToastModule.Toast deathlink_toast = new( [ @@ -444,9 +436,9 @@ private string _get_backup_deathlink_received_text(string source_player) { return String.Format(FhApi.Localization.localize(message_id), source_player); } - public static void post_deathlink(DeathLink death_msg) { - if (!_this._deathlink_enabled) return; - _this._deathlinks_queued += 1; + public void post_deathlink(DeathLink death_msg) { + if (!_deathlink_enabled) return; + _deathlinks_queued += 1; // Display a toast ToastModule.Toast deathlink_toast = new( @@ -454,10 +446,10 @@ public static void post_deathlink(DeathLink death_msg) { new(DEATHLINK_COLOR, "Deathlink received!"), ], [ - new(new(1f), death_msg.Cause ?? _this._get_backup_deathlink_received_text(death_msg.Source)), + new(new(1f), death_msg.Cause ?? _get_backup_deathlink_received_text(death_msg.Source)), ] ); - _this._toasts!.queue_toast(deathlink_toast); + _toasts?.queue_toast(deathlink_toast); } } diff --git a/src/modules/hardcore_contest.cs b/src/modules/hardcore_contest.cs index db943a0..9f0abe7 100644 --- a/src/modules/hardcore_contest.cs +++ b/src/modules/hardcore_contest.cs @@ -1,44 +1,34 @@ using System.IO; -using System.Runtime.InteropServices; using Fahrenheit; using Fahrenheit.FFX; using Fahrenheit.FFX.Ids; +using FhGCall = Fahrenheit.FhCall; +using FhXCall = Fahrenheit.FFX.FhCall; + namespace ArchipelagoFFX; [FhLoad(FhGameId.FFX)] -public unsafe partial class HardcoreDreamsEndModule : FhModule { - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void MsBtlReadManage(); - public const nint __addr_MsBtlReadManage = 0x3830d0; - - private static HardcoreDreamsEndModule _this; +public unsafe class HardcoreDreamsEndModule : FhModule { private bool _hardcore_dreams_end_enabled; - private FhMethodHandle _MsBtlReadManage; - - public HardcoreDreamsEndModule() { - _this = this; - _MsBtlReadManage = new(this, "FFX.exe", __addr_MsBtlReadManage, _h_MsBtlReadManage); - } - - public static bool get_enabled() { - return _this._hardcore_dreams_end_enabled; + public bool get_enabled() { + return _hardcore_dreams_end_enabled; } - public static void set_enabled(bool enabled) { - _this._hardcore_dreams_end_enabled = enabled; + public void set_enabled(bool enabled) { + _hardcore_dreams_end_enabled = enabled; } public override bool init(FhModContext mod_context, FileStream global_state_file) { - return _MsBtlReadManage.hook(); + return FhXCall.MsBtlReadManage.hook(this, _h_MsBtlReadManage); } private void _h_MsBtlReadManage() { int old_state = Globals.Battle.btl->battle_state; - _MsBtlReadManage.orig_fptr(); + FhXCall.MsBtlReadManage.chain_from(_h_MsBtlReadManage).fnptr!(); if (Globals.Battle.btl->battle_state != 13 || old_state == Globals.Battle.btl->battle_state) return; diff --git a/src/modules/overdrives.cs b/src/modules/overdrives.cs index 6524a48..e32e7cc 100644 --- a/src/modules/overdrives.cs +++ b/src/modules/overdrives.cs @@ -1,30 +1,34 @@ -using Archipelago.MultiClient.Net.Enums; +using Archipelago.MultiClient.Net.Enums; +using ArchipelagoFFX.Client; +using Fahrenheit; using Fahrenheit.Atel; using Fahrenheit.FFX; using Fahrenheit.FFX.Battle; using Fahrenheit.FFX.Ids; - using System.IO; using System.Runtime.InteropServices; - -using ArchipelagoFFX.Client; - -using Fahrenheit; - -using static Fahrenheit.FFX.Globals; using static ArchipelagoFFX.ArchipelagoFFXModule; -using static ArchipelagoFFX.Client.FFXArchipelagoClient; -using static ArchipelagoFFX.delegates; +using static Fahrenheit.FFX.Globals; +using FhGCall = Fahrenheit.FhCall; +using FhXCall = Fahrenheit.FFX.FhCall; namespace ArchipelagoFFX; [FhLoad(FhGameId.FFX)] -public unsafe partial class OverdriveModule : FhModule -{ +public unsafe class OverdriveModule : FhModule { // Fahrenheit-related private FhModContext? _mod_context; private FileStream? _global_state; + private FhModuleHandle _client_handle; + private ArchipelagoClientModule? _client; + + private FhModuleHandle _ffx_interop_handle; + private ArchipelagoFFXModule? _ffx_interop; + + private FhMethodHandle h_ret_doesChrKnowCommand + => new(new FhMethodLocation("FFX.exe", 0x3A30C0)); + // Damage Calc [StructLayout(LayoutKind.Explicit, Size = 0x2C)] private struct DamageInfo @@ -66,28 +70,15 @@ private struct Chr__0x774 [FieldOffset(0x18)] public DamageInfo field24_0x18; }; - public OverdriveModule() - { - const string GAME = "FFX.exe"; - - _MsGetSaveCommand = new FhMethodHandle(this, GAME, __addr_MsGetSaveCommand, h_MsGetSaveCommand); - _MsSetRamChrAbility = new FhMethodHandle(this, GAME, __addr_MsSetRamChrAbility, h_MsSetRamChrAbility); - _MsLimitTidusLearn = new FhMethodHandle(this, GAME, __addr_MsLimitTidusLearn, h_MsLimitTidusLearn); - _MsAfterDamageProcess = new FhMethodHandle(this, GAME, __addr_MsAfterDamageProcess, h_MsAfterDamageProcess); - _ret_doesChrKnowCommand = new FhMethodHandle(this, GAME, __addr_ret_doesChrKnowCommand, h_ret_doesChrKnowCommand); - _MsSetSaveCommandWithPrefix = new FhMethodHandle(this, GAME, __addr_MsSetSaveCommandWithPrefix, h_MsSetSaveCommandWithPrefix); - _TOBtlDrawLearningMessageWindow = new FhMethodHandle(this, GAME, __addr_TOBtlDrawLearningMessageWindow, h_TOBtlDrawLearningMessageWindow); + public OverdriveModule() { + _client_handle = new(this); + _ffx_interop_handle = new(this); } // Helper class for overdrive provider functions - public static class OverdriveProvider - { - private const int overdriveOffset = 0x3000; - - public static void provide_overdrive(int chr_id) - { - switch (chr_id) - { + public static class OverdriveProvider { + public static void provide_overdrive(int chr_id) { + switch (chr_id) { case PlySaveId.PC_TIDUS: tidus_overdrive(); break; @@ -109,8 +100,7 @@ public static void provide_overdrive(int chr_id) } } - private static void tidus_overdrive() - { + private static void tidus_overdrive() { bool hasSpiralCut = other_inventory.ContainsKey(PlayerCommandId.PCOM_SPIRAL_CUT); bool hasSliceAndDice = other_inventory.ContainsKey(PlayerCommandId.PCOM_SLICE_AND_DICE); bool hasEnergyRain = other_inventory.ContainsKey(PlayerCommandId.PCOM_ENERGY_RAIN); @@ -124,8 +114,7 @@ private static void tidus_overdrive() save_data->ability_map_limit.has_blitz_ace = hasBlitzAce; } - private static void auron_overdrive() - { + private static void auron_overdrive() { bool hasDragonFang = other_inventory.ContainsKey(PlayerCommandId.PCOM_DRAGON_FANG); bool hasShootingStar = other_inventory.ContainsKey(PlayerCommandId.PCOM_SHOOTING_STAR); bool hasBanishingBlade = other_inventory.ContainsKey(PlayerCommandId.PCOM_BANISHING_BLADE); @@ -139,8 +128,7 @@ private static void auron_overdrive() save_data->ability_map_limit.has_tornado = hasTornado; } - private static void kimahri_overdrive() - { + private static void kimahri_overdrive() { bool hasJump = other_inventory.ContainsKey(PlayerCommandId.PCOM_JUMP); bool hasFireBreath = other_inventory.ContainsKey(PlayerCommandId.PCOM_FIRE_BREATH); bool hasSeedCannon = other_inventory.ContainsKey(PlayerCommandId.PCOM_SEED_CANNON); @@ -172,8 +160,7 @@ private static void kimahri_overdrive() save_data->ability_map_limit.has_nova = hasNova; } - private static void wakka_overdrive() - { + private static void wakka_overdrive() { bool hasElementReels = other_inventory.ContainsKey(PlayerCommandId.PCOM_ELEMENT_REELS); bool hasAttackReels = other_inventory.ContainsKey(PlayerCommandId.PCOM_ATTACK_REELS); bool hasStatusReels = other_inventory.ContainsKey(PlayerCommandId.PCOM_STATUS_REELS); @@ -187,15 +174,13 @@ private static void wakka_overdrive() save_data->ability_map_limit.has_aurochs_reels = hasAurochsReels; } - private static void seymour_overdrive() - { + private static void seymour_overdrive() { bool hasRequiem = other_inventory.ContainsKey(PlayerCommandId.PCOM_REQUIEM); save_data->ability_map_limit.has_requiem = hasRequiem; } - private static void valefor_overdrive() - { + private static void valefor_overdrive() { bool hasEnergyBlast = other_inventory.ContainsKey(PlayerCommandId.PCOM_ENERGY_BLAST); save_data->ability_map_limit.has_energy_blast = hasEnergyBlast; @@ -217,154 +202,140 @@ public override bool init(FhModContext mod_context, FileStream global_state_file _mod_context = mod_context; _global_state = global_state_file; - return _MsGetSaveCommand.hook() - && _MsSetRamChrAbility.hook() - && _MsLimitTidusLearn.hook() - && _MsAfterDamageProcess.hook() - && _ret_doesChrKnowCommand.hook() - && _MsSetSaveCommandWithPrefix.hook() - && _TOBtlDrawLearningMessageWindow.hook(); + return _client_handle.try_get_module(out _client) + && _ffx_interop_handle.try_get_module(out _ffx_interop) + && FhXCall.MsGetSaveCommand.hook(this, h_MsGetSaveCommand) + && FhXCall.MsSetRamChrAbility.hook(this, h_MsSetRamChrAbility) + && FhXCall.MsLimitTidusLearn.hook(this, h_MsLimitTidusLearn) + && FhXCall.AfterDamageProcess.hook(this, h_MsAfterDamageProcess) + && h_ret_doesChrKnowCommand.hook(this, ret_doesChrKnowCommand) + && FhXCall.MsSetSaveCommandWithPrefix.hook(this, h_MsSetSaveCommandWithPrefix) + && FhXCall.TOBtlDrawLearningMessageWindow.hook(this, h_TOBtlDrawLearningMessageWindow); } private static T* ptr_at(nint address) where T : unmanaged { return (T*)(address); } private static T get_at(nint address) where T : unmanaged { return *ptr_at(address); } - private static T set_at(nint address, T value) where T : unmanaged { return *ptr_at(address) = value; } + private static void set_at(nint address, T value) where T : unmanaged { *ptr_at(address) = value; } // When game is attempting to give a character an overdrive, instead call the relevant overdrive provider function - private int h_MsGetSaveCommand(int chr_id, uint com_id) - { - if (com_id is >= PlayerCommandId.PCOM_SPIRAL_CUT and <= PlayerCommandId.PCOM_AUROCHS_REELS + private int h_MsGetSaveCommand(int chr_id, uint com_id) { + if (com_id is >= PlayerCommandId.PCOM_SPIRAL_CUT and <= PlayerCommandId.PCOM_AUROCHS_REELS || com_id == PlayerCommandId.PCOM_REQUIEM || com_id == PlayerCommandId.PCOM_ENERGY_BLAST) { OverdriveProvider.provide_overdrive(chr_id); } - return _MsGetSaveCommand.orig_fptr(chr_id, com_id); + return FhXCall.MsGetSaveCommand.chain_from(h_MsGetSaveCommand).fnptr!(chr_id, com_id); } // When game is attempting to set character abilities, ensure the correct overdrive provider is called first - private void h_MsSetRamChrAbility(int chr_id, Chr* chr) - { + private void h_MsSetRamChrAbility(int chr_id, Chr* chr) { OverdriveProvider.provide_overdrive(chr_id); - - _MsSetRamChrAbility.orig_fptr(chr_id, chr); - return; + + FhXCall.MsSetRamChrAbility.chain_from(h_MsSetRamChrAbility).fnptr!(chr_id, chr); } // Runs on every Tidus Limit. Override the normal requirements, and send locations based on 10 / 20 / 40 - private int h_MsLimitTidusLearn(int chr_id) - { + private int h_MsLimitTidusLearn(int chr_id) { if (chr_id != PlySaveId.PC_TIDUS) return 0; uint tidusLimitUses = ++save_data->tidus_limit_uses; - lock (FFXArchipelagoClient.client_lock) { - if (FFXArchipelagoClient.is_connected) { - FFXArchipelagoClient.current_session!.DataStorage[Scope.Slot, "FFX_TIDUS_OVERDRIVE"] = tidusLimitUses; + lock (_client!.client_lock) { + if (_client!.is_connected) { + _client!.current_session!.DataStorage[Scope.Slot, "FFX_TIDUS_OVERDRIVE"] = tidusLimitUses; } } if (tidusLimitUses >= 10) { if (send_overdrive(PlayerCommandId.PCOM_SLICE_AND_DICE)) { - _MsMessageCueRegist(6, PlySaveId.PC_TIDUS, PlayerCommandId.PCOM_SLICE_AND_DICE, 0x1e, 0x32); + FhXCall.MsMessageCueRegist.fnptr!(6, PlySaveId.PC_TIDUS, PlayerCommandId.PCOM_SLICE_AND_DICE, 0x1e, 0x32); } } if (tidusLimitUses >= 20) { if(send_overdrive(PlayerCommandId.PCOM_ENERGY_RAIN)) { - _MsMessageCueRegist(6, PlySaveId.PC_TIDUS, PlayerCommandId.PCOM_ENERGY_RAIN, 0x1e, 0x32); + FhXCall.MsMessageCueRegist.fnptr!(6, PlySaveId.PC_TIDUS, PlayerCommandId.PCOM_ENERGY_RAIN, 0x1e, 0x32); } } if (tidusLimitUses >= 40) { if(send_overdrive(PlayerCommandId.PCOM_BLITZ_ACE)) { - _MsMessageCueRegist(6, PlySaveId.PC_TIDUS, PlayerCommandId.PCOM_BLITZ_ACE, 0x1e, 0x32); + FhXCall.MsMessageCueRegist.fnptr!(6, PlySaveId.PC_TIDUS, PlayerCommandId.PCOM_BLITZ_ACE, 0x1e, 0x32); } } - + return 0; } // Called multiple times on every instance damage. Complete reimplementation in order to interject on Kimahri's overdrive learning - private uint h_MsAfterDamageProcess(int attacker_id, uint param_2, int target_id, uint* param_4, uint param_5) - { + private uint h_MsAfterDamageProcess(int attacker_id, uint param_2, int target_id, uint* param_4, uint param_5) { uint uVar12 = 0; DamageInfo* local_30 = (DamageInfo*)0x0; - Chr* attacker = _MsGetChr(attacker_id); - Chr* target = _MsGetChr(target_id); + Chr* attacker = FhXCall.MsGetChr.fnptr!(attacker_id); + Chr* target = FhXCall.MsGetChr.fnptr!(target_id); Chr__0x774* target_0x774 = (Chr__0x774*)((int)target + 0x774); - for (int n = 2; n > 0; n--) - { - if (target_0x774->field2_0x2 == attacker_id && target_0x774->field3_0x3 == param_2) - { + for (int n = 2; n > 0; n--) { + if (target_0x774->field2_0x2 == attacker_id && target_0x774->field3_0x3 == param_2) { //set_at((int)target + 0xF5E, param_5 & 0x7f); set_at((int)target + 0xF5E, (byte)param_5.get_bits(0, 7)); set_at((int)target + 0xDED, (byte)attacker_id); - if (!param_5.get_bit(3)) - { - if (target_0x774->field7_0x7 != 0) - { - _MsMenuCloseTitleWindow(0); + if (!param_5.get_bit(3)) { + if (target_0x774->field7_0x7 != 0) { + FhXCall.MsMenuCloseTitleWindow.fnptr!(0); target_0x774->field7_0x7 = 0; //_MsMessageCueRegist(0x4, target_0x774->field7_0x7 + 3, target_0x774->field7_0x7 + 1, 0x1b, 0x23); - _MsMessageCueRegist(0x4, target_0x774->field10_0xA, target_0x774->field8_0x8, 0x1b, 0x23); - if (0 < target_0x774->field8_0x8) - { - _MsSetStealEffect(target_id, target_0x774->field1_0x1); - _MsRegSEplay2(target_id, 0x41); + FhXCall.MsMessageCueRegist.fnptr!(0x4, target_0x774->field10_0xA, target_0x774->field8_0x8, 0x1b, 0x23); + if (0 < target_0x774->field8_0x8) { + FhXCall.MsSetStealEffect.fnptr!(target_id, target_0x774->field1_0x1); + FhXCall.MsRegSEplay2.fnptr!(target_id, 0x41); } target_0x774->field5_0x5 |= 1; } - if (target_0x774->field12_0xC != 0) - { - _MsMenuCloseTitleWindow(0); + if (target_0x774->field12_0xC != 0) { + FhXCall.MsMenuCloseTitleWindow.fnptr!(0); target_0x774->field12_0xC = 0; - _MsMessageCueRegist(0x8, target_0x774->field16_0x10, 0, 0x1b, 0x23); - if (0 < target_0x774->field16_0x10) - { - _MsPayGIL(-*(int*)(target_0x774 + 9)); - _MsSetStealGillEffect(target_id, target_0x774->field1_0x1); - _MsRegSEplay2(target_id, 0x41); + FhXCall.MsMessageCueRegist.fnptr!(0x8, target_0x774->field16_0x10, 0, 0x1b, 0x23); + if (0 < target_0x774->field16_0x10) { + FhXCall.MsPayGIL.fnptr!(-*(int*)(target_0x774 + 9)); + FhXCall.MsSetStealGillEffect.fnptr!(target_id, target_0x774->field1_0x1); + FhXCall.MsRegSEplay2.fnptr!(target_id, 0x41); } target_0x774->field5_0x5 |= 1; } } - if (target_0x774->field4_0x4 != 0) - { - if (target_0x774->field4_0x4.get_bit(0)) - { + if (target_0x774->field4_0x4 != 0) { + if (target_0x774->field4_0x4.get_bit(0)) { byte bVar1 = attacker->ram.limit_charge; attacker->ram.limit_charge = 0; - target->ram.limit_charge = (byte)_MsCheckRange(target->ram.limit_charge + bVar1, 0, target->ram.limit_charge_max); + target->ram.limit_charge = (byte)FhXCall.MsCheckRange.fnptr!(target->ram.limit_charge + bVar1, 0, target->ram.limit_charge_max); } - if (target_0x774->field4_0x4.get_bit(1)) - { - Chr* pCVar8 = _MsGetChr(target_0x774->chr_id__0x17); - if (target_id == PlySaveId.PC_KIMAHRI && pCVar8->loot != (ChrLoot*)0x0) - { + if (target_0x774->field4_0x4.get_bit(1)) { + Chr* pCVar8 = FhXCall.MsGetChr.fnptr!(target_0x774->chr_id__0x17); + if (target_id == PlySaveId.PC_KIMAHRI && pCVar8->loot != (ChrLoot*)0x0) { ushort rage_to_learn = pCVar8->loot->ronso_rage; - if (rage_to_learn != 0) - { + if (rage_to_learn != 0) { if(send_overdrive(rage_to_learn)) { - _MsMessageCueRegist(6, PlySaveId.PC_KIMAHRI, rage_to_learn, 0x1e, 0x32); + FhXCall.MsMessageCueRegist.fnptr!(6, PlySaveId.PC_KIMAHRI, rage_to_learn, 0x1e, 0x32); target->ram.limit_charge = target->ram.limit_charge_max; } - if (save_data->ability_map_limit.has_jump && save_data->ability_map_limit.has_fire_breath && + if ( + save_data->ability_map_limit.has_jump && save_data->ability_map_limit.has_fire_breath && save_data->ability_map_limit.has_seed_cannon && save_data->ability_map_limit.has_self_destruct && save_data->ability_map_limit.has_thrust_kick && save_data->ability_map_limit.has_stone_breath && save_data->ability_map_limit.has_aqua_breath && save_data->ability_map_limit.has_doom && save_data->ability_map_limit.has_white_wind && save_data->ability_map_limit.has_bad_breath && - save_data->ability_map_limit.has_mighty_guard && save_data->ability_map_limit.has_nova) - { - _achievementUnlockAchievement(0x19); + save_data->ability_map_limit.has_mighty_guard && save_data->ability_map_limit.has_nova + ) { + FhXCall.achievementUnlockAchievement.fnptr!(0x19); } } } @@ -373,48 +344,40 @@ private uint h_MsAfterDamageProcess(int attacker_id, uint param_2, int target_id target_0x774->field4_0x4 = 0; } - if (target_0x774->field0_0x0 < target_0x774->field1_0x1) - { + if (target_0x774->field0_0x0 < target_0x774->field1_0x1) { DamageInfo* target_0x774_damage_info = &target_0x774->field24_0x18 + target_0x774->field0_0x0; int local_20 = 0; - if (!param_5.get_bit(3)) - { + if (!param_5.get_bit(3)) { int iVar7 = target_0x774_damage_info->field1_0x1; uint uVar9 = target_0x774_damage_info->field2_0x2; - if (iVar7 == 1) - { - _MsNumberRegist(target_id, 3, 0, 0, 1, uVar9, 0x81); - } - else if (iVar7 == 2) - { - _MsNumberRegist(target_id, 4, 0, 0, 2, uVar9, 0x81); + if (iVar7 == 1) { + FhXCall.MsNumberRegist.fnptr!(target_id, 3, 0, 0, 1, uVar9, 0x81); + } else if (iVar7 == 2) { + FhXCall.MsNumberRegist.fnptr!(target_id, 4, 0, 0, 2, uVar9, 0x81); } - _MsLimitTypeDamageCheck(attacker_id, attacker, target_id, target, target_0x774_damage_info->out_damage_hp, target_0x774_damage_info->out_damage_expected, target_0x774->field6_0x6); + FhXCall.MsLimitTypeDamageCheck.fnptr!(attacker_id, attacker, target_id, target, target_0x774_damage_info->out_damage_hp, target_0x774_damage_info->out_damage_expected, target_0x774->field6_0x6); - if (target_0x774_damage_info->dmg_calc_flags1.get_bit(0)) - { - _MsSubHP(target_id, target, target_0x774_damage_info->out_damage_hp, target_0x774_damage_info->out_damage_mp, iVar7, uVar9, 0x81); + if (target_0x774_damage_info->dmg_calc_flags1.get_bit(0)) { + FhXCall.MsSubHP.fnptr!(target_id, target, target_0x774_damage_info->out_damage_hp, target_0x774_damage_info->out_damage_mp, iVar7, uVar9, 0x81); set_at((int)target + 0xF60, get_at((int)target + 0xF60) - target_0x774_damage_info->out_damage_hp); local_20 += target_0x774_damage_info->out_damage_hp; } - if (target_0x774_damage_info->dmg_calc_flags1.get_bit(1)) - { - _MsSubMP(target_id, target, target_0x774_damage_info->out_damage_mp, target_0x774_damage_info->out_damage_hp, iVar7, uVar9, 0x81); + if (target_0x774_damage_info->dmg_calc_flags1.get_bit(1)) { + FhXCall.MsSubMP.fnptr!(target_id, target, target_0x774_damage_info->out_damage_mp, target_0x774_damage_info->out_damage_hp, iVar7, uVar9, 0x81); } - if (target_0x774_damage_info->dmg_calc_flags1.get_bit(2)) - { - _MsSubCTB(target_id, target, target_0x774_damage_info->out_damage_ctb, iVar7, uVar9, 0x81); + if (target_0x774_damage_info->dmg_calc_flags1.get_bit(2)) { + FhXCall.MsSubCTB.fnptr!(target_id, target, target_0x774_damage_info->out_damage_ctb, iVar7, uVar9, 0x81); //dbgPrintf("CTB DAMAGE %d %d : %d\n", target_id, iVar10, (target->ram).ctb); } - _MsLimitTypeStatusCheck(attacker_id, attacker, target_id, target, target_0x774_damage_info->field4_0x4, target_0x774_damage_info->field3_0x3); + FhXCall.MsLimitTypeStatusCheck.fnptr!(attacker_id, attacker, target_id, target, target_0x774_damage_info->field4_0x4, target_0x774_damage_info->field3_0x3); StatusPermanentFlags SVar5 = target->ram.status_suffer; byte bVar1 = target->ram.status_suffer_turns_left.darkness; byte bVar2 = target->ram.status_suffer_turns_left.silence; @@ -422,98 +385,79 @@ private uint h_MsAfterDamageProcess(int attacker_id, uint param_2, int target_id StatusExtraFlags bVar4 = target->ram.status_suffer_extra; target->ram.status_suffer = target_0x774_damage_info->target_status_suffer; - for (int i = 0; i < 0xD; i++) - { + for (int i = 0; i < 0xD; i++) { // TODO: Improvements pending the availability of indexers from Fahrenheit, as per https://github.com/fahrenheit-crew/fahrenheit/issues/114 (&target->ram.status_suffer_turns_left.sleep)[i] = (&target_0x774_damage_info->target_status_suffer_turns_left.sleep)[i]; } target->ram.status_suffer_extra = target_0x774_damage_info->target_status_suffer_extra; - _MsLimitStatusProcess(target_id, target, target_0x774_damage_info->flags_buffs_mix); + FhXCall.MsLimitStatusProcess.fnptr!(target_id, target, target_0x774_damage_info->flags_buffs_mix); - if ((target->ram.status_suffer_turns_left.regen != 0) && (bVar3 == 0)) - { + if (target->ram.status_suffer_turns_left.regen != 0 && bVar3 == 0) { target->ram.regen_strength = 0; } StatusPermanentFlags SVar6 = target->ram.status_suffer; - set_at((int)target + 0xDCE, SVar6.petrification()); - if (target->ram.status_suffer.death() != SVar5.death()) - { - _MsAliveProcess(target_id, target); + set_at((int)target + 0xDCE, SVar6.petrification); + if (target->ram.status_suffer.death != SVar5.death) { + FhXCall.MsAliveProcess.fnptr!(target_id, target); } - if (target->ram.status_suffer.petrification() != SVar5.petrification()) - { - _MsStoneProcess(target_id, target); + if (target->ram.status_suffer.petrification != SVar5.petrification) { + FhXCall.MsStoneProcess.fnptr!(target_id, target); } - if (target->ram.status_suffer_extra.eject() != bVar4.eject()) - { - _MsBlowProcess(target_id, target); + if (target->ram.status_suffer_extra.eject != bVar4.eject) { + FhXCall.MsBlowProcess.fnptr!(target_id, target); } - if (target->ram.status_suffer.threaten() != SVar5.threaten()) - { - _MsThreatProcess(target_id, target); + if (target->ram.status_suffer.threaten != SVar5.threaten) { + FhXCall.MsThreatProcess.fnptr!(target_id, target); } target_0x774->field5_0x5 |= 1; - if (target->ram.auto_ability_effects.has_auto_med) - { - _MsAutoCureProcess(target_id, target, attacker_id, (int)SVar5 >> 3 & 1, (int)SVar5 >> 1 & 1, bVar1, bVar2); + if (target->ram.auto_ability_effects.has_auto_med) { + FhXCall.MsAutoCureProcess.fnptr!(target_id, target, attacker_id, (int)SVar5 >> 3 & 1, (int)SVar5 >> 1 & 1, bVar1, bVar2); } - if (0 < local_20 && target->ram.auto_ability_effects.has_auto_potion) - { - _MsAutoPotionProcess(target_id, target, attacker_id); + if (0 < local_20 && target->ram.auto_ability_effects.has_auto_potion) { + FhXCall.MsAutoPotionProcess.fnptr!(target_id, target, attacker_id); } - _MsSetChrWeak(target_id, -1); - uVar12 = uVar12 | 2; + FhXCall.MsSetChrWeak.fnptr!(target_id, -1); + uVar12 |= 2; target_0x774->field0_0x0 += 1; } - if (get_at((int)&target->ram + 0x19C)) - { - _MsAutoRelifeProcess(attacker_id, attacker, target_id, target); + if (get_at((int)&target->ram + 0x19C)) { + FhXCall.MsAutoRelifeProcess.fnptr!(attacker_id, attacker, target_id, target); } - if (!param_5.get_bit(1) && (target_0x774_damage_info->field0_0x0 != 1 || !target_0x774->field5_0x5.get_bit(2))) - { + if (!param_5.get_bit(1) && (target_0x774_damage_info->field0_0x0 != 1 || !target_0x774->field5_0x5.get_bit(2))) { target_0x774->field5_0x5 |= 4; local_30 = target_0x774_damage_info; } - if (!param_5.get_bit(4)) - { - _MsStatusEffectCheck(target_id); - if (_MsStatusDefenseEffect(attacker_id, target_id, target_0x774_damage_info->dmg_calc_flags1) != 0) - { + if (!param_5.get_bit(4)) { + FhXCall.MsStatusEffectCheck.fnptr!(target_id); + if (FhXCall.MsStatusDefenseEffect.fnptr!(attacker_id, target_id, target_0x774_damage_info->dmg_calc_flags1) != 0) { *param_4 = (uint)target_id; } } } - if (target_0x774->field0_0x0 < target_0x774->field1_0x1) - { - uVar12 = uVar12 | 1; - } - else - { - if (target_0x774->field5_0x5.get_bit(0) && !target_0x774->field5_0x5.get_bit(1)) - { + if (target_0x774->field0_0x0 < target_0x774->field1_0x1) { + uVar12 |= 1; + } else { + if (target_0x774->field5_0x5.get_bit(0) && !target_0x774->field5_0x5.get_bit(1)) { set_at((int)&target->ram + 0x19D, false); target_0x774->field5_0x5 |= 2; - _MsActionRequest(target_id, attacker_id, 3, 0, 1, null); + FhXCall.MsActionRequest.fnptr!(target_id, attacker_id, 3, 0, 1, null); } - if (!param_5.get_bit(10)) - { - _MsPopBtlPos(target); - } - else - { + if (!param_5.get_bit(10)) { + FhXCall.MsPopBtlPos.fnptr!(target); + } else { target_0x774->field2_0x2 = 0xff; } } @@ -522,56 +466,52 @@ private uint h_MsAfterDamageProcess(int attacker_id, uint param_2, int target_id target_0x774 += 1; } - if (!uVar12.get_bit(0) && _MsDamageCheckDeath(attacker_id, target_id, 0, (attacker_id != target_id) ? 1 : 0) != 0) - { + int not_attacking_self = attacker_id != target_id ? 1 : 0; + + if (!uVar12.get_bit(0) && FhXCall.MsDamageCheckDeath.fnptr!(attacker_id, target_id, 0, not_attacking_self) != 0) { return uVar12; } - if (local_30 == (DamageInfo*)0x0) - { + if (local_30 == (DamageInfo*)0x0) { return uVar12; } - if (!param_5.get_bit(5)) - { - _MsDamageSetMotion(target_id, local_30->field0_0x0, (attacker_id != target_id) ? 1 : 0); + if (!param_5.get_bit(5)) { + FhXCall.MsDamageSetMotion.fnptr!(target_id, local_30->field0_0x0, not_attacking_self); return uVar12; } - if (local_30->field0_0x0 != 5) - { - if (local_30->field0_0x0 == 6) - { - _MsDamageSetMotion(target_id, _brnd(9).get_bit(0) ? (byte)0x10 : (byte)0xF, (attacker_id != target_id) ? 1 : 0); + if (local_30->field0_0x0 != 5) { + if (local_30->field0_0x0 == 6) { + FhXCall.MsDamageSetMotion.fnptr!(target_id, FhXCall.brnd.fnptr!(9).get_bit(0) ? 0x10 : 0xF, not_attacking_self); return uVar12; } - if (local_30->field0_0x0 != 8) - { - _MsDamageSetMotion(target_id, local_30->field0_0x0, (attacker_id != target_id) ? 1 : 0); + if (local_30->field0_0x0 != 8) { + FhXCall.MsDamageSetMotion.fnptr!(target_id, local_30->field0_0x0, not_attacking_self); return uVar12; } } - _MsDamageSetMotion(target_id, _brnd(9).get_bits(0, 2) + 0xD, (attacker_id != target_id) ? 1 : 0); + FhXCall.MsDamageSetMotion.fnptr!(target_id, FhXCall.brnd.fnptr!(9).get_bits(0, 2) + 0xD, not_attacking_self); return uVar12; } // Required in order to allow Biran & Yenke's ChrLoot to progress to the next Ronso Rage based on location sent, rather than command known - private int h_ret_doesChrKnowCommand(AtelBasicWorker* work, int* storage, AtelStack* atelStack) - { + private int ret_doesChrKnowCommand(AtelBasicWorker* work, int* storage, AtelStack* atelStack) { int com_id = atelStack->pop_int(); int chr_id = atelStack->pop_int(); - if (chr_id == PlySaveId.PC_KIMAHRI && - com_id is >= PlayerCommandId.PCOM_JUMP and <= PlayerCommandId.PCOM_NOVA) - { - return local_checked_locations.Contains(((com_id - PlayerCommandId.PCOM_SPIRAL_CUT) & 0xFF) | (long)FFXArchipelagoClient.ArchipelagoLocationType.Overdrive) ? 1 : 0; + if ( + chr_id == PlySaveId.PC_KIMAHRI && + com_id is >= PlayerCommandId.PCOM_JUMP and <= PlayerCommandId.PCOM_NOVA + ) { + return _client!.local_checked_locations.Contains(((com_id - PlayerCommandId.PCOM_SPIRAL_CUT) & 0xFF) | (long)ArchipelagoClientModule.ArchipelagoLocationType.Overdrive) ? 1 : 0; } atelStack->push_int(chr_id); atelStack->push_int(com_id); - return _ret_doesChrKnowCommand.orig_fptr(work, storage, atelStack); + return h_ret_doesChrKnowCommand.chain_from(ret_doesChrKnowCommand).fnptr!(work, storage, atelStack); } // Called from teachAbilityToPartyMemberSilently & teachAbilityToPartyMemberWithMsg @@ -582,24 +522,23 @@ private void h_MsSetSaveCommandWithPrefix(int chr_id, int com_id, int param_3) { return; } - _MsSetSaveCommandWithPrefix.orig_fptr(chr_id, com_id, param_3); - return; + FhXCall.MsSetSaveCommandWithPrefix.chain_from(h_MsSetSaveCommandWithPrefix).fnptr!(chr_id, com_id, param_3); } private int h_TOBtlDrawLearningMessageWindow(int chr_id, int com_id) { byte* data_end; - byte* chr_name = _TOGetSaveChrName(chr_id); - _TOBtlSetMacroCommandType(7, 0, 0); - _TOBtlSetMacroCommandValue(7, 0, chr_name); + byte* chr_name = FhXCall.TOGetSaveChrName.fnptr!(chr_id); + FhXCall.TOBtlSetMacroCommandType.fnptr!(7, 0, 0); + FhXCall.TOBtlSetMacroCommandValue.fnptr!(7, 0, chr_name); - Command* com = _MsGetComData(com_id, &data_end); + Command* com = FhXCall.MsGetComData.fnptr!(com_id, &data_end); ushort com_name_offset = com->name_offset; - _TOBtlSetMacroCommandType(7, 1, 0); + FhXCall.TOBtlSetMacroCommandType.fnptr!(7, 1, 0); if (item_locations.overdrive.TryGetValue(com_id - PlayerCommandId.PCOM_SPIRAL_CUT, out var item)) { - ArchipelagoFFXModule.NativeCustomString custom_text; + NativeCustomString custom_text; if (item.id != 0) { custom_text = new($"{item.name}"); @@ -607,30 +546,26 @@ private int h_TOBtlDrawLearningMessageWindow(int chr_id, int com_id) { custom_text = new($"{item.player}'s {item.name}"); } - _TOBtlSetMacroCommandValue(7, 1, custom_text.encoded); + FhXCall.TOBtlSetMacroCommandValue.fnptr!(7, 1, custom_text.encoded); } else { - _TOBtlSetMacroCommandValue(7, 1, data_end + com_name_offset); + FhXCall.TOBtlSetMacroCommandValue.fnptr!(7, 1, data_end + com_name_offset); } - byte* btl_text = _MsGetRomBtlText(0x300d, 0); - _FUN_0089db10(0, btl_text); + byte* btl_text = FhXCall.MsGetRomBtlText.fnptr!(0x300d, 0); + FhXCall.FUN_0089db10.fnptr!(0, btl_text); return 7; } - public static bool send_overdrive(int com_id) - { + public bool send_overdrive(int com_id) { // Apworld defines Spiral Cut as overdrive location 0, and all other overdrives are treated as an offset from that value. int overdrive_id = com_id - PlayerCommandId.PCOM_SPIRAL_CUT; bool sent_overdrive = false; - if (!FFXArchipelagoClient.local_checked_locations.Contains(overdrive_id | (long)FFXArchipelagoClient.ArchipelagoLocationType.Overdrive)) - { - if (ArchipelagoFFXModule.item_locations.overdrive.TryGetValue(overdrive_id, out var item)) - { - if (FFXArchipelagoClient.sendLocation(overdrive_id, FFXArchipelagoClient.ArchipelagoLocationType.Overdrive)) - { - ArchipelagoFFXModule.obtain_item(item.id); + if (!_client!.local_checked_locations.Contains(overdrive_id | (long)ArchipelagoClientModule.ArchipelagoLocationType.Overdrive)) { + if (item_locations.overdrive.TryGetValue(overdrive_id, out var item)) { + if (_client!.sendLocation(overdrive_id, ArchipelagoClientModule.ArchipelagoLocationType.Overdrive)) { + _ffx_interop!.obtain_item(item.id); sent_overdrive = true; } } diff --git a/src/modules/sphere_grid.cs b/src/modules/sphere_grid.cs index a2ce483..8d35ff3 100644 --- a/src/modules/sphere_grid.cs +++ b/src/modules/sphere_grid.cs @@ -1,53 +1,25 @@ using System.Collections.Generic; using System.IO; -using System.Runtime.InteropServices; using System.Text; -using Fahrenheit; - using Hexa.NET.ImGui; +using Fahrenheit; using Fahrenheit.FFX; using static Fahrenheit.FFX.Globals; +using FhXCall = Fahrenheit.FFX.FhCall; + namespace ArchipelagoFFX; [FhLoad(FhGameId.FFX)] public unsafe class SphereGridQolModule : FhModule { - // Delegates for handles - //TODO: Remove these once FhCall is more up-to-date - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void abmap_get_panel(int ply_id, int node_idx); - public const nint __addr_abmap_get_panel = 0x6458a0; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void abmap_ctrl(); - public const nint __addr_AbmapState_MovingToTarget = 0x659990; - public const nint __addr_AbmapState_ChangingNode = 0x647d50; - public const nint __addr_AbmapState_Warping = 0x647f00; - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void abmap_confirm_move(int p1, int p2, int p3); - public const nint __addr_FUN_00a56160 = 0x656160; - // Sound IDs private const uint SND_PREFIX = 0x80000000; public const uint SND_ACTIVATE_NODE = 0x50 | SND_PREFIX; public const uint SND_DEACTIVATE_NODE = 0x6e | SND_PREFIX; - // Method handles - private readonly FhMethodHandle _sphere_grid_move_speed; - private readonly FhMethodHandle _sphere_grid_confirm_move; - private readonly FhMethodHandle _sphere_grid_state_moving; - private readonly FhMethodHandle _sphere_grid_state_warping; - private readonly FhMethodHandle _sphere_grid_change_node; - - // Function pointers - //TODO: Move this into a library common between modules - private static delegates.SndSepPlaySimple _SndSepPlaySimple = FhUtil.get_fptr(delegates.__addr_SndSepPlaySimple); - private readonly abmap_get_panel _abmap_get_panel = FhUtil.get_fptr(__addr_abmap_get_panel); - // Fahrenheit-related private FhModContext? _mod_context; private FileStream? _global_state; @@ -60,25 +32,15 @@ public unsafe class SphereGridQolModule : FhModule { private static readonly HashSet temporarily_activated_nodes = []; - public SphereGridQolModule() { - const string GAME = "FFX.exe"; - - _sphere_grid_move_speed = new(this, GAME, __addr_AbmapState_MovingToTarget, h_move_speed); - _sphere_grid_confirm_move = new(this, GAME, __addr_FUN_00a56160, h_move_confirm); - _sphere_grid_state_moving = new(this, GAME, __addr_AbmapState_MovingToTarget, h_state_moving); - _sphere_grid_state_warping = new(this, GAME, __addr_AbmapState_Warping, h_state_warping); - _sphere_grid_change_node = new(this, GAME, __addr_AbmapState_ChangingNode, h_change_node); - } - public override bool init(FhModContext mod_context, FileStream global_state_file) { _mod_context = mod_context; _global_state = global_state_file; - return _sphere_grid_move_speed.hook() - && _sphere_grid_confirm_move.hook() - && _sphere_grid_state_moving.hook() - && _sphere_grid_state_warping.hook() - && _sphere_grid_change_node.hook(); + return FhXCall.AbmapState_MovingToTarget.hook(this, h_move_speed) + && FhXCall.FUN_00a56160.hook(this, h_move_confirm) + && FhXCall.AbmapState_MovingToTarget.hook(this, h_state_moving) + && FhXCall.AbmapState_Warping.hook(this, h_state_warping) + && FhXCall.AbmapState_ChangingNode.hook(this, h_change_node); } private string get_state_name() { @@ -233,20 +195,20 @@ private void render_node_info() { if (ImGui.Button(activated ? $"Deactivate##{i}" : $"Activate##{i}")) { if (activated) { selected_node->activated_by.set_bit(i, false); - _SndSepPlaySimple(SND_DEACTIVATE_NODE); + FhXCall.SndSepPlaySimple.fnptr!(SND_DEACTIVATE_NODE); lpamng->should_update = 1; lpamng->should_update_node = lpamng->selected_node_idx; } else { - _abmap_get_panel(i, lpamng->selected_node_idx); + FhXCall.abmap_get_panel.fnptr!(i, lpamng->selected_node_idx); } } } ImGui.Unindent(); - ImGui.Text($"Can target? {selected_node->properties.can_target()}"); - ImGui.Text($"Is highlighted? {selected_node->properties.is_highlighted()}"); + ImGui.Text($"Can target? {selected_node->properties.can_target}"); + ImGui.Text($"Is highlighted? {selected_node->properties.is_highlighted}"); ImGui.Text($"Move cost: {selected_node->move_cost}"); } @@ -256,7 +218,7 @@ public void h_move_speed() { float prev_t = lpamng->moving_progress; - _sphere_grid_move_speed.orig_fptr(); + FhXCall.AbmapState_MovingToTarget.chain_from(h_move_speed).fnptr!(); if (freeze_move) { lpamng->moving_progress = prev_t; @@ -310,7 +272,7 @@ private bool try_activate(short node_idx, int ply_id, bool temporary) { } node->activated_by.set_bit(ply_id, true); - _SndSepPlaySimple(SND_ACTIVATE_NODE); + FhXCall.SndSepPlaySimple.fnptr!(SND_ACTIVATE_NODE); if (temporary) { temporarily_activated_nodes.Add(node_idx); @@ -344,7 +306,7 @@ public void h_move_confirm(int p1, int p2, int p3) { knots_counted = 0; - _sphere_grid_confirm_move.orig_fptr(p1, p2, p3); + FhXCall.FUN_00a56160.chain_from(h_move_confirm).fnptr!(p1, p2, p3); // If we cancelled it, also deactivate all activated nodes if (p3 == 1 && temporarily_activated_nodes.Count > 0) { @@ -354,7 +316,7 @@ public void h_move_confirm(int p1, int p2, int p3) { lpamng->nodes[node_idx].activated_by.set_bit(chr_id, false); } - _SndSepPlaySimple(SND_DEACTIVATE_NODE); + FhXCall.SndSepPlaySimple.fnptr!(SND_DEACTIVATE_NODE); lpamng->should_update = 1; lpamng->should_update_node = -1; @@ -369,7 +331,7 @@ public void h_state_moving() { float prev_t = lpamng->moving_progress; short last_knot = lpamng->move_next_target_node_idx; - _sphere_grid_state_moving.orig_fptr(); + FhXCall.AbmapState_MovingToTarget.chain_from(h_state_moving).fnptr!(); float current_t = lpamng->moving_progress; @@ -396,7 +358,7 @@ public void h_state_warping() { byte last_warp_state = *(byte*)((int)lpamng + 0x1164c); - _sphere_grid_state_warping.orig_fptr(); + FhXCall.AbmapState_Warping.chain_from(h_state_warping).fnptr!(); // Warp states: // 0 == Disappearing @@ -432,7 +394,7 @@ public void h_change_node() { short node_idx = *(short*)((int)lpamng + 0x1164e); byte ply_id = lpamng->current_chr_id; - _sphere_grid_change_node.orig_fptr(); + FhXCall.AbmapState_ChangingNode.chain_from(h_change_node).fnptr!(); byte timing = *(byte*)((int)lpamng + 0x11650);