From 754fc11c1b009f3ed707a80ac13fae95bb98397a Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 19 May 2024 19:01:24 -0400 Subject: [PATCH] TUNIC: ER Refactor for better plando connections, fewer shops improvement (#3075) * Fixed shop changes * Update option description * Apply suggestions from Vi's review (thank you) * Fix for plando connections on a full scene * Plando connections should work better now for complicated paths * Even more good plando connections yes * Starting to move the info over * Fixing up formatting a bit * Remove unneeded item info * Put in updated_reachable_regions, to replace add_dependent_regions * Updated to match ladder shuffle * More stuff I guess * It functions! * It mostly works with plando now, some slight issues still * Fixed minor logic bug * Fixed world leakage * Change exception message * Make exception message better for troubleshooting failed connections * Merged with main * technically a logic fix but it would never matter cause no start shuffle * Add a couple more alias item groups cause yeah * Rename beneath the vault front -> beneath the vault main * Flip lantern access rule to the region * Add missing connection to traversal reqs * Move start_inventory_from_pool to the top so that it's next to start_inventory * Reword the fixed shop description slightly * Refactor per ixrec's comments * Greatly reduced an overcomplicated block because Vi is cool and smart and also cool * Rewrite traversal reqs thing per Vi's comments --- worlds/tunic/er_data.py | 1173 +++++++++++++++++++++++++----------- worlds/tunic/er_rules.py | 23 +- worlds/tunic/er_scripts.py | 336 +++++------ worlds/tunic/items.py | 2 + worlds/tunic/locations.py | 2 +- worlds/tunic/options.py | 8 +- 6 files changed, 973 insertions(+), 571 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index d850a06d..f49e7dff 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -1,4 +1,4 @@ -from typing import Dict, NamedTuple, List, Tuple +from typing import Dict, NamedTuple, List from enum import IntEnum @@ -432,6 +432,9 @@ portal_mapping: List[Portal] = [ destination="ziggurat2020_2", tag="_"), Portal(name="Ziggurat Portal Room Entrance", region="Rooted Ziggurat Portal Room Entrance", destination="ziggurat2020_FTRoom", tag="_"), + # only if fixed shop is on, removed otherwise + Portal(name="Ziggurat Lower Falling Entrance", region="Zig Skip Exit", + destination="ziggurat2020_1", tag="_zig2_skip"), Portal(name="Ziggurat Portal Room Exit", region="Rooted Ziggurat Portal Room Exit", destination="ziggurat2020_3", tag="_"), @@ -514,13 +517,13 @@ portal_mapping: List[Portal] = [ class RegionInfo(NamedTuple): game_scene: str # the name of the scene in the actual game dead_end: int = 0 # if a region has only one exit - hint: int = 0 # what kind of hint text you should have class DeadEnd(IntEnum): free = 0 # not a dead end all_cats = 1 # dead end in every logic category restricted = 2 # dead end only in restricted + special = 3 # special handling for secret gathering place and zig skip exit # there's no dead ends that are only in unrestricted @@ -567,7 +570,7 @@ tunic_er_regions: Dict[str, RegionInfo] = { "Furnace Fuse": RegionInfo("Furnace"), # top of the furnace "Furnace Ladder Area": RegionInfo("Furnace"), # the two portals accessible by the ladder "Furnace Walking Path": RegionInfo("Furnace"), # dark tomb to west garden - "Secret Gathering Place": RegionInfo("Waterfall", dead_end=DeadEnd.all_cats), + "Secret Gathering Place": RegionInfo("Waterfall", dead_end=DeadEnd.special), "Changing Room": RegionInfo("Changing Room", dead_end=DeadEnd.all_cats), "Patrol Cave": RegionInfo("PatrolCave", dead_end=DeadEnd.all_cats), "Ruined Shop": RegionInfo("Ruined Shop", dead_end=DeadEnd.all_cats), @@ -650,7 +653,7 @@ tunic_er_regions: Dict[str, RegionInfo] = { "Fortress Courtyard": RegionInfo("Fortress Courtyard"), "Fortress Courtyard Upper": RegionInfo("Fortress Courtyard"), "Beneath the Vault Ladder Exit": RegionInfo("Fortress Basement"), - "Beneath the Vault Front": RegionInfo("Fortress Basement"), # the vanilla entry point + "Beneath the Vault Main": RegionInfo("Fortress Basement"), # the vanilla entry point "Beneath the Vault Back": RegionInfo("Fortress Basement"), # the vanilla exit point "Eastern Vault Fortress": RegionInfo("Fortress Main"), "Eastern Vault Fortress Gold Door": RegionInfo("Fortress Main"), @@ -687,6 +690,7 @@ tunic_er_regions: Dict[str, RegionInfo] = { "Rooted Ziggurat Middle Bottom": RegionInfo("ziggurat2020_2"), "Rooted Ziggurat Lower Front": RegionInfo("ziggurat2020_3"), # the vanilla entry point side "Rooted Ziggurat Lower Back": RegionInfo("ziggurat2020_3"), # the boss side + "Zig Skip Exit": RegionInfo("ziggurat2020_3", dead_end=DeadEnd.special), # the exit from zig skip, for use with fixed shop on "Rooted Ziggurat Portal Room Entrance": RegionInfo("ziggurat2020_3"), # the door itself on the zig 3 side "Rooted Ziggurat Portal": RegionInfo("ziggurat2020_FTRoom"), "Rooted Ziggurat Portal Room Exit": RegionInfo("ziggurat2020_FTRoom"), @@ -723,357 +727,812 @@ tunic_er_regions: Dict[str, RegionInfo] = { } -# the key is the region you have, the value is the regions you get for having that region -# this is mostly so we don't have to do something overly complex to get this information -# really want to get rid of this, but waiting on item plando being workable with ER -dependent_regions_restricted: Dict[Tuple[str, ...], List[str]] = { - ("Overworld", "Overworld Belltower", "Overworld Belltower at Bell", "Overworld Swamp Upper Entry", - "Overworld Special Shop Entry", "Overworld West Garden Laurels Entry", "Overworld Southeast Cross Door", - "Overworld Temple Door", "Overworld Fountain Cross Door", "Overworld Town Portal", "Overworld Spawn Portal", - "Overworld Swamp Lower Entry", "After Ruined Passage", "Above Ruined Passage", "East Overworld", "Upper Overworld", - "Overworld after Temple Rafters", "Overworld Quarry Entry", "Overworld above Patrol Cave", - "Overworld at Patrol Cave", "Overworld to West Garden Upper", "Overworld Well Ladder", "Overworld Beach", - "Overworld to Atoll Upper", "Overworld above Quarry Entrance", "Overworld after Envoy", "Overworld Tunnel Turret"): - ["Overworld", "Overworld Belltower", "Overworld Belltower at Bell", "Overworld Swamp Upper Entry", - "Overworld Special Shop Entry", "Overworld West Garden Laurels Entry", "Overworld Ruined Passage Door", - "Overworld Southeast Cross Door", "Overworld Old House Door", "Overworld Temple Door", - "Overworld Fountain Cross Door", "Overworld Town Portal", "Overworld Spawn Portal", - "Overworld Swamp Lower Entry", "After Ruined Passage", "Above Ruined Passage", "East Overworld", - "Upper Overworld", "Overworld after Temple Rafters", "Overworld Quarry Entry", "Overworld above Patrol Cave", - "Overworld at Patrol Cave", "Overworld to West Garden Upper", "Overworld Well Ladder", "Overworld Beach", - "Overworld to Atoll Upper", "Overworld Temple Door", "Overworld above Quarry Entrance", - "Overworld after Envoy", "Overworld Tunnel Turret"], - ("Hourglass Cave",): - ["Hourglass Cave", "Hourglass Cave Tower"], - ("Old House Front",): - ["Old House Front", "Old House Back"], - ("Furnace Fuse", "Furnace Ladder Area", "Furnace Walking Path"): - ["Furnace Fuse", "Furnace Ladder Area", "Furnace Walking Path"], - ("Sealed Temple", "Sealed Temple Rafters"): ["Sealed Temple", "Sealed Temple Rafters"], - ("Forest Belltower Upper",): - ["Forest Belltower Upper", "Forest Belltower Main", "Forest Belltower Lower"], - ("Forest Belltower Main",): - ["Forest Belltower Main", "Forest Belltower Lower"], - ("East Forest", "East Forest Dance Fox Spot", "East Forest Portal", "Lower Forest"): - ["East Forest", "East Forest Dance Fox Spot", "East Forest Portal", "Lower Forest"], - ("Guard House 1 East", "Guard House 1 West"): - ["Guard House 1 East", "Guard House 1 West"], - ("Guard House 2 Upper", "Guard House 2 Lower"): - ["Guard House 2 Upper", "Guard House 2 Lower"], - ("Forest Grave Path Main", "Forest Grave Path Upper"): - ["Forest Grave Path Main", "Forest Grave Path Upper", "Forest Grave Path by Grave", "Forest Hero's Grave"], - ("Forest Grave Path by Grave", "Forest Hero's Grave"): - ["Forest Grave Path by Grave", "Forest Hero's Grave"], - ("Beneath the Well Front", "Beneath the Well Main", "Beneath the Well Back", "Beneath the Well Ladder Exit"): - ["Beneath the Well Front", "Beneath the Well Main", "Beneath the Well Back", "Beneath the Well Ladder Exit"], - ("Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit", "Dark Tomb Upper"): - ["Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit", "Dark Tomb Upper"], - ("Well Boss",): - ["Dark Tomb Checkpoint", "Well Boss"], - ("West Garden", "West Garden Laurels Exit Region", "West Garden after Boss", "West Garden Hero's Grave Region"): - ["West Garden", "West Garden Laurels Exit Region", "West Garden after Boss", "West Garden Hero's Grave Region"], - ("West Garden Portal", "West Garden Portal Item"): ["West Garden Portal", "West Garden Portal Item"], - ("Ruined Atoll", "Ruined Atoll Lower Entry Area", "Ruined Atoll Frog Mouth", "Ruined Atoll Portal", - "Ruined Atoll Statue", "Ruined Atoll Ladder Tops", "Ruined Atoll Frog Eye", "Ruined Atoll Ladder Tops"): - ["Ruined Atoll", "Ruined Atoll Lower Entry Area", "Ruined Atoll Frog Mouth", "Ruined Atoll Portal", - "Ruined Atoll Statue", "Ruined Atoll Ladder Tops", "Ruined Atoll Frog Eye", "Ruined Atoll Ladder Tops"], - ("Frog Stairs Upper", "Frog Stairs Lower", "Frog Stairs to Frog's Domain"): - ["Frog Stairs Upper", "Frog Stairs Lower", "Frog Stairs to Frog's Domain"], - ("Frog's Domain", "Frog's Domain Entry"): - ["Frog's Domain", "Frog's Domain Back", "Frog's Domain Entry"], - ("Library Exterior Ladder Region", "Library Exterior Tree Region"): - ["Library Exterior Ladder Region", "Library Exterior Tree Region"], - ("Library Hall", "Library Hero's Grave Region", "Library Hall Bookshelf", "Library Hall to Rotunda"): - ["Library Hall", "Library Hero's Grave Region", "Library Hall Bookshelf", "Library Hall to Rotunda"], - ("Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab"): - ["Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab"], - ("Library Lab", "Library Lab Lower", "Library Portal", "Library Lab to Librarian"): - ["Library Lab", "Library Lab Lower", "Library Portal", "Library Lab to Librarian"], - ("Fortress Courtyard Upper",): - ["Fortress Courtyard Upper", "Fortress Exterior from East Forest", "Fortress Exterior from Overworld", - "Fortress Exterior near cave", "Fortress Courtyard"], - ("Fortress Exterior from East Forest", "Fortress Exterior from Overworld", - "Fortress Exterior near cave", "Fortress Courtyard", "Beneath the Vault Entry"): - ["Fortress Exterior from East Forest", "Fortress Exterior from Overworld", - "Fortress Exterior near cave", "Fortress Courtyard", "Beneath the Vault Entry"], - ("Beneath the Vault Front", "Beneath the Vault Back", "Beneath the Vault Ladder Exit"): - ["Beneath the Vault Front", "Beneath the Vault Back", "Beneath the Vault Ladder Exit"], - ("Fortress East Shortcut Upper",): - ["Fortress East Shortcut Upper", "Fortress East Shortcut Lower"], - ("Eastern Vault Fortress",): - ["Eastern Vault Fortress", "Eastern Vault Fortress Gold Door"], - ("Fortress Grave Path", "Fortress Grave Path Dusty Entrance Region", "Fortress Hero's Grave Region"): - ["Fortress Grave Path", "Fortress Grave Path Dusty Entrance Region", "Fortress Hero's Grave Region"], - ("Fortress Arena", "Fortress Arena Portal"): - ["Fortress Arena", "Fortress Arena Portal"], - ("Lower Mountain", "Lower Mountain Stairs"): - ["Lower Mountain", "Lower Mountain Stairs"], - ("Monastery Front",): - ["Monastery Front", "Monastery Back", "Monastery Hero's Grave Region"], - ("Monastery Back", "Monastery Hero's Grave Region"): - ["Monastery Back", "Monastery Hero's Grave Region"], - ("Quarry", "Quarry Portal", "Lower Quarry", "Quarry Entry", "Quarry Back", "Quarry Monastery Entry", - "Even Lower Quarry"): - ["Quarry", "Quarry Portal", "Lower Quarry", "Quarry Entry", "Quarry Back", "Quarry Monastery Entry", - "Lower Quarry Zig Door", "Even Lower Quarry"], - ("Monastery Rope",): ["Monastery Rope", "Quarry", "Quarry Entry", "Quarry Back", "Quarry Portal", "Lower Quarry", - "Lower Quarry Zig Door", "Even Lower Quarry"], - ("Rooted Ziggurat Upper Entry", "Rooted Ziggurat Upper Front"): - ["Rooted Ziggurat Upper Entry", "Rooted Ziggurat Upper Front", "Rooted Ziggurat Upper Back"], - ("Rooted Ziggurat Middle Top",): - ["Rooted Ziggurat Middle Top", "Rooted Ziggurat Middle Bottom"], - ("Rooted Ziggurat Lower Front", "Rooted Ziggurat Lower Back", "Rooted Ziggurat Portal Room Entrance"): - ["Rooted Ziggurat Lower Front", "Rooted Ziggurat Lower Back", "Rooted Ziggurat Portal Room Entrance"], - ("Rooted Ziggurat Portal", "Rooted Ziggurat Portal Room Exit"): - ["Rooted Ziggurat Portal", "Rooted Ziggurat Portal Room Exit"], - ("Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp Ledge under Cathedral Door"): - ["Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance Region", - "Swamp Ledge under Cathedral Door"], - ("Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave Region"): - ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave Region"], - ("Cathedral Gauntlet Checkpoint",): - ["Cathedral Gauntlet Checkpoint", "Cathedral Gauntlet Exit", "Cathedral Gauntlet"], - ("Cathedral Gauntlet Exit",): - ["Cathedral Gauntlet Exit", "Cathedral Gauntlet"], - ("Far Shore", "Far Shore to Spawn Region", "Far Shore to East Forest Region", "Far Shore to Quarry Region", - "Far Shore to Fortress Region", "Far Shore to Library Region", "Far Shore to West Garden Region"): - ["Far Shore", "Far Shore to Spawn Region", "Far Shore to East Forest Region", "Far Shore to Quarry Region", - "Far Shore to Fortress Region", "Far Shore to Library Region", "Far Shore to West Garden Region"] -} - - -dependent_regions_nmg: Dict[Tuple[str, ...], List[str]] = { - ("Overworld", "Overworld Belltower", "Overworld Belltower at Bell", "Overworld Swamp Upper Entry", - "Overworld Special Shop Entry", "Overworld West Garden Laurels Entry", "Overworld Southeast Cross Door", - "Overworld Temple Door", "Overworld Fountain Cross Door", "Overworld Town Portal", "Overworld Spawn Portal", - "Overworld Ruined Passage Door", "Overworld Swamp Lower Entry", "After Ruined Passage", "Above Ruined Passage", - "East Overworld", "Upper Overworld", "Overworld after Temple Rafters", "Overworld Quarry Entry", - "Overworld above Patrol Cave", "Overworld at Patrol Cave", "Overworld to West Garden Upper", - "Overworld Well Ladder", "Overworld Beach", "Overworld to Atoll Upper", "Overworld above Quarry Entrance", - "Overworld after Envoy", "Overworld Tunnel Turret"): - ["Overworld", "Overworld Belltower", "Overworld Belltower at Bell", "Overworld Swamp Upper Entry", - "Overworld Special Shop Entry", "Overworld West Garden Laurels Entry", "Overworld Ruined Passage Door", - "Overworld Southeast Cross Door", "Overworld Old House Door", "Overworld Temple Door", - "Overworld Fountain Cross Door", "Overworld Town Portal", "Overworld Spawn Portal", - "Overworld Swamp Lower Entry", "After Ruined Passage", "Above Ruined Passage", "East Overworld", - "Upper Overworld", "Overworld after Temple Rafters", "Overworld Quarry Entry", "Overworld above Patrol Cave", - "Overworld at Patrol Cave", "Overworld to West Garden Upper", "Overworld Well Ladder", "Overworld Beach", - "Overworld to Atoll Upper", "Overworld above Quarry Entrance", "Overworld after Envoy", - "Overworld Tunnel Turret"], - # can laurels through the gate - ("Old House Front", "Old House Back"): - ["Old House Front", "Old House Back"], - ("Hourglass Cave",): - ["Hourglass Cave", "Hourglass Cave Tower"], - ("Furnace Fuse", "Furnace Ladder Area", "Furnace Walking Path"): - ["Furnace Fuse", "Furnace Ladder Area", "Furnace Walking Path"], - ("Sealed Temple", "Sealed Temple Rafters"): ["Sealed Temple", "Sealed Temple Rafters"], - ("Forest Belltower Upper",): - ["Forest Belltower Upper", "Forest Belltower Main", "Forest Belltower Lower"], - ("Forest Belltower Main",): - ["Forest Belltower Main", "Forest Belltower Lower"], - ("East Forest", "East Forest Dance Fox Spot", "East Forest Portal", "Lower Forest"): - ["East Forest", "East Forest Dance Fox Spot", "East Forest Portal", "Lower Forest"], - ("Guard House 1 East", "Guard House 1 West"): - ["Guard House 1 East", "Guard House 1 West"], - ("Guard House 2 Upper", "Guard House 2 Lower"): - ["Guard House 2 Upper", "Guard House 2 Lower"], - ("Forest Grave Path Main", "Forest Grave Path Upper", "Forest Grave Path by Grave", "Forest Hero's Grave"): - ["Forest Grave Path Main", "Forest Grave Path Upper", "Forest Grave Path by Grave", "Forest Hero's Grave"], - ("Beneath the Well Front", "Beneath the Well Main", "Beneath the Well Back", "Beneath the Well Ladder Exit"): - ["Beneath the Well Front", "Beneath the Well Main", "Beneath the Well Back", "Beneath the Well Ladder Exit"], - ("Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit", "Dark Tomb Upper"): - ["Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit", "Dark Tomb Upper"], - ("Dark Tomb Checkpoint", "Well Boss"): - ["Dark Tomb Checkpoint", "Well Boss"], - ("West Garden", "West Garden Laurels Exit Region", "West Garden after Boss", "West Garden Hero's Grave Region", - "West Garden Portal", "West Garden Portal Item"): - ["West Garden", "West Garden Laurels Exit Region", "West Garden after Boss", "West Garden Hero's Grave Region", - "West Garden Portal", "West Garden Portal Item"], - ("Ruined Atoll", "Ruined Atoll Lower Entry Area", "Ruined Atoll Frog Mouth", "Ruined Atoll Portal", - "Ruined Atoll Statue", "Ruined Atoll Ladder Tops", "Ruined Atoll Frog Eye", "Ruined Atoll Ladder Tops"): - ["Ruined Atoll", "Ruined Atoll Lower Entry Area", "Ruined Atoll Frog Mouth", "Ruined Atoll Portal", - "Ruined Atoll Statue", "Ruined Atoll Ladder Tops", "Ruined Atoll Frog Eye", "Ruined Atoll Ladder Tops"], - ("Frog Stairs Upper", "Frog Stairs Lower", "Frog Stairs to Frog's Domain"): - ["Frog Stairs Upper", "Frog Stairs Lower", "Frog Stairs to Frog's Domain"], - ("Frog's Domain", "Frog's Domain Entry"): - ["Frog's Domain", "Frog's Domain Back", "Frog's Domain Entry"], - ("Library Exterior Ladder Region", "Library Exterior Tree Region"): - ["Library Exterior Ladder Region", "Library Exterior Tree Region"], - ("Library Hall", "Library Hero's Grave Region", "Library Hall Bookshelf", "Library Hall to Rotunda"): - ["Library Hall", "Library Hero's Grave Region", "Library Hall Bookshelf", "Library Hall to Rotunda"], - ("Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab"): - ["Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab"], - ("Library Lab", "Library Lab Lower", "Library Portal", "Library Lab to Librarian"): - ["Library Lab", "Library Lab Lower", "Library Portal", "Library Lab to Librarian"], - ("Fortress Exterior from East Forest", "Fortress Exterior from Overworld", - "Fortress Exterior near cave", "Fortress Courtyard", "Fortress Courtyard Upper", "Beneath the Vault Entry"): - ["Fortress Exterior from East Forest", "Fortress Exterior from Overworld", - "Fortress Exterior near cave", "Fortress Courtyard", "Fortress Courtyard Upper", "Beneath the Vault Entry"], - ("Beneath the Vault Front", "Beneath the Vault Back", "Beneath the Vault Ladder Exit"): - ["Beneath the Vault Front", "Beneath the Vault Back", "Beneath the Vault Ladder Exit"], - ("Fortress East Shortcut Upper", "Fortress East Shortcut Lower"): - ["Fortress East Shortcut Upper", "Fortress East Shortcut Lower"], - ("Eastern Vault Fortress", "Eastern Vault Fortress Gold Door"): - ["Eastern Vault Fortress", "Eastern Vault Fortress Gold Door"], - ("Fortress Grave Path", "Fortress Grave Path Dusty Entrance Region", "Fortress Hero's Grave Region"): - ["Fortress Grave Path", "Fortress Grave Path Dusty Entrance Region", "Fortress Hero's Grave Region"], - ("Fortress Grave Path Upper",): - ["Fortress Grave Path Upper", "Fortress Grave Path", "Fortress Grave Path Dusty Entrance Region", - "Fortress Hero's Grave Region"], - ("Fortress Arena", "Fortress Arena Portal"): - ["Fortress Arena", "Fortress Arena Portal"], - ("Lower Mountain", "Lower Mountain Stairs"): - ["Lower Mountain", "Lower Mountain Stairs"], - ("Monastery Front", "Monastery Back", "Monastery Hero's Grave Region"): - ["Monastery Front", "Monastery Back", "Monastery Hero's Grave Region"], - ("Quarry", "Quarry Portal", "Lower Quarry", "Quarry Entry", "Quarry Back", "Quarry Monastery Entry", - "Even Lower Quarry"): - ["Quarry", "Quarry Portal", "Lower Quarry", "Quarry Entry", "Quarry Back", "Quarry Monastery Entry", - "Lower Quarry Zig Door", "Even Lower Quarry"], - ("Monastery Rope",): ["Monastery Rope", "Quarry", "Quarry Entry", "Quarry Back", "Quarry Portal", "Lower Quarry", - "Lower Quarry Zig Door", "Even Lower Quarry"], - ("Rooted Ziggurat Upper Entry", "Rooted Ziggurat Upper Front"): - ["Rooted Ziggurat Upper Entry", "Rooted Ziggurat Upper Front", "Rooted Ziggurat Upper Back"], - ("Rooted Ziggurat Middle Top",): - ["Rooted Ziggurat Middle Top", "Rooted Ziggurat Middle Bottom"], - ("Rooted Ziggurat Lower Front", "Rooted Ziggurat Lower Back", "Rooted Ziggurat Portal Room Entrance"): - ["Rooted Ziggurat Lower Front", "Rooted Ziggurat Lower Back", "Rooted Ziggurat Portal Room Entrance"], - ("Rooted Ziggurat Portal", "Rooted Ziggurat Portal Room Exit"): - ["Rooted Ziggurat Portal", "Rooted Ziggurat Portal Room Exit"], - ("Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance Region", - "Swamp Ledge under Cathedral Door"): - ["Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance Region", - "Swamp Ledge under Cathedral Door"], - ("Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave Region"): - ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave Region", "Swamp Front", "Swamp Mid", - "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance Region", - "Swamp Ledge under Cathedral Door"], - ("Cathedral Gauntlet Checkpoint",): - ["Cathedral Gauntlet Checkpoint", "Cathedral Gauntlet Exit", "Cathedral Gauntlet"], - ("Cathedral Gauntlet Exit",): - ["Cathedral Gauntlet Exit", "Cathedral Gauntlet"], - ("Far Shore", "Far Shore to Spawn Region", "Far Shore to East Forest Region", "Far Shore to Quarry Region", - "Far Shore to Fortress Region", "Far Shore to Library Region", "Far Shore to West Garden Region"): - ["Far Shore", "Far Shore to Spawn Region", "Far Shore to East Forest Region", "Far Shore to Quarry Region", - "Far Shore to Fortress Region", "Far Shore to Library Region", "Far Shore to West Garden Region"] -} - - -dependent_regions_ur: Dict[Tuple[str, ...], List[str]] = { - # can use ladder storage to get to the well rail - ("Overworld", "Overworld Belltower", "Overworld Belltower at Bell", "Overworld Swamp Upper Entry", - "Overworld Special Shop Entry", "Overworld West Garden Laurels Entry", "Overworld Southeast Cross Door", - "Overworld Temple Door", "Overworld Fountain Cross Door", "Overworld Town Portal", "Overworld Spawn Portal", - "Overworld Ruined Passage Door", "Overworld Swamp Lower Entry", "After Ruined Passage", "Above Ruined Passage", - "East Overworld", "Upper Overworld", "Overworld after Temple Rafters", "Overworld Quarry Entry", - "Overworld above Patrol Cave", "Overworld at Patrol Cave", "Overworld to West Garden Upper", - "Overworld Well Ladder", "Overworld Beach", "Overworld to Atoll Upper", "Overworld above Quarry Entrance", - "Overworld after Envoy", "Overworld Tunnel Turret"): - ["Overworld", "Overworld Belltower", "Overworld Belltower at Bell", "Overworld Swamp Upper Entry", - "Overworld Special Shop Entry", "Overworld West Garden Laurels Entry", "Overworld Southeast Cross Door", - "Overworld Temple Door", "Overworld Fountain Cross Door", "Overworld Town Portal", "Overworld Spawn Portal", - "Overworld Ruined Passage Door", "Overworld Swamp Lower Entry", "After Ruined Passage", - "Above Ruined Passage", "East Overworld", "Upper Overworld", "Overworld after Temple Rafters", - "Overworld Quarry Entry", "Overworld above Patrol Cave", "Overworld at Patrol Cave", - "Overworld to West Garden Upper", "Overworld Well Ladder", "Overworld Beach", "Overworld to Atoll Upper", - "Overworld above Quarry Entrance", "Overworld after Envoy", "Overworld Tunnel Turret"], - # can laurels through the gate - ("Old House Front", "Old House Back"): - ["Old House Front", "Old House Back"], - ("Hourglass Cave",): - ["Hourglass Cave", "Hourglass Cave Tower"], - ("Furnace Fuse", "Furnace Ladder Area", "Furnace Walking Path"): - ["Furnace Fuse", "Furnace Ladder Area", "Furnace Walking Path"], - ("Sealed Temple", "Sealed Temple Rafters"): ["Sealed Temple", "Sealed Temple Rafters"], - ("Forest Belltower Upper",): - ["Forest Belltower Upper", "Forest Belltower Main", "Forest Belltower Lower"], - ("Forest Belltower Main",): - ["Forest Belltower Main", "Forest Belltower Lower"], - ("East Forest", "East Forest Dance Fox Spot", "East Forest Portal", "Lower Forest"): - ["East Forest", "East Forest Dance Fox Spot", "East Forest Portal", "Lower Forest"], - ("Guard House 1 East", "Guard House 1 West"): - ["Guard House 1 East", "Guard House 1 West"], - ("Guard House 2 Upper", "Guard House 2 Lower"): - ["Guard House 2 Upper", "Guard House 2 Lower"], - # can use laurels, ice grapple, or ladder storage to traverse - ("Forest Grave Path Main", "Forest Grave Path Upper", "Forest Grave Path by Grave", "Forest Hero's Grave"): - ["Forest Grave Path Main", "Forest Grave Path Upper", "Forest Grave Path by Grave", "Forest Hero's Grave"], - ("Beneath the Well Front", "Beneath the Well Main", "Beneath the Well Back", "Beneath the Well Ladder Exit"): - ["Beneath the Well Front", "Beneath the Well Main", "Beneath the Well Back", "Beneath the Well Ladder Exit"], - ("Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit", "Dark Tomb Upper"): - ["Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit", "Dark Tomb Upper"], - ("Dark Tomb Checkpoint", "Well Boss"): - ["Dark Tomb Checkpoint", "Well Boss"], - # can ice grapple from portal area to the rest, and vice versa - ("West Garden", "West Garden Laurels Exit Region", "West Garden after Boss", "West Garden Hero's Grave Region", - "West Garden Portal", "West Garden Portal Item"): - ["West Garden", "West Garden Laurels Exit Region", "West Garden after Boss", "West Garden Hero's Grave Region", - "West Garden Portal", "West Garden Portal Item"], - ("Ruined Atoll", "Ruined Atoll Lower Entry Area", "Ruined Atoll Frog Mouth", "Ruined Atoll Portal", - "Ruined Atoll Statue", "Ruined Atoll Ladder Tops", "Ruined Atoll Frog Eye", "Ruined Atoll Ladder Tops"): - ["Ruined Atoll", "Ruined Atoll Lower Entry Area", "Ruined Atoll Frog Mouth", "Ruined Atoll Portal", - "Ruined Atoll Statue", "Ruined Atoll Ladder Tops", "Ruined Atoll Frog Eye", "Ruined Atoll Ladder Tops"], - ("Frog Stairs Upper", "Frog Stairs Lower", "Frog Stairs to Frog's Domain"): - ["Frog Stairs Upper", "Frog Stairs Lower", "Frog Stairs to Frog's Domain"], - ("Frog's Domain", "Frog's Domain Entry"): - ["Frog's Domain", "Frog's Domain Back", "Frog's Domain Entry"], - ("Library Exterior Ladder Region", "Library Exterior Tree Region"): - ["Library Exterior Ladder Region", "Library Exterior Tree Region"], - ("Library Hall", "Library Hero's Grave Region", "Library Hall Bookshelf", "Library Hall to Rotunda"): - ["Library Hall", "Library Hero's Grave Region", "Library Hall Bookshelf", "Library Hall to Rotunda"], - ("Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab"): - ["Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab"], - ("Library Lab", "Library Lab Lower", "Library Portal", "Library Lab to Librarian"): - ["Library Lab", "Library Lab Lower", "Library Portal", "Library Lab to Librarian"], - # can use ice grapple or ladder storage to get from any ladder to upper - ("Fortress Exterior from East Forest", "Fortress Exterior from Overworld", - "Fortress Exterior near cave", "Fortress Courtyard", "Fortress Courtyard Upper", "Beneath the Vault Entry"): - ["Fortress Exterior from East Forest", "Fortress Exterior from Overworld", - "Fortress Exterior near cave", "Fortress Courtyard", "Fortress Courtyard Upper", "Beneath the Vault Entry"], - ("Beneath the Vault Front", "Beneath the Vault Back", "Beneath the Vault Ladder Exit"): - ["Beneath the Vault Front", "Beneath the Vault Back", "Beneath the Vault Ladder Exit"], - # can ice grapple up - ("Fortress East Shortcut Upper", "Fortress East Shortcut Lower"): - ["Fortress East Shortcut Upper", "Fortress East Shortcut Lower"], - ("Eastern Vault Fortress", "Eastern Vault Fortress Gold Door"): - ["Eastern Vault Fortress", "Eastern Vault Fortress Gold Door"], - ("Fortress Grave Path", "Fortress Grave Path Dusty Entrance Region", "Fortress Hero's Grave Region"): - ["Fortress Grave Path", "Fortress Grave Path Dusty Entrance Region", "Fortress Hero's Grave Region"], - # can ice grapple down - ("Fortress Grave Path Upper",): - ["Fortress Grave Path Upper", "Fortress Grave Path", "Fortress Grave Path Dusty Entrance Region", - "Fortress Hero's Grave Region"], - ("Fortress Arena", "Fortress Arena Portal"): - ["Fortress Arena", "Fortress Arena Portal"], - ("Lower Mountain", "Lower Mountain Stairs"): - ["Lower Mountain", "Lower Mountain Stairs"], - ("Monastery Front", "Monastery Back", "Monastery Hero's Grave Region"): - ["Monastery Front", "Monastery Back", "Monastery Hero's Grave Region"], - # can use ladder storage at any of the Quarry ladders to get to Monastery Rope - ("Quarry", "Quarry Portal", "Lower Quarry", "Quarry Entry", "Quarry Back", "Quarry Monastery Entry", - "Monastery Rope", "Even Lower Quarry"): - ["Quarry", "Quarry Portal", "Lower Quarry", "Quarry Entry", "Quarry Back", "Quarry Monastery Entry", - "Monastery Rope", "Lower Quarry Zig Door", "Even Lower Quarry"], - ("Rooted Ziggurat Upper Entry", "Rooted Ziggurat Upper Front"): - ["Rooted Ziggurat Upper Entry", "Rooted Ziggurat Upper Front", "Rooted Ziggurat Upper Back"], - ("Rooted Ziggurat Middle Top",): - ["Rooted Ziggurat Middle Top", "Rooted Ziggurat Middle Bottom"], - ("Rooted Ziggurat Lower Front", "Rooted Ziggurat Lower Back", "Rooted Ziggurat Portal Room Entrance"): - ["Rooted Ziggurat Lower Front", "Rooted Ziggurat Lower Back", "Rooted Ziggurat Portal Room Entrance"], - ("Rooted Ziggurat Portal", "Rooted Ziggurat Portal Room Exit"): - ["Rooted Ziggurat Portal", "Rooted Ziggurat Portal Room Exit"], - ("Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance Region", - "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave Region", "Swamp Ledge under Cathedral Door"): - ["Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance Region", - "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave Region", - "Swamp Ledge under Cathedral Door"], - ("Cathedral Gauntlet Checkpoint",): - ["Cathedral Gauntlet Checkpoint", "Cathedral Gauntlet Exit", "Cathedral Gauntlet"], - ("Cathedral Gauntlet Exit",): - ["Cathedral Gauntlet Exit", "Cathedral Gauntlet"], - ("Far Shore", "Far Shore to Spawn Region", "Far Shore to East Forest Region", "Far Shore to Quarry Region", - "Far Shore to Fortress Region", "Far Shore to Library Region", "Far Shore to West Garden Region"): - ["Far Shore", "Far Shore to Spawn Region", "Far Shore to East Forest Region", "Far Shore to Quarry Region", - "Far Shore to Fortress Region", "Far Shore to Library Region", "Far Shore to West Garden Region"] +traversal_requirements: Dict[str, Dict[str, List[List[str]]]] = { + "Overworld": { + "Overworld Beach": + [], + "Overworld to Atoll Upper": + [["Hyperdash"]], + "Overworld Belltower": + [["Hyperdash"], ["UR"]], + "Overworld Swamp Upper Entry": + [["Hyperdash"], ["UR"]], + "Overworld Swamp Lower Entry": + [], + "Overworld Special Shop Entry": + [["Hyperdash"], ["UR"]], + "Overworld Well Ladder": + [], + "Overworld Ruined Passage Door": + [], + "After Ruined Passage": + [], + "Above Ruined Passage": + [], + "East Overworld": + [], + "Overworld above Patrol Cave": + [], + "Overworld above Quarry Entrance": + [], + "Overworld after Envoy": + [], + "Overworld Quarry Entry": + [["NMG"]], + "Overworld Tunnel Turret": + [["NMG"], ["Hyperdash"]], + "Overworld Temple Door": + [["NMG"], ["Forest Belltower Upper", "Overworld Belltower"]], + "Overworld Southeast Cross Door": + [], + "Overworld Fountain Cross Door": + [], + "Overworld Town Portal": + [], + "Overworld Spawn Portal": + [], + "Overworld Well to Furnace Rail": + [["UR"]], + "Overworld Old House Door": + [], + }, + "East Overworld": { + "Above Ruined Passage": + [], + "After Ruined Passage": + [["NMG"]], + "Overworld": + [], + "Overworld at Patrol Cave": + [], + "Overworld above Patrol Cave": + [], + "Overworld Special Shop Entry": + [["Hyperdash"], ["UR"]] + }, + "Overworld Special Shop Entry": { + "East Overworld": + [["Hyperdash"]] + }, + "Overworld Belltower": { + "Overworld Belltower at Bell": + [], + "Overworld": + [], + "Overworld to West Garden Upper": + [], + }, + "Overworld to West Garden Upper": { + "Overworld Belltower": + [], + }, + "Overworld Swamp Upper Entry": { + "Overworld": + [], + }, + "Overworld Swamp Lower Entry": { + "Overworld": + [], + }, + "Overworld Beach": { + "Overworld": + [], + "Overworld West Garden Laurels Entry": + [["Hyperdash"]], + "Overworld to Atoll Upper": + [], + "Overworld Tunnel Turret": + [], + }, + "Overworld West Garden Laurels Entry": { + "Overworld Beach": + [["Hyperdash"]], + }, + "Overworld to Atoll Upper": { + "Overworld": + [], + "Overworld Beach": + [], + }, + "Overworld Tunnel Turret": { + "Overworld": + [], + "Overworld Beach": + [], + }, + "Overworld Well Ladder": { + "Overworld": + [], + }, + "Overworld at Patrol Cave": { + "East Overworld": + [["Hyperdash"]], + "Overworld above Patrol Cave": + [], + }, + "Overworld above Patrol Cave": { + "Overworld": + [], + "East Overworld": + [], + "Upper Overworld": + [], + "Overworld at Patrol Cave": + [], + "Overworld Belltower at Bell": + [["NMG"]], + }, + "Upper Overworld": { + "Overworld above Patrol Cave": + [], + "Overworld above Quarry Entrance": + [], + "Overworld after Temple Rafters": + [], + }, + "Overworld after Temple Rafters": { + "Upper Overworld": + [], + }, + "Overworld above Quarry Entrance": { + "Overworld": + [], + "Upper Overworld": + [], + }, + "Overworld Quarry Entry": { + "Overworld after Envoy": + [], + "Overworld": + [["NMG"]], + }, + "Overworld after Envoy": { + "Overworld": + [], + "Overworld Quarry Entry": + [], + }, + "After Ruined Passage": { + "Overworld": + [], + "Above Ruined Passage": + [], + "East Overworld": + [["NMG"]], + }, + "Above Ruined Passage": { + "Overworld": + [], + "After Ruined Passage": + [], + "East Overworld": + [], + }, + "Overworld Ruined Passage Door": { + "Overworld": + [["Hyperdash", "NMG"]], + }, + "Overworld Town Portal": { + "Overworld": + [], + }, + "Overworld Spawn Portal": { + "Overworld": + [], + }, + "Old House Front": { + "Old House Back": + [], + }, + "Old House Back": { + "Old House Front": + [["Hyperdash", "NMG"]], + }, + "Furnace Fuse": { + "Furnace Ladder Area": + [["Hyperdash"]], + }, + "Furnace Ladder Area": { + "Furnace Fuse": + [["Hyperdash"], ["UR"]], + "Furnace Walking Path": + [["Hyperdash"], ["UR"]], + }, + "Furnace Walking Path": { + "Furnace Ladder Area": + [["Hyperdash"]], + }, + "Sealed Temple": { + "Sealed Temple Rafters": + [], + }, + "Sealed Temple Rafters": { + "Sealed Temple": + [["Hyperdash"]], + }, + "Hourglass Cave": { + "Hourglass Cave Tower": + [], + }, + "Forest Belltower Upper": { + "Forest Belltower Main": + [], + }, + "Forest Belltower Main": { + "Forest Belltower Lower": + [], + }, + "East Forest": { + "East Forest Dance Fox Spot": + [["Hyperdash"], ["NMG"]], + "East Forest Portal": + [], + "Lower Forest": + [], + }, + "East Forest Dance Fox Spot": { + "East Forest": + [["Hyperdash"], ["NMG"]], + }, + "East Forest Portal": { + "East Forest": + [], + }, + "Lower Forest": { + "East Forest": + [], + }, + "Guard House 1 East": { + "Guard House 1 West": + [], + }, + "Guard House 1 West": { + "Guard House 1 East": + [["Hyperdash"], ["UR"]], + }, + "Guard House 2 Upper": { + "Guard House 2 Lower": + [], + }, + "Guard House 2 Lower": { + "Guard House 2 Upper": + [], + }, + "Forest Grave Path Main": { + "Forest Grave Path Upper": + [["Hyperdash"], ["UR"]], + "Forest Grave Path by Grave": + [], + }, + "Forest Grave Path Upper": { + "Forest Grave Path Main": + [["Hyperdash"], ["NMG"]], + }, + "Forest Grave Path by Grave": { + "Forest Hero's Grave": + [], + "Forest Grave Path Main": + [["NMG"]], + }, + "Forest Hero's Grave": { + "Forest Grave Path by Grave": + [], + }, + "Beneath the Well Ladder Exit": { + "Beneath the Well Front": + [], + }, + "Beneath the Well Front": { + "Beneath the Well Ladder Exit": + [], + "Beneath the Well Main": + [], + }, + "Beneath the Well Main": { + "Beneath the Well Front": + [], + "Beneath the Well Back": + [], + }, + "Beneath the Well Back": { + "Beneath the Well Main": + [], + }, + "Well Boss": { + "Dark Tomb Checkpoint": + [], + }, + "Dark Tomb Checkpoint": { + "Well Boss": + [["Hyperdash", "NMG"]], + }, + "Dark Tomb Entry Point": { + "Dark Tomb Upper": + [], + }, + "Dark Tomb Upper": { + "Dark Tomb Entry Point": + [], + "Dark Tomb Main": + [], + }, + "Dark Tomb Main": { + "Dark Tomb Upper": + [], + "Dark Tomb Dark Exit": + [], + }, + "Dark Tomb Dark Exit": { + "Dark Tomb Main": + [], + }, + "West Garden": { + "West Garden Laurels Exit Region": + [["Hyperdash"], ["UR"]], + "West Garden after Boss": + [], + "West Garden Hero's Grave Region": + [], + "West Garden Portal Item": + [["NMG"]], + }, + "West Garden Laurels Exit Region": { + "West Garden": + [["Hyperdash"]], + }, + "West Garden after Boss": { + "West Garden": + [["Hyperdash"]], + }, + "West Garden Portal Item": { + "West Garden": + [["NMG"]], + "West Garden Portal": + [["Hyperdash", "West Garden"]], + }, + "West Garden Portal": { + "West Garden Portal Item": + [["Hyperdash"]], + }, + "West Garden Hero's Grave Region": { + "West Garden": + [], + }, + "Ruined Atoll": { + "Ruined Atoll Lower Entry Area": + [["Hyperdash"], ["UR"]], + "Ruined Atoll Ladder Tops": + [], + "Ruined Atoll Frog Mouth": + [], + "Ruined Atoll Frog Eye": + [], + "Ruined Atoll Portal": + [], + "Ruined Atoll Statue": + [], + }, + "Ruined Atoll Lower Entry Area": { + "Ruined Atoll": + [], + }, + "Ruined Atoll Ladder Tops": { + "Ruined Atoll": + [], + }, + "Ruined Atoll Frog Mouth": { + "Ruined Atoll": + [], + }, + "Ruined Atoll Frog Eye": { + "Ruined Atoll": + [], + }, + "Ruined Atoll Portal": { + "Ruined Atoll": + [], + }, + "Ruined Atoll Statue": { + "Ruined Atoll": + [], + }, + "Frog Stairs Eye Exit": { + "Frog Stairs Upper": + [], + }, + "Frog Stairs Upper": { + "Frog Stairs Eye Exit": + [], + "Frog Stairs Lower": + [], + }, + "Frog Stairs Lower": { + "Frog Stairs Upper": + [], + "Frog Stairs to Frog's Domain": + [], + }, + "Frog Stairs to Frog's Domain": { + "Frog Stairs Lower": + [], + }, + "Frog's Domain Entry": { + "Frog's Domain": + [], + }, + "Frog's Domain": { + "Frog's Domain Entry": + [], + "Frog's Domain Back": + [], + }, + "Library Exterior Ladder Region": { + "Library Exterior Tree Region": + [], + }, + "Library Exterior Tree Region": { + "Library Exterior Ladder Region": + [], + }, + "Library Hall Bookshelf": { + "Library Hall": + [], + }, + "Library Hall": { + "Library Hall Bookshelf": + [], + "Library Hero's Grave Region": + [], + }, + "Library Hero's Grave Region": { + "Library Hall": + [], + }, + "Library Hall to Rotunda": { + "Library Hall": + [], + }, + "Library Rotunda to Hall": { + "Library Rotunda": + [], + }, + "Library Rotunda": { + "Library Rotunda to Hall": + [], + "Library Rotunda to Lab": + [], + }, + "Library Rotunda to Lab": { + "Library Rotunda": + [], + }, + + "Library Lab Lower": { + "Library Lab": + [], + }, + "Library Lab": { + "Library Lab Lower": + [["Hyperdash"]], + "Library Portal": + [], + "Library Lab to Librarian": + [], + }, + "Library Portal": { + "Library Lab": + [], + }, + "Library Lab to Librarian": { + "Library Lab": + [], + }, + "Fortress Exterior from East Forest": { + "Fortress Exterior from Overworld": + [], + "Fortress Courtyard Upper": + [["UR"]], + "Fortress Exterior near cave": + [["UR"]], + "Fortress Courtyard": + [["UR"]], + }, + "Fortress Exterior from Overworld": { + "Fortress Exterior from East Forest": + [["Hyperdash"]], + "Fortress Exterior near cave": + [], + "Fortress Courtyard": + [["Hyperdash"], ["NMG"]], + }, + "Fortress Exterior near cave": { + "Fortress Exterior from Overworld": + [["Hyperdash"], ["UR"]], + "Fortress Courtyard": + [["UR"]], + "Fortress Courtyard Upper": + [["UR"]], + "Beneath the Vault Entry": + [], + }, + "Beneath the Vault Entry": { + "Fortress Exterior near cave": + [], + }, + "Fortress Courtyard": { + "Fortress Courtyard Upper": + [["NMG"]], + "Fortress Exterior from Overworld": + [["Hyperdash"]], + }, + "Fortress Courtyard Upper": { + "Fortress Courtyard": + [], + }, + "Beneath the Vault Ladder Exit": { + "Beneath the Vault Main": + [], + }, + "Beneath the Vault Main": { + "Beneath the Vault Ladder Exit": + [], + "Beneath the Vault Back": + [], + }, + "Beneath the Vault Back": { + "Beneath the Vault Main": + [], + "Beneath the Vault Ladder Exit": + [], + }, + "Fortress East Shortcut Lower": { + "Fortress East Shortcut Upper": + [["NMG"]], + }, + "Fortress East Shortcut Upper": { + "Fortress East Shortcut Lower": + [], + }, + "Eastern Vault Fortress": { + "Eastern Vault Fortress Gold Door": + [["NMG"], ["Fortress Exterior from Overworld", "Beneath the Vault Back", "Fortress Courtyard Upper"]], + }, + "Eastern Vault Fortress Gold Door": { + "Eastern Vault Fortress": + [["NMG"]], + }, + "Fortress Grave Path": { + "Fortress Hero's Grave Region": + [], + "Fortress Grave Path Dusty Entrance Region": + [["Hyperdash"]], + }, + "Fortress Grave Path Upper": { + "Fortress Grave Path": + [["NMG"]], + }, + "Fortress Grave Path Dusty Entrance Region": { + "Fortress Grave Path": + [["Hyperdash"]], + }, + "Fortress Hero's Grave Region": { + "Fortress Grave Path": + [], + }, + "Fortress Arena": { + "Fortress Arena Portal": + [["Fortress Exterior from Overworld", "Beneath the Vault Back", "Eastern Vault Fortress"]], + }, + "Fortress Arena Portal": { + "Fortress Arena": + [], + }, + "Lower Mountain": { + "Lower Mountain Stairs": + [], + }, + "Lower Mountain Stairs": { + "Lower Mountain": + [], + }, + "Monastery Back": { + "Monastery Front": + [["Hyperdash", "NMG"]], + "Monastery Hero's Grave Region": + [], + }, + "Monastery Hero's Grave Region": { + "Monastery Back": + [], + }, + "Monastery Front": { + "Monastery Back": + [], + }, + "Quarry Entry": { + "Quarry Portal": + [["Quarry Connector"]], + "Quarry": + [], + }, + "Quarry Portal": { + "Quarry Entry": + [], + }, + "Quarry Monastery Entry": { + "Quarry": + [], + "Quarry Back": + [["Hyperdash"]], + "Monastery Rope": + [["UR"]], + }, + "Quarry Back": { + "Quarry": + [], + "Quarry Monastery Entry": + [["Hyperdash"]], + }, + "Quarry": { + "Lower Quarry": + [], + "Quarry Entry": + [], + "Quarry Back": + [], + "Quarry Monastery Entry": + [], + "Lower Quarry Zig Door": + [["NMG"]], + }, + "Lower Quarry": { + "Even Lower Quarry": + [], + }, + "Even Lower Quarry": { + "Lower Quarry": + [], + "Lower Quarry Zig Door": + [["Quarry", "Quarry Connector"], ["NMG"]], + }, + "Monastery Rope": { + "Quarry Back": + [], + }, + "Rooted Ziggurat Upper Entry": { + "Rooted Ziggurat Upper Front": + [], + }, + "Rooted Ziggurat Upper Front": { + "Rooted Ziggurat Upper Back": + [], + }, + "Rooted Ziggurat Upper Back": { + "Rooted Ziggurat Upper Front": + [["Hyperdash"]], + }, + "Rooted Ziggurat Middle Top": { + "Rooted Ziggurat Middle Bottom": + [], + }, + "Rooted Ziggurat Lower Front": { + "Rooted Ziggurat Lower Back": + [], + }, + "Rooted Ziggurat Lower Back": { + "Rooted Ziggurat Lower Front": + [["Hyperdash"], ["UR"]], + "Rooted Ziggurat Portal Room Entrance": + [], + }, + "Zig Skip Exit": { + "Rooted Ziggurat Lower Front": + [], + }, + "Rooted Ziggurat Portal Room Entrance": { + "Rooted Ziggurat Lower Back": + [], + }, + "Rooted Ziggurat Portal Room Exit": { + "Rooted Ziggurat Portal": + [], + }, + "Rooted Ziggurat Portal": { + "Rooted Ziggurat Portal Room Exit": + [["Rooted Ziggurat Lower Back"]], + }, + "Swamp Front": { + "Swamp Mid": + [], + }, + "Swamp Mid": { + "Swamp Front": + [], + "Swamp to Cathedral Main Entrance Region": + [["Hyperdash"], ["NMG"]], + "Swamp Ledge under Cathedral Door": + [], + "Back of Swamp": + [["UR"]], + }, + "Swamp Ledge under Cathedral Door": { + "Swamp Mid": + [], + "Swamp to Cathedral Treasure Room": + [], + }, + "Swamp to Cathedral Treasure Room": { + "Swamp Ledge under Cathedral Door": + [], + }, + "Swamp to Cathedral Main Entrance Region": { + "Swamp Mid": + [["NMG"]], + }, + "Back of Swamp": { + "Back of Swamp Laurels Area": + [["Hyperdash"], ["UR"]], + "Swamp Hero's Grave Region": + [], + }, + "Back of Swamp Laurels Area": { + "Back of Swamp": + [["Hyperdash"]], + "Swamp Mid": + [["NMG", "Hyperdash"]], + }, + "Swamp Hero's Grave Region": { + "Back of Swamp": + [], + }, + "Cathedral Gauntlet Checkpoint": { + "Cathedral Gauntlet": + [], + }, + "Cathedral Gauntlet": { + "Cathedral Gauntlet Exit": + [["Hyperdash"]], + }, + "Cathedral Gauntlet Exit": { + "Cathedral Gauntlet": + [["Hyperdash"]], + }, + "Far Shore": { + "Far Shore to Spawn Region": + [["Hyperdash"]], + "Far Shore to East Forest Region": + [["Hyperdash"]], + "Far Shore to Quarry Region": + [["Quarry Connector", "Quarry"]], + "Far Shore to Library Region": + [["Library Lab"]], + "Far Shore to West Garden Region": + [["West Garden"]], + "Far Shore to Fortress Region": + [["Fortress Exterior from Overworld", "Beneath the Vault Back", "Eastern Vault Fortress"]], + }, + "Far Shore to Spawn Region": { + "Far Shore": + [["Hyperdash"]], + }, + "Far Shore to East Forest Region": { + "Far Shore": + [["Hyperdash"]], + }, + "Far Shore to Quarry Region": { + "Far Shore": + [], + }, + "Far Shore to Library Region": { + "Far Shore": + [], + }, + "Far Shore to West Garden Region": { + "Far Shore": + [], + }, + "Far Shore to Fortress Region": { + "Far Shore": + [], + }, } diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 6352d96b..08eb73a3 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -268,7 +268,8 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld Well Ladder"], rule=lambda state: has_ladder("Ladders in Well", state, player, options)) regions["Overworld Well Ladder"].connect( - connecting_region=regions["Overworld"]) + connecting_region=regions["Overworld"], + rule=lambda state: has_ladder("Ladders in Well", state, player, options)) # nmg: can ice grapple through the door regions["Overworld"].connect( @@ -706,17 +707,18 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Fortress Exterior from Overworld"]) regions["Beneath the Vault Ladder Exit"].connect( - connecting_region=regions["Beneath the Vault Front"], - rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options)) - regions["Beneath the Vault Front"].connect( + connecting_region=regions["Beneath the Vault Main"], + rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options) + and has_lantern(state, player, options)) + regions["Beneath the Vault Main"].connect( connecting_region=regions["Beneath the Vault Ladder Exit"], rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options)) - regions["Beneath the Vault Front"].connect( - connecting_region=regions["Beneath the Vault Back"], - rule=lambda state: has_lantern(state, player, options)) + regions["Beneath the Vault Main"].connect( + connecting_region=regions["Beneath the Vault Back"]) regions["Beneath the Vault Back"].connect( - connecting_region=regions["Beneath the Vault Front"]) + connecting_region=regions["Beneath the Vault Main"], + rule=lambda state: has_lantern(state, player, options)) regions["Fortress East Shortcut Upper"].connect( connecting_region=regions["Fortress East Shortcut Lower"]) @@ -870,6 +872,9 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Rooted Ziggurat Portal Room Entrance"].connect( connecting_region=regions["Rooted Ziggurat Lower Back"]) + regions["Zig Skip Exit"].connect( + connecting_region=regions["Rooted Ziggurat Lower Front"]) + regions["Rooted Ziggurat Portal"].connect( connecting_region=regions["Rooted Ziggurat Portal Room Exit"], rule=lambda state: state.has("Activate Ziggurat Fuse", player)) @@ -1453,8 +1458,6 @@ def set_er_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) # Beneath the Vault set_rule(multiworld.get_location("Beneath the Fortress - Bridge", player), lambda state: state.has_group("Melee Weapons", player, 1) or state.has_any({laurels, fire_wand}, player)) - set_rule(multiworld.get_location("Beneath the Fortress - Obscured Behind Waterfall", player), - lambda state: has_lantern(state, player, options)) # Quarry set_rule(multiworld.get_location("Quarry - [Central] Above Ladder Dash Chest", player), diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 323ccf42..3abdfecc 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -1,12 +1,12 @@ from typing import Dict, List, Set, TYPE_CHECKING from BaseClasses import Region, ItemClassification, Item, Location from .locations import location_table -from .er_data import Portal, tunic_er_regions, portal_mapping, \ - dependent_regions_restricted, dependent_regions_nmg, dependent_regions_ur +from .er_data import Portal, tunic_er_regions, portal_mapping, traversal_requirements, DeadEnd from .er_rules import set_er_region_rules from .options import EntranceRando from worlds.generic import PlandoConnection from random import Random +from copy import deepcopy if TYPE_CHECKING: from . import TunicWorld @@ -95,7 +95,8 @@ def place_event_items(world: "TunicWorld", regions: Dict[str, Region]) -> None: def vanilla_portals() -> Dict[Portal, Portal]: portal_pairs: Dict[Portal, Portal] = {} - portal_map = portal_mapping.copy() + # we don't want the zig skip exit for vanilla portals, since it shouldn't be considered for logic here + portal_map = [portal for portal in portal_mapping if portal.name != "Ziggurat Lower Falling Entrance"] while portal_map: portal1 = portal_map[0] @@ -130,9 +131,13 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: dead_ends: List[Portal] = [] two_plus: List[Portal] = [] player_name = world.multiworld.get_player_name(world.player) + portal_map = portal_mapping.copy() logic_rules = world.options.logic_rules.value fixed_shop = world.options.fixed_shop laurels_location = world.options.laurels_location + traversal_reqs = deepcopy(traversal_requirements) + has_laurels = True + waterfall_plando = False # if it's not one of the EntranceRando options, it's a custom seed if world.options.entrance_rando.value not in EntranceRando.options: @@ -140,38 +145,53 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: logic_rules = seed_group["logic_rules"] fixed_shop = seed_group["fixed_shop"] laurels_location = "10_fairies" if seed_group["laurels_at_10_fairies"] is True else False - + + # marking that you don't immediately have laurels + if laurels_location == "10_fairies" and not hasattr(world.multiworld, "re_gen_passthrough"): + has_laurels = False + shop_scenes: Set[str] = set() shop_count = 6 if fixed_shop: - shop_count = 1 + shop_count = 0 shop_scenes.add("Overworld Redux") - - if not logic_rules: - dependent_regions = dependent_regions_restricted - elif logic_rules == 1: - dependent_regions = dependent_regions_nmg else: - dependent_regions = dependent_regions_ur + # if fixed shop is off, remove this portal + for portal in portal_map: + if portal.region == "Zig Skip Exit": + portal_map.remove(portal) + break # create separate lists for dead ends and non-dead ends - if logic_rules: - for portal in portal_mapping: - if tunic_er_regions[portal.region].dead_end == 1: - dead_ends.append(portal) - else: + for portal in portal_map: + dead_end_status = tunic_er_regions[portal.region].dead_end + if dead_end_status == DeadEnd.free: + two_plus.append(portal) + elif dead_end_status == DeadEnd.all_cats: + dead_ends.append(portal) + elif dead_end_status == DeadEnd.restricted: + if logic_rules: two_plus.append(portal) - else: - for portal in portal_mapping: - if tunic_er_regions[portal.region].dead_end: - dead_ends.append(portal) else: - two_plus.append(portal) + dead_ends.append(portal) + # these two get special handling + elif dead_end_status == DeadEnd.special: + if portal.region == "Secret Gathering Place": + if laurels_location == "10_fairies": + two_plus.append(portal) + else: + dead_ends.append(portal) + if portal.region == "Zig Skip Exit": + if fixed_shop: + two_plus.append(portal) + else: + dead_ends.append(portal) connected_regions: Set[str] = set() # make better start region stuff when/if implementing random start start_region = "Overworld" - connected_regions.update(add_dependent_regions(start_region, logic_rules)) + connected_regions.add(start_region) + connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_rules) if world.options.entrance_rando.value in EntranceRando.options: plando_connections = world.multiworld.plando_connections[world.player] @@ -205,11 +225,17 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: non_dead_end_regions.add(region_name) elif region_info.dead_end == 2 and logic_rules: non_dead_end_regions.add(region_name) + elif region_info.dead_end == 3: + if (region_name == "Secret Gathering Place" and laurels_location == "10_fairies") \ + or (region_name == "Zig Skip Exit" and fixed_shop): + non_dead_end_regions.add(region_name) if plando_connections: for connection in plando_connections: p_entrance = connection.entrance p_exit = connection.exit + portal1_dead_end = True + portal2_dead_end = True portal1 = None portal2 = None @@ -218,8 +244,10 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: for portal in two_plus: if p_entrance == portal.name: portal1 = portal + portal1_dead_end = False if p_exit == portal.name: portal2 = portal + portal2_dead_end = False # search dead_ends individually since we can't really remove items from two_plus during the loop if portal1: @@ -233,7 +261,7 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: else: raise Exception(f"{player_name} paired a dead end to a dead end in their " "plando connections.") - + for portal in dead_ends: if p_entrance == portal.name: portal1 = portal @@ -246,7 +274,6 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: if portal2: two_plus.remove(portal2) else: - # check if portal2 is a dead end for portal in dead_ends: if p_exit == portal.name: portal2 = portal @@ -256,6 +283,7 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: portal2 = Portal(name="Shop Portal", region="Shop", destination="Previous Region", tag="_") shop_count -= 1 + # need to maintain an even number of portals total if shop_count < 0: shop_count += 2 for p in portal_mapping: @@ -269,48 +297,36 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: f"plando connections in {player_name}'s YAML.") dead_ends.remove(portal2) + # update the traversal chart to say you can get from portal1's region to portal2's and vice versa + if not portal1_dead_end and not portal2_dead_end: + traversal_reqs.setdefault(portal1.region, dict())[portal2.region] = [] + traversal_reqs.setdefault(portal2.region, dict())[portal1.region] = [] + + if portal1.region == "Zig Skip Exit" or portal2.region == "Zig Skip Exit": + if portal1_dead_end or portal2_dead_end or \ + portal1.region == "Secret Gathering Place" or portal2.region == "Secret Gathering Place": + if world.options.entrance_rando.value not in EntranceRando.options: + raise Exception(f"Tunic ER seed group {world.options.entrance_rando.value} paired a dead " + "end to a dead end in their plando connections.") + else: + raise Exception(f"{player_name} paired a dead end to a dead end in their " + "plando connections.") + + if portal1.region == "Secret Gathering Place" or portal2.region == "Secret Gathering Place": + # need to make sure you didn't pair this to a dead end or zig skip + if portal1_dead_end or portal2_dead_end or \ + portal1.region == "Zig Skip Exit" or portal2.region == "Zig Skip Exit": + if world.options.entrance_rando.value not in EntranceRando.options: + raise Exception(f"Tunic ER seed group {world.options.entrance_rando.value} paired a dead " + "end to a dead end in their plando connections.") + else: + raise Exception(f"{player_name} paired a dead end to a dead end in their " + "plando connections.") + waterfall_plando = True portal_pairs[portal1] = portal2 - # update dependent regions based on the plando'd connections, to ensure the portals connect well, logically - for origins, destinations in dependent_regions.items(): - if portal1.region in origins: - if portal2.region in non_dead_end_regions: - destinations.append(portal2.region) - if portal2.region in origins: - if portal1.region in non_dead_end_regions: - destinations.append(portal1.region) - # if we have plando connections, our connected regions may change somewhat - while True: - test1 = len(connected_regions) - for region in connected_regions.copy(): - connected_regions.update(add_dependent_regions(region, logic_rules)) - test2 = len(connected_regions) - if test1 == test2: - break - - # need to plando fairy cave, or it could end up laurels locked - # fix this later to be random after adding some item logic to dependent regions - if laurels_location == "10_fairies" and not hasattr(world.multiworld, "re_gen_passthrough"): - portal1 = None - portal2 = None - for portal in two_plus: - if portal.scene_destination() == "Overworld Redux, Waterfall_": - portal1 = portal - break - for portal in dead_ends: - if portal.scene_destination() == "Waterfall, Overworld Redux_": - portal2 = portal - break - if not portal1: - raise Exception(f"Failed to do Laurels Location at 10 Fairies option. " - f"Did {player_name} plando connection the Secret Gathering Place Entrance?") - if not portal2: - raise Exception(f"Failed to do Laurels Location at 10 Fairies option. " - f"Did {player_name} plando connection the Secret Gathering Place Exit?") - portal_pairs[portal1] = portal2 - two_plus.remove(portal1) - dead_ends.remove(portal2) + connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_rules) if fixed_shop and not hasattr(world.multiworld, "re_gen_passthrough"): portal1 = None @@ -339,47 +355,54 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: previous_conn_num = 0 fail_count = 0 while len(connected_regions) < len(non_dead_end_regions): - # if the connected regions length stays unchanged for too long, it's stuck in a loop - # should, hopefully, only ever occur if someone plandos connections poorly + # if this is universal tracker, just break immediately and move on if hasattr(world.multiworld, "re_gen_passthrough"): break + # if the connected regions length stays unchanged for too long, it's stuck in a loop + # should, hopefully, only ever occur if someone plandos connections poorly if previous_conn_num == len(connected_regions): fail_count += 1 if fail_count >= 500: - raise Exception(f"Failed to pair regions. Check plando connections for {player_name} for loops.") + raise Exception(f"Failed to pair regions. Check plando connections for {player_name} for errors. " + "Unconnected regions:", non_dead_end_regions - connected_regions) else: fail_count = 0 previous_conn_num = len(connected_regions) - # find a portal in an inaccessible region + # find a portal in a connected region if check_success == 0: for portal in two_plus: if portal.region in connected_regions: - # if there's risk of self-locking, start over - if gate_before_switch(portal, two_plus): - random_object.shuffle(two_plus) - break portal1 = portal two_plus.remove(portal) check_success = 1 break - # then we find a portal in a connected region + # then we find a portal in an inaccessible region if check_success == 1: for portal in two_plus: if portal.region not in connected_regions: - # if there's risk of self-locking, shuffle and try again - if gate_before_switch(portal, two_plus): - random_object.shuffle(two_plus) - break + # if secret gathering place happens to get paired really late, you can end up running out + if not has_laurels and len(two_plus) < 80: + # if you plando'd secret gathering place with laurels at 10 fairies, you're the reason for this + if waterfall_plando: + cr = connected_regions.copy() + cr.add(portal.region) + if "Secret Gathering Place" not in update_reachable_regions(cr, traversal_reqs, has_laurels, logic_rules): + continue + elif portal.region != "Secret Gathering Place": + continue portal2 = portal + connected_regions.add(portal.region) two_plus.remove(portal) check_success = 2 break # once we have both portals, connect them and add the new region(s) to connected_regions if check_success == 2: - connected_regions.update(add_dependent_regions(portal2.region, logic_rules)) + connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic_rules) + if "Secret Gathering Place" in connected_regions: + has_laurels = True portal_pairs[portal1] = portal2 check_success = 0 random_object.shuffle(two_plus) @@ -411,7 +434,6 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: portal1 = two_plus.pop() portal2 = dead_ends.pop() portal_pairs[portal1] = portal2 - # then randomly connect the remaining portals to each other # every region is accessible, so gate_before_switch is not necessary while len(two_plus) > 1: @@ -438,126 +460,42 @@ def create_randomized_entrances(portal_pairs: Dict[Portal, Portal], regions: Dic region2.connect(connecting_region=region1, name=portal2.name) -# loop through the static connections, return regions you can reach from this region -# todo: refactor to take region_name and dependent_regions -def add_dependent_regions(region_name: str, logic_rules: int) -> Set[str]: - region_set = set() - if not logic_rules: - regions_to_add = dependent_regions_restricted - elif logic_rules == 1: - regions_to_add = dependent_regions_nmg - else: - regions_to_add = dependent_regions_ur - for origin_regions, destination_regions in regions_to_add.items(): - if region_name in origin_regions: - # if you matched something in the first set, you get the regions in its paired set - region_set.update(destination_regions) - return region_set - # if you didn't match anything in the first sets, just gives you the region - region_set = {region_name} - return region_set +def update_reachable_regions(connected_regions: Set[str], traversal_reqs: Dict[str, Dict[str, List[List[str]]]], + has_laurels: bool, logic: int) -> Set[str]: + # starting count, so we can run it again if this changes + region_count = len(connected_regions) + for origin, destinations in traversal_reqs.items(): + if origin not in connected_regions: + continue + # check if we can traverse to any of the destinations + for destination, req_lists in destinations.items(): + if destination in connected_regions: + continue + met_traversal_reqs = False + if len(req_lists) == 0: + met_traversal_reqs = True + # loop through each set of possible requirements, with a fancy for else loop + for reqs in req_lists: + for req in reqs: + if req == "Hyperdash": + if not has_laurels: + break + elif req == "NMG": + if not logic: + break + elif req == "UR": + if logic < 2: + break + elif req not in connected_regions: + break + else: + met_traversal_reqs = True + break + if met_traversal_reqs: + connected_regions.add(destination) + # if the length of connected_regions changed, we got new regions, so we want to check those new origins + if region_count != len(connected_regions): + connected_regions = update_reachable_regions(connected_regions, traversal_reqs, has_laurels, logic) -# we're checking if an event-locked portal is being placed before the regions where its key(s) is/are -# doing this ensures the keys will not be locked behind the event-locked portal -def gate_before_switch(check_portal: Portal, two_plus: List[Portal]) -> bool: - # the western belltower cannot be locked since you can access it with laurels - # so we only need to make sure the forest belltower isn't locked - if check_portal.scene_destination() == "Overworld Redux, Temple_main": - i = 0 - for portal in two_plus: - if portal.region == "Forest Belltower Upper": - i += 1 - break - if i == 1: - return True - - # fortress big gold door needs 2 scenes and one of the two upper portals of the courtyard - elif check_portal.scene_destination() == "Fortress Main, Fortress Arena_": - i = j = k = 0 - for portal in two_plus: - if portal.region == "Fortress Courtyard Upper": - i += 1 - if portal.scene() == "Fortress Basement": - j += 1 - if portal.region == "Eastern Vault Fortress": - k += 1 - if i == 2 or j == 2 or k == 5: - return True - - # fortress teleporter needs only the left fuses - elif check_portal.scene_destination() in {"Fortress Arena, Transit_teleporter_spidertank", - "Transit, Fortress Arena_teleporter_spidertank"}: - i = j = k = 0 - for portal in two_plus: - if portal.scene() == "Fortress Courtyard": - i += 1 - if portal.scene() == "Fortress Basement": - j += 1 - if portal.region == "Eastern Vault Fortress": - k += 1 - if i == 8 or j == 2 or k == 5: - return True - - # Cathedral door needs Overworld and the front of Swamp - # Overworld is currently guaranteed, so no need to check it - elif check_portal.scene_destination() == "Swamp Redux 2, Cathedral Redux_main": - i = 0 - for portal in two_plus: - if portal.region in {"Swamp Front", "Swamp to Cathedral Treasure Room", - "Swamp to Cathedral Main Entrance Region"}: - i += 1 - if i == 4: - return True - - # Zig portal room exit needs Zig 3 to be accessible to hit the fuse - elif check_portal.scene_destination() == "ziggurat2020_FTRoom, ziggurat2020_3_": - i = 0 - for portal in two_plus: - if portal.scene() == "ziggurat2020_3": - i += 1 - if i == 2: - return True - - # Quarry teleporter needs you to hit the Darkwoods fuse - # Since it's physically in Quarry, we don't need to check for it - elif check_portal.scene_destination() in {"Quarry Redux, Transit_teleporter_quarry teleporter", - "Quarry Redux, ziggurat2020_0_"}: - i = 0 - for portal in two_plus: - if portal.scene() == "Darkwoods Tunnel": - i += 1 - if i == 2: - return True - - # Same as above, but Quarry isn't guaranteed here - elif check_portal.scene_destination() == "Transit, Quarry Redux_teleporter_quarry teleporter": - i = j = 0 - for portal in two_plus: - if portal.scene() == "Darkwoods Tunnel": - i += 1 - if portal.scene() == "Quarry Redux": - j += 1 - if i == 2 or j == 7: - return True - - # Need Library fuse to use this teleporter - elif check_portal.scene_destination() == "Transit, Library Lab_teleporter_library teleporter": - i = 0 - for portal in two_plus: - if portal.scene() == "Library Lab": - i += 1 - if i == 3: - return True - - # Need West Garden fuse to use this teleporter - elif check_portal.scene_destination() == "Transit, Archipelagos Redux_teleporter_archipelagos_teleporter": - i = 0 - for portal in two_plus: - if portal.scene() == "Archipelagos Redux": - i += 1 - if i == 6: - return True - - # false means you're good to place the portal - return False + return connected_regions diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 6efdeaa3..f470ea54 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -237,6 +237,8 @@ extra_groups: Dict[str, Set[str]] = { "Ladder to Atoll": {"Ladder to Ruined Atoll"}, # fuzzy matching made it hint Ladders in Well, now it won't "Ladders to Bell": {"Ladders to West Bell"}, "Ladders to Well": {"Ladders in Well"}, # fuzzy matching decided ladders in well was ladders to west bell + "Ladders in Atoll": {"Ladders in South Atoll"}, + "Ladders in Ruined Atoll": {"Ladders in South Atoll"}, } item_name_groups.update(extra_groups) diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index fdf66216..2d87140f 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -86,7 +86,7 @@ location_table: Dict[str, TunicLocationData] = { "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"), - "Beneath the Fortress - Obscured Behind Waterfall": TunicLocationData("Beneath the Vault", "Beneath the Vault Front"), + "Beneath the Fortress - Obscured Behind Waterfall": TunicLocationData("Beneath the Vault", "Beneath the Vault Main"), "Beneath the Fortress - Back Room Chest": TunicLocationData("Beneath the Vault", "Beneath the Vault Back"), "Beneath the Fortress - Cell Chest 2": TunicLocationData("Beneath the Vault", "Beneath the Vault Back"), "Frog's Domain - Near Vault": TunicLocationData("Frog's Domain", "Frog's Domain"), diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index 9af0a040..605bb065 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -118,7 +118,8 @@ class EntranceRando(TextChoice): class FixedShop(Toggle): - """Forces the Windmill entrance to lead to a shop, and places only one other shop in the pool. + """Forces the Windmill entrance to lead to a shop, and removes the remaining shops from the pool. + Adds another entrance in Rooted Ziggurat Lower to keep an even number of entrances. Has no effect if Entrance Rando is not enabled.""" internal_name = "fixed_shop" display_name = "Fewer Shops in Entrance Rando" @@ -126,8 +127,7 @@ class FixedShop(Toggle): class LaurelsLocation(Choice): """Force the Hero's Laurels to be placed at a location in your world. - For if you want to avoid or specify early or late Laurels. - If you use the 10 Fairies option in Entrance Rando, Secret Gathering Place will be at its vanilla entrance.""" + For if you want to avoid or specify early or late Laurels.""" internal_name = "laurels_location" display_name = "Laurels Location" option_anywhere = 0 @@ -147,6 +147,7 @@ class ShuffleLadders(Toggle): @dataclass class TunicOptions(PerGameCommonOptions): + start_inventory_from_pool: StartInventoryPool sword_progression: SwordProgression start_with_sword: StartWithSword keys_behind_bosses: KeysBehindBosses @@ -162,4 +163,3 @@ class TunicOptions(PerGameCommonOptions): lanternless: Lanternless maskless: Maskless laurels_location: LaurelsLocation - start_inventory_from_pool: StartInventoryPool