From b8a7e4717ba994d29897bdf1367da77e568e4b92 Mon Sep 17 00:00:00 2001 From: evelyntsmg Date: Thu, 5 Mar 2026 13:00:00 +0100 Subject: [PATCH 1/5] Implement Hardcore Contest of Aeons I'll clean this up once I get some feedback --- src/archipelago.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/archipelago.cs b/src/archipelago.cs index bd2d6f2..6e63c35 100644 --- a/src/archipelago.cs +++ b/src/archipelago.cs @@ -136,6 +136,8 @@ public struct ArchipelagoSeedOptions { public int CaptureDamage; [JsonInclude] public int SkipContestOfAeons; + [JsonInclude] + public int HardcoreContestOfAeons; public ArchipelagoSeedOptions() { PlayerName = ""; @@ -938,6 +940,15 @@ public static uint allocate_file(string filename, out nint file_ptr) { return readBytes; } + public static void try_remove_autolife() { + // In every Contest of Aeons battle, autolife is applied at 004E through 005A, so just remove those + if (seed.Options.HardcoreContestOfAeons != 0) { + AtelScriptChunk* script_chunk = Globals.Atel.controllers[0].script_chunk; + nint code_ptr = (nint)((int)script_chunk + script_chunk->offset_code); + NativeMemory.Fill((void*)(code_ptr + 0x4E), 0xC, 0); + } + } + public override void render_imgui() { ArchipelagoGUI.render(); } From f75280f239f82081cf687e8b8040c5fb4406bb27 Mon Sep 17 00:00:00 2001 From: evelyntsmg Date: Thu, 5 Mar 2026 13:03:41 +0100 Subject: [PATCH 2/5] Combine Contest of Aeons settings --- src/archipelago.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/archipelago.cs b/src/archipelago.cs index 6e63c35..855e8a7 100644 --- a/src/archipelago.cs +++ b/src/archipelago.cs @@ -135,9 +135,7 @@ public struct ArchipelagoSeedOptions { [JsonInclude] public int CaptureDamage; [JsonInclude] - public int SkipContestOfAeons; - [JsonInclude] - public int HardcoreContestOfAeons; + public int ContestOfAeonsDifficulty; public ArchipelagoSeedOptions() { PlayerName = ""; @@ -942,7 +940,7 @@ public static uint allocate_file(string filename, out nint file_ptr) { public static void try_remove_autolife() { // In every Contest of Aeons battle, autolife is applied at 004E through 005A, so just remove those - if (seed.Options.HardcoreContestOfAeons != 0) { + if (seed.Options.ContestOfAeonsDifficulty == 2) { AtelScriptChunk* script_chunk = Globals.Atel.controllers[0].script_chunk; nint code_ptr = (nint)((int)script_chunk + script_chunk->offset_code); NativeMemory.Fill((void*)(code_ptr + 0x4E), 0xC, 0); From 3a2e53aee96f9bd9d62eefd35f54f9658912f3da Mon Sep 17 00:00:00 2001 From: evelyntsmg Date: Fri, 6 Mar 2026 14:16:39 +0100 Subject: [PATCH 3/5] Actually add the encounters --- src/data/ArchipelagoData.cs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/data/ArchipelagoData.cs b/src/data/ArchipelagoData.cs index 66dcffc..d5b17ab 100644 --- a/src/data/ArchipelagoData.cs +++ b/src/data/ArchipelagoData.cs @@ -159,7 +159,7 @@ public enum GoalRequirement { 282, 220, 139, - 191, // + 191, // 336, // Jecht Sphere 337, // Jecht Sphere 347, //Blitzball Menu @@ -606,7 +606,7 @@ public unsafe class ArchipelagoRegion { ArchipelagoFFXModule.call_warp_to_map(382, 0); }} } } } }, - {RegionEnum.BaajTemple, new(){ story_progress = 30, room_id = 48, entrance = 0, airship_destination_index = 1, + {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"); } } }, @@ -700,9 +700,9 @@ public unsafe class ArchipelagoRegion { } } } } }, - { 730, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 123, next_entrance = 6, return_to_airship = true, + { 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"); + ArchipelagoFFXModule.logger.Info("Luca visit complete"); // CSR workaround Globals.save_data->current_room_id = 123; Globals.save_data->current_spawnpoint = 6; @@ -740,7 +740,7 @@ public unsafe class ArchipelagoRegion { } } }, {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, + { 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; @@ -842,7 +842,7 @@ public unsafe class ArchipelagoRegion { { 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, // Destination 12 doesn't work (12 = Bevelle but doesn't have destination, 18 = Highbridge) + {RegionEnum.Bevelle, new(){ story_progress = 2040, room_id = 205, entrance = 0, airship_destination_index = 14, // Destination 12 doesn't work (12 = Bevelle but doesn't have destination, 18 = Highbridge) story_checks = { { 2220, new() {pilgrimage = true, check_delegate = (r) => { // Bahamut @@ -857,7 +857,7 @@ public unsafe class ArchipelagoRegion { } } }, { 2385, new() {visit_complete = true, next_story_progress = 2920, next_room_id = 208, next_entrance = 1, return_to_airship = true, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Bevelle visit 1 complete"); } } }, { 2945, new() {visit_complete = true, next_story_progress = 3210, next_room_id = 208, next_entrance = 1, check_delegate = (r) => {ArchipelagoFFXModule.logger.Info("Bevelle visit 2 complete"); } } }, - } } }, + } } }, {RegionEnum.CalmLands, new(){ story_progress = 2385, room_id = 223, entrance = 0, airship_destination_index = 15, savedata = [ new ArchipelagoRegionSaveData(0x0285, 1), @@ -1025,7 +1025,7 @@ public unsafe class ArchipelagoRegion { 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) }, // Yenke and Biran. Can only target Kimahri and scale on his stats. @@ -1144,12 +1144,23 @@ public unsafe class ArchipelagoRegion { {"bsil03_03", () => ArchipelagoFFXModule.set_underwater_party()}, // S.S Liki {"slik02_01", () => ArchipelagoFFXModule.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()}, + + // Hardcore Contest of Aeons + { "sins07_00", () => ArchipelagoFFXModule.try_remove_autolife() }, // Valefor + { "sins07_01", () => ArchipelagoFFXModule.try_remove_autolife() }, // Ifrit + { "sins07_02", () => ArchipelagoFFXModule.try_remove_autolife() }, // Ixion + { "sins07_03", () => ArchipelagoFFXModule.try_remove_autolife() }, // Shiva + { "sins07_04", () => ArchipelagoFFXModule.try_remove_autolife() }, // Bahamut + { "sins07_05", () => ArchipelagoFFXModule.try_remove_autolife() }, // Anima + { "sins07_06", () => ArchipelagoFFXModule.try_remove_autolife() }, // Yojimbo + { "sins07_07", () => ArchipelagoFFXModule.try_remove_autolife() }, // Magus Sisters + { "sins07_10", () => ArchipelagoFFXModule.try_remove_autolife() }, // Yu Yevon }; From 651d0cd5b8458835474e31cf9800793fe7ff1eda Mon Sep 17 00:00:00 2001 From: evelyntsmg Date: Fri, 6 Mar 2026 23:09:11 +0100 Subject: [PATCH 4/5] Fix old references to removed `SkipContestOfAeons` --- src/archipelago.cs | 20 ++++++++++---------- src/hooks.cs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/archipelago.cs b/src/archipelago.cs index 855e8a7..3f17807 100644 --- a/src/archipelago.cs +++ b/src/archipelago.cs @@ -138,16 +138,16 @@ public struct ArchipelagoSeedOptions { public int ContestOfAeonsDifficulty; public ArchipelagoSeedOptions() { - PlayerName = ""; - SeedId = ""; - GoalRequirement = GoalRequirement.None; - RequiredPartyMembers = 1; - RequiredPrimers = 0; - APMultiplier = 1; - AlwaysSensor = 0; - AlwaysCapture = 0; - CaptureDamage = 0; - SkipContestOfAeons = 0; + PlayerName = ""; + SeedId = ""; + GoalRequirement = GoalRequirement.None; + RequiredPartyMembers = 1; + RequiredPrimers = 0; + APMultiplier = 1; + AlwaysSensor = 0; + AlwaysCapture = 0; + CaptureDamage = 0; + ContestOfAeonsDifficulty = 2; } } public struct ArchipelagoSeedLocations { diff --git a/src/hooks.cs b/src/hooks.cs index 78081d3..455e10f 100644 --- a/src/hooks.cs +++ b/src/hooks.cs @@ -1528,7 +1528,7 @@ AtelOp.PUSHII .build(0x0000), logger.Debug($"atel_event_setup: Handle removing Aeons"); // Lock all Aeons and skip Contest of Aeons - if (seed.Options.SkipContestOfAeons == 1) { + if (seed.Options.ContestOfAeonsDifficulty == 1) { set(code_ptr, 0x58FA, [ AtelOp.CALLPOPA.build((ushort)CustomCallTarget.LOCK_ALL_AEONS), AtelOp.JMP.build(0x0003), From 5d3ff3e1d7e0cd251c381507bf03da1ed697360c Mon Sep 17 00:00:00 2001 From: evelyntsmg Date: Sat, 7 Mar 2026 11:37:40 +0100 Subject: [PATCH 5/5] Use `set()` over `NativeMemory.Fill()` --- src/archipelago.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/archipelago.cs b/src/archipelago.cs index 3f17807..86aff37 100644 --- a/src/archipelago.cs +++ b/src/archipelago.cs @@ -944,6 +944,7 @@ public static void try_remove_autolife() { AtelScriptChunk* script_chunk = Globals.Atel.controllers[0].script_chunk; nint code_ptr = (nint)((int)script_chunk + script_chunk->offset_code); NativeMemory.Fill((void*)(code_ptr + 0x4E), 0xC, 0); + set(code_ptr, 0x4E, atelNOPArray(0xC)); } }