From 4fb06cb0ffd5d78ae8e4964b54fda7296b2956f3 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 11 Jul 2024 19:46:44 -0400 Subject: [PATCH] Fortress Grave Path logic, and a couple fixes to the west garden logic --- worlds/tunic/er_data.py | 34 ++++++++++++++---- worlds/tunic/er_rules.py | 73 ++++++++++++++++++++++++++++++++------- worlds/tunic/locations.py | 4 +-- 3 files changed, 89 insertions(+), 22 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 63e97b3854..cf04afdacb 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -362,7 +362,7 @@ portal_mapping: List[Portal] = [ Portal(name="East Fortress to Interior Upper", region="Fortress East Shortcut Upper", destination="Fortress Main", tag="_upper"), - Portal(name="Fortress Grave Path Lower Exit", region="Fortress Grave Path", + Portal(name="Fortress Grave Path Lower Exit", region="Fortress Grave Path Entry", destination="Fortress Courtyard", tag="_Lower"), Portal(name="Fortress Hero's Grave", region="Fortress Hero's Grave Region", destination="RelicVoid", tag="_teleporter_relic plinth"), @@ -668,7 +668,9 @@ tunic_er_regions: Dict[str, RegionInfo] = { "Eastern Vault Fortress Gold Door": RegionInfo("Fortress Main"), "Fortress East Shortcut Upper": RegionInfo("Fortress East"), "Fortress East Shortcut Lower": RegionInfo("Fortress East"), - "Fortress Grave Path": RegionInfo("Fortress Reliquary"), + "Fortress Grave Path Entry": RegionInfo("Fortress Reliquary"), + "Fortress Grave Path Combat": RegionInfo("Fortress Reliquary"), # the combat is basically just a barrier here + "Fortress Grave Path by Grave": RegionInfo("Fortress Reliquary"), "Fortress Grave Path Upper": RegionInfo("Fortress Reliquary", dead_end=DeadEnd.restricted), "Fortress Grave Path Dusty Entrance Region": RegionInfo("Fortress Reliquary"), "Fortress Hero's Grave Region": RegionInfo("Fortress Reliquary"), @@ -1355,22 +1357,40 @@ traversal_requirements: Dict[str, Dict[str, List[List[str]]]] = { "Eastern Vault Fortress": [["IG1"]], }, - "Fortress Grave Path": { + "Fortress Grave Path Entry": { + "Fortress Grave Path Combat": + [], + # redundant here, keeping a comment to show it's intentional + # "Fortress Grave Path Dusty Entrance Region": + # [["Hyperdash"]], + }, + "Fortress Grave Path Combat": { + "Fortress Grave Path Entry": + [], + "Fortress Grave Path by Grave": + [], + }, + "Fortress Grave Path by Grave": { + "Fortress Grave Path Entry": + [], + # unnecessary, you can just skip it + # "Fortress Grave Path Combat": + # [], "Fortress Hero's Grave Region": - [], + [], "Fortress Grave Path Dusty Entrance Region": [["Hyperdash"]], }, "Fortress Grave Path Upper": { - "Fortress Grave Path": + "Fortress Grave Path Entry": [["IG1"]], }, "Fortress Grave Path Dusty Entrance Region": { - "Fortress Grave Path": + "Fortress Grave Path by Grave": [["Hyperdash"]], }, "Fortress Hero's Grave Region": { - "Fortress Grave Path": + "Fortress Grave Path by Grave": [], }, "Fortress Arena": { diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index f8bf4a341c..9692b2a4b1 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -802,22 +802,32 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ connecting_region=regions["Eastern Vault Fortress"], rule=lambda state: has_ice_grapple_logic(False, IceGrappling.option_easy, state, world)) - regions["Fortress Grave Path"].connect( - connecting_region=regions["Fortress Grave Path Dusty Entrance Region"], - rule=lambda state: state.has(laurels, player)) - regions["Fortress Grave Path Dusty Entrance Region"].connect( - connecting_region=regions["Fortress Grave Path"], - rule=lambda state: state.has(laurels, player)) + fort_grave_entry_to_combat = regions["Fortress Grave Path Entry"].connect( + connecting_region=regions["Fortress Grave Path Combat"]) + regions["Fortress Grave Path Combat"].connect( + connecting_region=regions["Fortress Grave Path Entry"]) - regions["Fortress Grave Path"].connect( + regions["Fortress Grave Path Combat"].connect( + connecting_region=regions["Fortress Grave Path by Grave"]) + + # run past the enemies + regions["Fortress Grave Path by Grave"].connect( + connecting_region=regions["Fortress Grave Path Entry"]) + + regions["Fortress Grave Path by Grave"].connect( connecting_region=regions["Fortress Hero's Grave Region"], rule=lambda state: has_ability(prayer, state, world)) regions["Fortress Hero's Grave Region"].connect( - connecting_region=regions["Fortress Grave Path"]) + connecting_region=regions["Fortress Grave Path by Grave"]) + + regions["Fortress Grave Path by Grave"].connect( + connecting_region=regions["Fortress Grave Path Dusty Entrance Region"], + rule=lambda state: state.has(laurels, player)) + # reverse connection is conditionally made later, depending on whether combat logic is on, and the details of ER # nmg: ice grapple from upper grave path to lower regions["Fortress Grave Path Upper"].connect( - connecting_region=regions["Fortress Grave Path"], + connecting_region=regions["Fortress Grave Path Entry"], rule=lambda state: has_ice_grapple_logic(True, IceGrappling.option_easy, state, world)) regions["Fortress Arena"].connect( @@ -1205,6 +1215,11 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ lambda state: has_combat_reqs("The Heir", state, player)) if world.options.combat_logic == CombatLogic.option_on: + # this is redundant with combat logic off + regions["Fortress Grave Path Entry"].connect( + connecting_region=regions["Fortress Grave Path Dusty Entrance Region"], + rule=lambda state: state.has(laurels, player)) + # need to fight through the rudelings and turret, or just laurels from near the windmill set_rule(ow_to_well_entry, lambda state: state.has(laurels, player) @@ -1242,12 +1257,17 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ set_rule(monastery_front_to_back, lambda state: has_combat_reqs("Quarry", state, player)) + set_rule(fort_grave_entry_to_combat, + lambda state: has_combat_reqs("Eastern Vault Fortress", state, player)) + # for spots where you can go into and come out of an entrance to reset enemy aggro if world.options.entrance_rando: - dagger_entry_paired_name, dagger_entry_paired_region = get_paired_portal("Archipelagos Redux, Archipelagos_house_") + # for the chest outside of magic dagger house + dagger_entry_paired_name, dagger_entry_paired_region = ( + get_paired_portal("Archipelagos Redux, archipelagos_house_")) try: - dagger_entry_paired_entrance = world.multiworld.get_entrance(dagger_entry_paired_name) - except: + dagger_entry_paired_entrance = world.multiworld.get_entrance(dagger_entry_paired_name, player) + except KeyError: # there is no paired entrance, so we don't include the can_reach set_rule(wg_checkpoint_to_dagger, lambda state: state.has(laurels, player) or has_combat_reqs("West Garden", state, player)) @@ -1255,7 +1275,34 @@ def set_er_region_rules(world: "TunicWorld", regions: Dict[str, Region], portal_ set_rule(wg_checkpoint_to_dagger, lambda state: state.has(laurels, player) or has_combat_reqs("West Garden", state, player) or dagger_entry_paired_entrance.can_reach(state)) - world.multiworld.register_indirect_condition(regions["West Garden at Dagger House"], dagger_entry_paired_region) + world.multiworld.register_indirect_condition(region=regions["West Garden at Dagger House"], + entrance=dagger_entry_paired_entrance) + + # zip past enemies in fortress grave path to enter the dusty entrance, then come back out + fort_dusty_paired_name, fort_dusty_paired_region = get_paired_portal("Fortress Reliquary, Dusty_") + try: + fort_dusty_paired_entrance = world.multiworld.get_entrance(fort_dusty_paired_name, player) + except KeyError: + # there is no paired entrance, so you can't run past to deaggro + # the path to dusty can be done via combat, so no need to do anything here + pass + else: + # there is a paired entrance, so you can use that to deaggro enemies + regions["Fortress Grave Path Dusty Entrance Region"].connect( + connecting_region=regions["Fortress Grave Path by Grave"], + rule=lambda state: state.has(laurels, player) and fort_dusty_paired_entrance.can_reach(state)) + world.multiworld.register_indirect_condition(region=regions["Fortress Grave Path by Grave"], + entrance=fort_dusty_paired_entrance) + else: + # if combat logic is on and ER is off, we can make this entrance freely + regions["Fortress Grave Path Dusty Entrance Region"].connect( + connecting_region=regions["Fortress Grave Path by Grave"], + rule=lambda state: state.has(laurels, player)) + else: + # if combat logic is off, we can make this entrance freely + regions["Fortress Grave Path Dusty Entrance Region"].connect( + connecting_region=regions["Fortress Grave Path by Grave"], + rule=lambda state: state.has(laurels, player)) def set_er_location_rules(world: "TunicWorld") -> None: diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index aaea9839fe..f7e9005eec 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -81,8 +81,8 @@ location_table: Dict[str, TunicLocationData] = { "Eastern Vault Fortress - [East Wing] Bombable Wall": TunicLocationData("Eastern Vault Fortress", "Eastern Vault Fortress"), "Eastern Vault Fortress - [West Wing] Page Pickup": TunicLocationData("Eastern Vault Fortress", "Eastern Vault Fortress"), "Fortress Grave Path - Upper Walkway": TunicLocationData("Eastern Vault Fortress", "Fortress Grave Path Upper"), - "Fortress Grave Path - Chest Right of Grave": TunicLocationData("Eastern Vault Fortress", "Fortress Grave Path"), - "Fortress Grave Path - Obscured Chest Left of Grave": TunicLocationData("Eastern Vault Fortress", "Fortress Grave Path"), + "Fortress Grave Path - Chest Right of Grave": TunicLocationData("Eastern Vault Fortress", "Fortress Grave Path by Grave"), + "Fortress Grave Path - Obscured Chest Left of Grave": TunicLocationData("Eastern Vault Fortress", "Fortress Grave Path by Grave"), "Hero's Grave - Flowers Relic": TunicLocationData("Eastern Vault Fortress", "Hero Relic - Fortress"), "Beneath the Fortress - Bridge": TunicLocationData("Beneath the Vault", "Beneath the Vault Back"), "Beneath the Fortress - Cell Chest 1": TunicLocationData("Beneath the Vault", "Beneath the Vault Back"),