From 47649b2a532b1a2fc273a2a65217104902e75398 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Wed, 28 Feb 2024 18:15:07 -0500 Subject: [PATCH 01/82] New branch to fix git being git --- worlds/tunic/__init__.py | 62 ++++-- worlds/tunic/items.py | 16 ++ worlds/tunic/ladder_rules.py | 376 +++++++++++++++++++++++++++++++++++ worlds/tunic/locations.py | 123 ++++++------ worlds/tunic/options.py | 7 + worlds/tunic/regions.py | 38 +++- worlds/tunic/rules.py | 17 +- 7 files changed, 547 insertions(+), 92 deletions(-) create mode 100644 worlds/tunic/ladder_rules.py diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index b10ccd43af59..e08cd21cb46f 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -5,7 +5,8 @@ from .locations import location_table, location_name_groups, location_name_to_id, hexagon_locations from .rules import set_location_rules, set_region_rules, randomize_ability_unlocks, gold_hexagon from .er_rules import set_er_location_rules -from .regions import tunic_regions +from .ladder_rules import set_ladder_region_rules, set_ladder_location_rules +from .regions import tunic_regions, tunic_ladder_regions from .er_scripts import create_er_regions from .options import TunicOptions from worlds.AutoWorld import WebWorld, World @@ -72,6 +73,7 @@ def generate_early(self) -> None: self.options.maskless.value = passthrough["maskless"] self.options.hexagon_quest.value = passthrough["hexagon_quest"] self.options.entrance_rando.value = passthrough["entrance_rando"] + self.options.ladder_rando.value = passthrough["ladder_rando"] def create_item(self, name: str) -> TunicItem: item_data = item_table[name] @@ -86,7 +88,7 @@ def create_items(self) -> None: self.slot_data_items = [] items_to_create: Dict[str, int] = {item: data.quantity_in_item_pool for item, data in item_table.items()} - + for money_fool in fool_tiers[self.options.fool_traps]: items_to_create["Fool Trap"] += items_to_create[money_fool] items_to_create[money_fool] = 0 @@ -119,27 +121,41 @@ def create_items(self) -> None: items_to_create[rgb_hexagon] = 0 items_to_create[gold_hexagon] -= 3 + # Filler items that are still in the item pool to swap out + available_filler: List[str] = [filler for filler in items_to_create if items_to_create[filler] > 0 and + item_table[filler].classification == ItemClassification.filler] + + def remove_filler(amount: int): + # Remove filler to make room for other items + for _ in range(0, amount): + fill = self.random.choice(available_filler) + items_to_create[fill] -= 1 + if items_to_create[fill] == 0: + available_filler.remove(fill) + + if self.options.ladder_rando: + ladder_count = 0 + for item_name, item_data in item_table.items(): + if item_data.item_group == "ladders": + items_to_create[item_name] = 1 + ladder_count += 1 + remove_filler(ladder_count) + if hexagon_quest: # Calculate number of hexagons in item pool hexagon_goal = self.options.hexagon_goal extra_hexagons = self.options.extra_hexagon_percentage items_to_create[gold_hexagon] += int((Decimal(100 + extra_hexagons) / 100 * hexagon_goal).to_integral_value(rounding=ROUND_HALF_UP)) - + # Replace pages and normal hexagons with filler for replaced_item in list(filter(lambda item: "Pages" in item or item in hexagon_locations, items_to_create)): - items_to_create[self.get_filler_item_name()] += items_to_create[replaced_item] + filler_name = self.get_filler_item_name() + items_to_create[filler_name] += items_to_create[replaced_item] + if items_to_create[filler_name] >= 1 and filler_name not in available_filler: + available_filler.append(filler_name) items_to_create[replaced_item] = 0 - # Filler items that are still in the item pool to swap out - available_filler: List[str] = [filler for filler in items_to_create if items_to_create[filler] > 0 and - item_table[filler].classification == ItemClassification.filler] - - # Remove filler to make room for extra hexagons - for i in range(0, items_to_create[gold_hexagon]): - fill = self.random.choice(available_filler) - items_to_create[fill] -= 1 - if items_to_create[fill] == 0: - available_filler.remove(fill) + remove_filler(items_to_create[gold_hexagon]) if self.options.maskless: mask_item = TunicItem("Scavenger Mask", ItemClassification.useful, self.item_name_to_id["Scavenger Mask"], self.player) @@ -181,16 +197,24 @@ def create_regions(self) -> None: self.er_portal_hints = portal_hints else: - for region_name in tunic_regions: + if self.options.ladder_rando: + region_list = tunic_ladder_regions + else: + region_list = tunic_regions + + for region_name in region_list: region = Region(region_name, self.player, self.multiworld) self.multiworld.regions.append(region) - for region_name, exits in tunic_regions.items(): + for region_name, exits in region_list.items(): region = self.multiworld.get_region(region_name, self.player) region.add_exits(exits) for location_name, location_id in self.location_name_to_id.items(): - region = self.multiworld.get_region(location_table[location_name].region, self.player) + if self.options.ladder_rando: + region = self.multiworld.get_region(location_table[location_name].region, self.player) + else: + region = self.multiworld.get_region(location_table[location_name].region, self.player) location = TunicLocation(self.player, location_name, location_id, region) region.locations.append(location) @@ -203,6 +227,9 @@ def create_regions(self) -> None: def set_rules(self) -> None: if self.options.entrance_rando: set_er_location_rules(self, self.ability_unlocks) + elif self.options.ladder_rando: + set_ladder_region_rules(self, self.ability_unlocks) + set_ladder_location_rules(self, self.ability_unlocks) else: set_region_rules(self, self.ability_unlocks) set_location_rules(self, self.ability_unlocks) @@ -227,6 +254,7 @@ def fill_slot_data(self) -> Dict[str, Any]: "lanternless": self.options.lanternless.value, "maskless": self.options.maskless.value, "entrance_rando": self.options.entrance_rando.value, + "ladder_rando": self.options.ladder_rando.value, "Hexagon Quest Prayer": self.ability_unlocks["Pages 24-25 (Prayer)"], "Hexagon Quest Holy Cross": self.ability_unlocks["Pages 42-43 (Holy Cross)"], "Hexagon Quest Icebolt": self.ability_unlocks["Pages 52-53 (Icebolt)"], diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 547a0ffb816f..ffc45d0a83cd 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -143,6 +143,22 @@ class TunicItemData(NamedTuple): "Pages 50-51": TunicItemData(ItemClassification.useful, 1, 127, "pages"), "Pages 52-53 (Icebolt)": TunicItemData(ItemClassification.progression, 1, 128, "pages"), "Pages 54-55": TunicItemData(ItemClassification.useful, 1, 129, "pages"), + + "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), + "Ladders next to Dark Tomb": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), + "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), + "Ladders next to Ruined Passage Exit": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), + "Overworld Shortcut Ladders": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), + "Ladder by Temple Rafters Exit": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), + "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), + "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), + "Ladders next to West Belltower": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), + "Ladder to Well": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), + "Ladder Drop to East Forest": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), + "Ladders next to Patrol Cave": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), + "Dark Tomb Ladder": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), + "Well Back Ladder": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), + "Swamp Ladder": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), } fool_tiers: List[List[str]] = [ diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py new file mode 100644 index 000000000000..6cd64c7e6c32 --- /dev/null +++ b/worlds/tunic/ladder_rules.py @@ -0,0 +1,376 @@ +from typing import Dict, TYPE_CHECKING +from BaseClasses import CollectionState +from worlds.generic.Rules import set_rule, forbid_item +from .rules import has_ability, has_sword, has_stick, has_ice_grapple_logic, has_lantern, has_mask, can_ladder_storage +from .options import TunicOptions +if TYPE_CHECKING: + from . import TunicWorld + +laurels = "Hero's Laurels" +grapple = "Magic Orb" +ice_dagger = "Magic Dagger" +fire_wand = "Magic Wand" +lantern = "Lantern" +fairies = "Fairy" +coins = "Golden Coin" +prayer = "Pages 24-25 (Prayer)" +holy_cross = "Pages 42-43 (Holy Cross)" +icebolt = "Pages 52-53 (Icebolt)" +key = "Key" +house_key = "Old House Key" +vault_key = "Fortress Vault Key" +mask = "Scavenger Mask" +red_hexagon = "Red Questagon" +green_hexagon = "Green Questagon" +blue_hexagon = "Blue Questagon" +gold_hexagon = "Gold Questagon" + + +def can_reach_east_overworld(state: CollectionState, player: int, options: TunicOptions, ability_unlocks: Dict[str, int]) -> bool: + return ( + state.has_any({"Ladders next to Ruined Passage Exit", "Overworld Shortcut Ladders"}, player) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks) + or (can_reach_upper_overworld(state, player, options, ability_unlocks) + and state.has("Ladders next to Patrol Cave", player)) + or can_ladder_storage(state, player, options) + or (state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) + ) + + +def can_reach_upper_overworld(state: CollectionState, player: int, options: TunicOptions, ability_unlocks: Dict[str, int]) -> bool: + return ( + (state.has("Ladders next to Dark Tomb", player) and state.has_any({laurels, grapple}, player)) + or ((state.has_any({"Ladders next to Ruined Passage Exit", "Overworld Shortcut Ladders", grapple}, player) + or can_ladder_storage(state, player, options)) + and (state.has("Ladders next to Patrol Cave", player) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks))) + ) + + +def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> None: + multiworld = world.multiworld + player = world.player + options = world.options + + multiworld.get_entrance("Overworld -> Overworld Holy Cross", player).access_rule = \ + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) + multiworld.get_entrance("Overworld -> Sealed Temple", player).access_rule = \ + lambda state: ((state.has("Ladder Drop to East Forest", player) and + can_reach_east_overworld(state, player, options, ability_unlocks)) and + (state.has("Ladders next to West Belltower", player) and + ((state.has(laurels, player) and (has_sword(state, player) or state.has(fire_wand, player))) or + (state.has_all({lantern, "Dark Tomb Ladder"}, player) and has_sword(state, player)))) + or (can_reach_upper_overworld(state, player, options, ability_unlocks) + and state.has_all({laurels, "Ladder by Temple Rafters Exit"}, player)) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks) + or can_ladder_storage(state, player, options) and state.has(laurels, player)) + multiworld.get_entrance("Overworld -> East Overworld", player).access_rule = \ + lambda state: can_reach_east_overworld(state, player, options, ability_unlocks) + multiworld.get_entrance("Overworld -> Upper Overworld", player).access_rule = \ + lambda state: can_reach_upper_overworld(state, player, options, ability_unlocks) + multiworld.get_entrance("Overworld -> East Forest", player).access_rule = \ + lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks) + multiworld.get_entrance("East Overworld -> East Forest", player).access_rule = \ + lambda state: state.has("Ladder Drop to East Forest", player) + multiworld.get_entrance("Overworld -> Swamp", player).access_rule = \ + lambda state: state.has("Ladder to Swamp", player) + multiworld.get_entrance("Swamp -> Swamp Middle", player).access_rule = \ + lambda state: (state.has("Swamp Ladder", player) or state.has(laurels, player)) \ + or (can_ladder_storage(state, player, options) + and has_ability(state, player, holy_cross, options, ability_unlocks)) + multiworld.get_entrance("Swamp Middle -> Cathedral", player).access_rule = \ + lambda state: (has_ability(state, player, prayer, options, ability_unlocks) + and (state.has(laurels, player) + or (can_ladder_storage(state, player, options) and state.has(fire_wand, player))) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) + multiworld.get_entrance("Overworld -> Back of Swamp", player).access_rule = \ + lambda state: state.has(laurels, player) or can_ladder_storage(state, player, options) + # before the ladder, just the one chest in the room where you open up the grave to the ladder + multiworld.get_entrance("Overworld -> Dark Tomb Front", player).access_rule = \ + lambda state: has_lantern(state, player, options) + multiworld.get_entrance("Dark Tomb Front -> Dark Tomb", player).access_rule = \ + lambda state: state.has("Dark Tomb Ladder", player) + # dark tomb to west garden has no rule intentionally + multiworld.get_entrance("Overworld -> West Garden", player).access_rule = \ + lambda state: (state.has(laurels, player) and state.has("Ladders next to West Belltower", player)) \ + or can_ladder_storage(state, player, options) + multiworld.get_entrance("Overworld -> Beneath the Well", player).access_rule = \ + lambda state: state.has("Ladder to Well", player) + # todo: make sure this ice grapple actually works with enemy rando off + multiworld.get_entrance("Beneath the Well -> Beneath the Well Back", player).access_rule = \ + lambda state: state.has("Well Back Ladder", player) \ + or has_ice_grapple_logic(True, state, player, options, ability_unlocks) + # dash to the fuse and have the rear ladder, or dash through the well boss gate in nmg + multiworld.get_entrance("Overworld -> Beneath the Well Back", player).access_rule = \ + lambda state: state.has(laurels, player) and (state.has("Well Back Ladder", player) + or options.logic_rules) + multiworld.get_entrance("Beneath the Well Back -> Beneath the Well", player).access_rule = \ + lambda state: state.has("Well Back Ladder", player) + multiworld.get_entrance("East Overworld -> Eastern Vault Fortress", player).access_rule = \ + lambda state: state.has(laurels, player) \ + or has_ice_grapple_logic(True, state, player, options, ability_unlocks) \ + or can_ladder_storage(state, player, options) + multiworld.get_entrance("East Overworld -> Beneath the Vault", player).access_rule = \ + lambda state: has_lantern(state, player, options) \ + and (can_ladder_storage(state, player, options) + or has_ability(state, player, prayer, options, ability_unlocks) + or state.has(laurels, player)) + multiworld.get_entrance("Overworld -> Ruined Atoll", player).access_rule = \ + lambda state: state.has_any({"Ladder to Ruined Atoll", laurels, grapple}, player) \ + or has_ability(state, player, prayer, options, ability_unlocks) + multiworld.get_entrance("Ruined Atoll -> Library", player).access_rule = \ + lambda state: state.has_any({grapple, laurels}, player) and \ + has_ability(state, player, prayer, options, ability_unlocks) + # have combat items, and the ladder to quarry, and the quarry ladder, or ls to skip those last two + multiworld.get_entrance("Overworld -> Quarry", player).access_rule = \ + lambda state: (has_sword(state, player) or state.has(fire_wand, player)) \ + and ((state.has_any({grapple, laurels}, player) and state.has("Ladder to Quarry", player)) + or can_ladder_storage(state, player, options)) + multiworld.get_entrance("Quarry Back -> Quarry", player).access_rule = \ + lambda state: has_sword(state, player) or state.has(fire_wand, player) + multiworld.get_entrance("Quarry -> Lower Quarry", player).access_rule = \ + lambda state: has_mask(state, player, options) + multiworld.get_entrance("Lower Quarry -> Rooted Ziggurat", player).access_rule = \ + lambda state: state.has(grapple, player) and has_ability(state, player, prayer, options, ability_unlocks) + multiworld.get_entrance("Overworld -> Spirit Arena", player).access_rule = \ + lambda state: (state.has(gold_hexagon, player, options.hexagon_goal.value) if options.hexagon_quest.value + else state.has_all({red_hexagon, green_hexagon, blue_hexagon}, player)) and \ + has_ability(state, player, prayer, options, ability_unlocks) and has_sword(state, player) + + +def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> None: + multiworld = world.multiworld + player = world.player + options = world.options + + forbid_item(multiworld.get_location("Secret Gathering Place - 20 Fairy Reward", player), fairies, player) + + # Ability Shuffle Exclusive Rules + set_rule(multiworld.get_location("Far Shore - Page Pickup", player), + lambda state: has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Fortress Courtyard - Chest Near Cave", player), + lambda state: can_ladder_storage(state, player, options) + or has_ability(state, player, prayer, options, ability_unlocks) + or state.has(laurels, player)) + set_rule(multiworld.get_location("Fortress Courtyard - Page Near Cave", player), + lambda state: can_ladder_storage(state, player, options) + or has_ability(state, player, prayer, options, ability_unlocks) + or state.has(laurels, player)) + set_rule(multiworld.get_location("East Forest - Dancing Fox Spirit Holy Cross", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Forest Grave Path - Holy Cross Code by Grave", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("East Forest - Golden Obelisk Holy Cross", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Beneath the Well - [Powered Secret Room] Chest", player), + lambda state: has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("West Garden - [North] Behind Holy Cross Door", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Library Hall - Holy Cross Chest", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Eastern Vault Fortress - [West Wing] Candles Holy Cross", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("West Garden - [Central Highlands] Holy Cross (Blue Lines)", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Quarry - [Back Entrance] Bushes Holy Cross", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Cathedral - Secret Legend Trophy Chest", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Northwest] Golden Obelisk Page", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Northeast] Flowers Holy Cross", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Patrol Cave - Holy Cross Chest", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) + and (can_reach_east_overworld(state, player, options, ability_unlocks) + or ((can_reach_upper_overworld(state, player, options, ability_unlocks) or state.has(grapple, player)) + and state.has("Ladders next to Patrol Cave", player)))) + set_rule(multiworld.get_location("Sealed Temple - Holy Cross Chest", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Ruined Passage - Holy Cross Chest", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) + and (state.has("Ladders next to Ruined Passage Exit", player) + or state.has(key, player, 2) + or (state.has(laurels, player) and options.logic_rules) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks) + or can_ladder_storage(state, player, options))) + set_rule(multiworld.get_location("Caustic Light Cave - Holy Cross Chest", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Top of the Mountain - Page At The Peak", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + + # Overworld + set_rule(multiworld.get_location("Overworld - [Southwest] Fountain Page", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Overworld - [Southwest] Grapple Chest Over Walkway", player), + lambda state: state.has_any({grapple, laurels}, player)) + set_rule(multiworld.get_location("Overworld - [Southwest] West Beach Guarded By Turret 2", player), + lambda state: state.has_any({grapple, laurels}, player)) + set_rule(multiworld.get_location("Far Shore - Secret Chest", player), + lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Southeast] Page on Pillar by Swamp", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Old House - Normal Chest", player), + lambda state: state.has(house_key, player) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks) + or (state.has(laurels, player) and options.logic_rules)) + set_rule(multiworld.get_location("Old House - Holy Cross Chest", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) and + (state.has(house_key, player) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks) + or (state.has(laurels, player) and options.logic_rules))) + set_rule(multiworld.get_location("Old House - Shield Pickup", player), + lambda state: state.has(house_key, player) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks) + or (state.has(laurels, player) and options.logic_rules)) + set_rule(multiworld.get_location("Overworld - [Northwest] Page on Pillar by Dark Tomb", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Overworld - [Southwest] From West Garden", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Overworld - [West] Chest After Bell", player), + lambda state: state.has(laurels, player) + or (has_lantern(state, player, options) and has_sword(state, player) + and state.has_all({"Ladders next to West Belltower", "Dark Tomb Ladder"}, player)) + or can_ladder_storage(state, player, options)) + set_rule(multiworld.get_location("Overworld - [Northwest] Chest Beneath Quarry Gate", player), + lambda state: state.has_any({grapple, laurels}, player) or options.logic_rules) + set_rule(multiworld.get_location("Overworld - [East] Grapple Chest", player), + lambda state: state.has(grapple, player)) + set_rule(multiworld.get_location("Special Shop - Secret Page Pickup", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Ruined Passage - Page Pickup", player), + lambda state: state.has("Ladders next to Ruined Passage Exit", player) + or state.has(key, player, 2) + or (state.has(laurels, player) and options.logic_rules) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks) + or can_ladder_storage(state, player, options)) + set_rule(multiworld.get_location("Overworld - [East] Between Ladders Near Ruined Passage", player), + lambda state: state.has("Ladders next to Ruined Passage Exit", player) + or state.has(key, player, 2) + or (state.has(laurels, player) and options.logic_rules) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks) + or can_ladder_storage(state, player, options)) + set_rule(multiworld.get_location("Overworld - [East] Chest In Trees", player), + lambda state: state.has_any({laurels, "Ladders next to Ruined Passage Exit"}, player)) + set_rule(multiworld.get_location("Hourglass Cave - Holy Cross Chest", player), + lambda state: state.has("Hourglass Cave Ladders", player)) + set_rule(multiworld.get_location("Overworld - [Northwest] Chest Near Golden Obelisk", player), + lambda state: state.has("Ladders next to Dark Tomb", player) + or (can_reach_upper_overworld(state, player, options, ability_unlocks) + and state.has_any({laurels, grapple}, player))) + set_rule(multiworld.get_location("Patrol Cave - Normal Chest", player), + lambda state: can_reach_east_overworld(state, player, options, ability_unlocks) + or ((can_reach_upper_overworld(state, player, options, ability_unlocks) or state.has(grapple, player)) + and state.has("Ladders next to Patrol Cave", player))) + + set_rule(multiworld.get_location("Secret Gathering Place - 10 Fairy Reward", player), + lambda state: state.has(fairies, player, 10)) + set_rule(multiworld.get_location("Secret Gathering Place - 20 Fairy Reward", player), + lambda state: state.has(fairies, player, 20)) + set_rule(multiworld.get_location("Coins in the Well - 3 Coins", player), + lambda state: state.has(coins, player, 3)) + set_rule(multiworld.get_location("Coins in the Well - 6 Coins", player), + lambda state: state.has(coins, player, 6)) + set_rule(multiworld.get_location("Coins in the Well - 10 Coins", player), + lambda state: state.has(coins, player, 10)) + set_rule(multiworld.get_location("Coins in the Well - 15 Coins", player), + lambda state: state.has(coins, player, 15)) + + # East Forest + set_rule(multiworld.get_location("East Forest - Lower Grapple Chest", player), + lambda state: state.has(grapple, player)) + set_rule(multiworld.get_location("East Forest - Lower Dash Chest", player), + lambda state: state.has_all({grapple, laurels}, player)) + set_rule(multiworld.get_location("East Forest - Ice Rod Grapple Chest", player), + lambda state: state.has_all({grapple, ice_dagger, fire_wand}, player) + and has_ability(state, player, icebolt, options, ability_unlocks)) + + # West Garden + set_rule(multiworld.get_location("West Garden - [North] Across From Page Pickup", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("West Garden - [West] In Flooded Walkway", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("West Garden - [West Lowlands] Tree Holy Cross Chest", player), + lambda state: state.has(laurels, player) + and has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("West Garden - [East Lowlands] Page Behind Ice Dagger House", player), + lambda state: (state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + set_rule(multiworld.get_location("West Garden - [Central Lowlands] Below Left Walkway", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("West Garden - [Central Highlands] After Garden Knight", player), + lambda state: has_sword(state, player) or state.has(laurels, player) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks) + or can_ladder_storage(state, player, options)) + + # Ruined Atoll + set_rule(multiworld.get_location("Ruined Atoll - [West] Near Kevin Block", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Ruined Atoll - [East] Locked Room Lower Chest", player), + lambda state: state.has_any({laurels, key}, player)) + set_rule(multiworld.get_location("Ruined Atoll - [East] Locked Room Upper Chest", player), + lambda state: state.has_any({laurels, key}, player)) + set_rule(multiworld.get_location("Librarian - Hexagon Green", player), + lambda state: has_sword(state, player) or options.logic_rules) + + # Frog's Domain + set_rule(multiworld.get_location("Frog's Domain - Side Room Grapple Secret", player), + lambda state: state.has_any({grapple, laurels}, player)) + set_rule(multiworld.get_location("Frog's Domain - Grapple Above Hot Tub", player), + lambda state: state.has_any({grapple, laurels}, player)) + set_rule(multiworld.get_location("Frog's Domain - Escape Chest", player), + lambda state: state.has_any({grapple, laurels}, player)) + + # Eastern Vault Fortress + set_rule(multiworld.get_location("Fortress Leaf Piles - Secret Chest", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Fortress Arena - Siege Engine/Vault Key Pickup", player), + lambda state: has_sword(state, player) and + (has_ability(state, player, prayer, options, ability_unlocks) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks))) + set_rule(multiworld.get_location("Fortress Arena - Hexagon Red", player), + lambda state: state.has(vault_key, player) and + (has_ability(state, player, prayer, options, ability_unlocks) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks))) + + # Beneath the Vault + set_rule(multiworld.get_location("Beneath the Fortress - Bridge", player), + lambda state: has_stick(state, player) or state.has_any({laurels, fire_wand}, player)) + set_rule(multiworld.get_location("Beneath the Fortress - Obscured Behind Waterfall", player), + lambda state: has_stick(state, player) and has_lantern(state, player, options)) + + # Quarry + set_rule(multiworld.get_location("Quarry - [Central] Above Ladder Dash Chest", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Quarry - [West] Upper Area Bombable Wall", player), + lambda state: has_mask(state, player, options)) + set_rule(multiworld.get_location("Rooted Ziggurat Lower - Hexagon Blue", player), + lambda state: has_sword(state, player)) + + # Swamp + set_rule(multiworld.get_location("Cathedral Gauntlet - Gauntlet Reward", player), + lambda state: state.has(laurels, player) and state.has(fire_wand, player) and has_sword(state, player)) + set_rule(multiworld.get_location("Swamp - [Entrance] Above Entryway", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Swamp - [South Graveyard] Upper Walkway Dash Chest", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Swamp - [Outside Cathedral] Obscured Behind Memorial", player), + lambda state: state.has(laurels, player)) + set_rule(multiworld.get_location("Swamp - [South Graveyard] 4 Orange Skulls", player), + lambda state: has_sword(state, player)) + set_rule(multiworld.get_location("Swamp - [South Graveyard] Guarded By Tentacles", player), + lambda state: has_sword(state, player)) + + # Hero's Grave + set_rule(multiworld.get_location("Hero's Grave - Tooth Relic", player), + lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Hero's Grave - Mushroom Relic", player), + lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Hero's Grave - Ash Relic", player), + lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Hero's Grave - Flowers Relic", player), + lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Hero's Grave - Effigy Relic", player), + lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Hero's Grave - Feathers Relic", player), + lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index 1501fb7da24d..1c34a4808f96 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -1,10 +1,11 @@ -from typing import Dict, NamedTuple, Set +from typing import Dict, NamedTuple, Set, Optional from itertools import groupby class TunicLocationData(NamedTuple): region: str er_region: str # entrance rando region + ladder_region: Optional[str] = None location_group: str = "region" @@ -25,7 +26,7 @@ class TunicLocationData(NamedTuple): "Beneath the Well - [Side Room] Chest By Pots": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Side Room] Chest By Phrends": TunicLocationData("Beneath the Well", "Beneath the Well Back"), "Beneath the Well - [Second Room] Page": TunicLocationData("Beneath the Well", "Beneath the Well Main"), - "Dark Tomb Checkpoint - [Passage To Dark Tomb] Page Pickup": TunicLocationData("Beneath the Well", "Dark Tomb Checkpoint"), + "Dark Tomb Checkpoint - [Passage To Dark Tomb] Page Pickup": TunicLocationData("Overworld", "Dark Tomb Checkpoint"), "Cathedral - [1F] Guarded By Lasers": TunicLocationData("Cathedral", "Cathedral"), "Cathedral - [1F] Near Spikes": TunicLocationData("Cathedral", "Cathedral"), "Cathedral - [2F] Bird Room": TunicLocationData("Cathedral", "Cathedral"), @@ -39,14 +40,14 @@ class TunicLocationData(NamedTuple): "Dark Tomb - 2nd Laser Room": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - 1st Laser Room": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - Spike Maze Upper Walkway": TunicLocationData("Dark Tomb", "Dark Tomb Main"), - "Dark Tomb - Skulls Chest": TunicLocationData("Dark Tomb", "Dark Tomb Main"), + "Dark Tomb - Skulls Chest": TunicLocationData("Dark Tomb", "Dark Tomb Main", ladder_region="Dark Tomb Front"), "Dark Tomb - Spike Maze Near Stairs": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - 1st Laser Room Obscured": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Guardhouse 2 - Upper Floor": TunicLocationData("East Forest", "Guard House 2"), "Guardhouse 2 - Bottom Floor Secret": TunicLocationData("East Forest", "Guard House 2"), "Guardhouse 1 - Upper Floor Obscured": TunicLocationData("East Forest", "Guard House 1 East"), "Guardhouse 1 - Upper Floor": TunicLocationData("East Forest", "Guard House 1 East"), - "East Forest - Dancing Fox Spirit Holy Cross": TunicLocationData("East Forest", "East Forest Dance Fox Spot", "holy cross"), + "East Forest - Dancing Fox Spirit Holy Cross": TunicLocationData("East Forest", "East Forest Dance Fox Spot", location_group="holy cross"), "East Forest - Golden Obelisk Holy Cross": TunicLocationData("East Forest", "East Forest", "holy cross"), "East Forest - Ice Rod Grapple Chest": TunicLocationData("East Forest", "East Forest"), "East Forest - Above Save Point": TunicLocationData("East Forest", "East Forest"), @@ -65,7 +66,7 @@ class TunicLocationData(NamedTuple): "Forest Belltower - Obscured Near Bell Top Floor": TunicLocationData("East Forest", "Forest Belltower Upper"), "Forest Belltower - Obscured Beneath Bell Bottom Floor": TunicLocationData("East Forest", "Forest Belltower Main"), "Forest Belltower - Page Pickup": TunicLocationData("East Forest", "Forest Belltower Main"), - "Forest Grave Path - Holy Cross Code by Grave": TunicLocationData("East Forest", "Forest Grave Path by Grave", "holy cross"), + "Forest Grave Path - Holy Cross Code by Grave": TunicLocationData("East Forest", "Forest Grave Path by Grave", location_group="holy cross"), "Forest Grave Path - Above Gate": TunicLocationData("East Forest", "Forest Grave Path Main"), "Forest Grave Path - Obscured Chest": TunicLocationData("East Forest", "Forest Grave Path Main"), "Forest Grave Path - Upper Walkway": TunicLocationData("East Forest", "Forest Grave Path Upper"), @@ -76,7 +77,7 @@ class TunicLocationData(NamedTuple): "Fortress Arena - Hexagon Red": TunicLocationData("Eastern Vault Fortress", "Fortress Arena"), "Fortress Arena - Siege Engine/Vault Key Pickup": TunicLocationData("Eastern Vault Fortress", "Fortress Arena"), "Fortress East Shortcut - Chest Near Slimes": TunicLocationData("Eastern Vault Fortress", "Fortress East Shortcut Lower"), - "Eastern Vault Fortress - [West Wing] Candles Holy Cross": TunicLocationData("Eastern Vault Fortress", "Eastern Vault Fortress", "holy cross"), + "Eastern Vault Fortress - [West Wing] Candles Holy Cross": TunicLocationData("Eastern Vault Fortress", "Eastern Vault Fortress", location_group="holy cross"), "Eastern Vault Fortress - [West Wing] Dark Room Chest 1": TunicLocationData("Eastern Vault Fortress", "Eastern Vault Fortress"), "Eastern Vault Fortress - [West Wing] Dark Room Chest 2": TunicLocationData("Eastern Vault Fortress", "Eastern Vault Fortress"), "Eastern Vault Fortress - [East Wing] Bombable Wall": TunicLocationData("Eastern Vault Fortress", "Eastern Vault Fortress"), @@ -113,11 +114,11 @@ class TunicLocationData(NamedTuple): "Hero's Grave - Mushroom Relic": TunicLocationData("Library", "Hero Relic - Library"), "Lower Mountain - Page Before Door": TunicLocationData("Overworld", "Lower Mountain"), "Changing Room - Normal Chest": TunicLocationData("Overworld", "Changing Room"), - "Fortress Courtyard - Chest Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave"), - "Fortress Courtyard - Near Fuse": TunicLocationData("Overworld", "Fortress Exterior from Overworld"), - "Fortress Courtyard - Below Walkway": TunicLocationData("Overworld", "Fortress Exterior from Overworld"), - "Fortress Courtyard - Page Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave"), - "West Furnace - Lantern Pickup": TunicLocationData("Overworld", "Furnace Fuse"), + "Fortress Courtyard - Chest Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave", ladder_region="East Overworld"), + "Fortress Courtyard - Near Fuse": TunicLocationData("Overworld", "Fortress Exterior from Overworld", ladder_region="East Overworld"), + "Fortress Courtyard - Below Walkway": TunicLocationData("Overworld", "Fortress Exterior from Overworld", ladder_region="East Overworld"), + "Fortress Courtyard - Page Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave", ladder_region="East Overworld"), + "West Furnace - Lantern Pickup": TunicLocationData("Overworld", "Furnace Fuse", ladder_region="Beneath the Well Back"), "Maze Cave - Maze Room Chest": TunicLocationData("Overworld", "Maze Cave"), "Old House - Normal Chest": TunicLocationData("Overworld", "Old House Front"), "Old House - Shield Pickup": TunicLocationData("Overworld", "Old House Front"), @@ -126,7 +127,7 @@ class TunicLocationData(NamedTuple): "Overworld - [West] Obscured Near Well": TunicLocationData("Overworld", "Overworld"), "Overworld - [Central] Bombable Wall": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Chest Near Turret": TunicLocationData("Overworld", "Overworld"), - "Overworld - [East] Chest Near Pots": TunicLocationData("Overworld", "Overworld"), + "Overworld - [East] Chest Near Pots": TunicLocationData("Overworld", "Overworld", ladder_region="East Overworld"), "Overworld - [Northwest] Chest Near Golden Obelisk": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] South Chest Near Guard": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] West Beach Guarded By Turret": TunicLocationData("Overworld", "Overworld"), @@ -135,7 +136,7 @@ class TunicLocationData(NamedTuple): "Overworld - [Southwest] Obscured In Tunnel To Beach": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Grapple Chest Over Walkway": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Chest Beneath Quarry Gate": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Southeast] Chest Near Swamp": TunicLocationData("Overworld", "Overworld"), + "Overworld - [Southeast] Chest Near Swamp": TunicLocationData("Overworld", "Overworld", ladder_region="Swamp"), "Overworld - [Southwest] From West Garden": TunicLocationData("Overworld", "Overworld"), "Overworld - [East] Grapple Chest": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] West Beach Guarded By Turret 2": TunicLocationData("Overworld", "Overworld"), @@ -144,7 +145,7 @@ class TunicLocationData(NamedTuple): "Overworld - [West] Chest After Bell": TunicLocationData("Overworld", "Overworld Belltower"), "Overworld - [Southwest] Tunnel Guarded By Turret": TunicLocationData("Overworld", "Overworld"), "Overworld - [East] Between Ladders Near Ruined Passage": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Northeast] Chest Above Patrol Cave": TunicLocationData("Overworld", "Overworld"), + "Overworld - [Northeast] Chest Above Patrol Cave": TunicLocationData("Overworld", "Overworld", ladder_region="Upper Overworld"), "Overworld - [Southwest] Beach Chest Beneath Guard": TunicLocationData("Overworld", "Overworld"), "Overworld - [Central] Chest Across From Well": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Chest Near Quarry Gate": TunicLocationData("Overworld", "Overworld"), @@ -154,10 +155,10 @@ class TunicLocationData(NamedTuple): "Overworld - [Southeast] Page on Pillar by Swamp": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Key Pickup": TunicLocationData("Overworld", "Overworld"), "Overworld - [West] Key Pickup": TunicLocationData("Overworld", "Overworld"), - "Overworld - [East] Page Near Secret Shop": TunicLocationData("Overworld", "Overworld"), + "Overworld - [East] Page Near Secret Shop": TunicLocationData("Overworld", "Overworld", ladder_region="East Overworld"), "Overworld - [Southwest] Fountain Page": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Page on Pillar by Dark Tomb": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Northwest] Fire Wand Pickup": TunicLocationData("Overworld", "Overworld"), + "Overworld - [Northwest] Fire Wand Pickup": TunicLocationData("Overworld", "Overworld", ladder_region="Upper Overworld"), "Overworld - [West] Page On Teleporter": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Page By Well": TunicLocationData("Overworld", "Overworld"), "Patrol Cave - Normal Chest": TunicLocationData("Overworld", "Patrol Cave"), @@ -169,45 +170,45 @@ class TunicLocationData(NamedTuple): "Shop - Potion 2": TunicLocationData("Overworld", "Shop", "shop"), "Shop - Coin 1": TunicLocationData("Overworld", "Shop", "shop"), "Shop - Coin 2": TunicLocationData("Overworld", "Shop", "shop"), - "Special Shop - Secret Page Pickup": TunicLocationData("Overworld", "Special Shop"), + "Special Shop - Secret Page Pickup": TunicLocationData("Overworld", "Special Shop", ladder_region="East Overworld"), "Stick House - Stick Chest": TunicLocationData("Overworld", "Stick House"), - "Sealed Temple - Page Pickup": TunicLocationData("Overworld", "Sealed Temple"), + "Sealed Temple - Page Pickup": TunicLocationData("Overworld", "Sealed Temple", ladder_region="Sealed Temple"), "Hourglass Cave - Hourglass Chest": TunicLocationData("Overworld", "Hourglass Cave"), "Far Shore - Secret Chest": TunicLocationData("Overworld", "Far Shore"), "Far Shore - Page Pickup": TunicLocationData("Overworld", "Far Shore to Spawn"), - "Coins in the Well - 10 Coins": TunicLocationData("Overworld", "Overworld", "well"), - "Coins in the Well - 15 Coins": TunicLocationData("Overworld", "Overworld", "well"), - "Coins in the Well - 3 Coins": TunicLocationData("Overworld", "Overworld", "well"), - "Coins in the Well - 6 Coins": TunicLocationData("Overworld", "Overworld", "well"), - "Secret Gathering Place - 20 Fairy Reward": TunicLocationData("Overworld", "Secret Gathering Place", "fairies"), - "Secret Gathering Place - 10 Fairy Reward": TunicLocationData("Overworld", "Secret Gathering Place", "fairies"), - "Overworld - [West] Moss Wall Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Overworld - [Southwest] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Overworld - [Southwest] Fountain Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Overworld - [Northeast] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Overworld - [East] Weathervane Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Overworld - [West] Windmill Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Overworld - [Southwest] Haiku Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Overworld - [West] Windchimes Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), + "Coins in the Well - 10 Coins": TunicLocationData("Overworld", "Overworld", location_group="well"), + "Coins in the Well - 15 Coins": TunicLocationData("Overworld", "Overworld", location_group="well"), + "Coins in the Well - 3 Coins": TunicLocationData("Overworld", "Overworld", location_group="well"), + "Coins in the Well - 6 Coins": TunicLocationData("Overworld", "Overworld", location_group="well"), + "Secret Gathering Place - 20 Fairy Reward": TunicLocationData("Overworld", "Secret Gathering Place", location_group="fairies"), + "Secret Gathering Place - 10 Fairy Reward": TunicLocationData("Overworld", "Secret Gathering Place", location_group="fairies"), + "Overworld - [West] Moss Wall Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), + "Overworld - [Southwest] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), + "Overworld - [Southwest] Fountain Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), + "Overworld - [Northeast] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", ladder_region="East Overworld", location_group="holy cross"), + "Overworld - [East] Weathervane Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", ladder_region="East Overworld", location_group="holy cross"), + "Overworld - [West] Windmill Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), + "Overworld - [Southwest] Haiku Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), + "Overworld - [West] Windchimes Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), "Overworld - [South] Starting Platform Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Overworld - [Northwest] Golden Obelisk Page": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Old House - Holy Cross Door Page": TunicLocationData("Overworld Holy Cross", "Old House Back", "holy cross"), - "Cube Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Cube Cave", "holy cross"), - "Southeast Cross Door - Chest 3": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", "holy cross"), - "Southeast Cross Door - Chest 2": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", "holy cross"), - "Southeast Cross Door - Chest 1": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", "holy cross"), + "Overworld - [Northwest] Golden Obelisk Page": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", ladder_region="Upper Overworld", location_group="holy cross"), + "Old House - Holy Cross Door Page": TunicLocationData("Overworld Holy Cross", "Old House Back", location_group="holy cross"), + "Cube Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Cube Cave", location_group="holy cross"), + "Southeast Cross Door - Chest 3": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), + "Southeast Cross Door - Chest 2": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), + "Southeast Cross Door - Chest 1": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), "Maze Cave - Maze Room Holy Cross": TunicLocationData("Overworld Holy Cross", "Maze Cave", "holy cross"), - "Caustic Light Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Caustic Light Cave", "holy cross"), + "Caustic Light Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Caustic Light Cave", ladder_region="Swamp", location_group="holy cross"), "Old House - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Old House Front", "holy cross"), "Patrol Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Patrol Cave", "holy cross"), - "Ruined Passage - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Ruined Passage", "holy cross"), + "Ruined Passage - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Ruined Passage", ladder_region="Overworld", location_group="holy cross"), "Hourglass Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Hourglass Cave", "holy cross"), - "Sealed Temple - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Sealed Temple", "holy cross"), + "Sealed Temple - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Sealed Temple", ladder_region="Sealed Temple", location_group="holy cross"), "Fountain Cross Door - Page Pickup": TunicLocationData("Overworld Holy Cross", "Fountain Cross Room", "holy cross"), - "Secret Gathering Place - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Secret Gathering Place", "holy cross"), - "Top of the Mountain - Page At The Peak": TunicLocationData("Overworld Holy Cross", "Top of the Mountain", "holy cross"), + "Secret Gathering Place - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Secret Gathering Place", location_group="holy cross"), + "Top of the Mountain - Page At The Peak": TunicLocationData("Overworld Holy Cross", "Top of the Mountain", ladder_region="Upper Overworld", location_group="holy cross"), "Monastery - Monastery Chest": TunicLocationData("Quarry", "Monastery Back"), - "Quarry - [Back Entrance] Bushes Holy Cross": TunicLocationData("Quarry Back", "Quarry Back", "holy cross"), + "Quarry - [Back Entrance] Bushes Holy Cross": TunicLocationData("Quarry Back", "Quarry Back", location_group="holy cross"), "Quarry - [Back Entrance] Chest": TunicLocationData("Quarry Back", "Quarry Back"), "Quarry - [Central] Near Shortcut Ladder": TunicLocationData("Quarry", "Quarry"), "Quarry - [East] Near Telescope": TunicLocationData("Quarry", "Quarry"), @@ -264,35 +265,35 @@ class TunicLocationData(NamedTuple): "Ruined Atoll - [Northeast] Chest On Brick Walkway": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [Southeast] Chest Near Fuse": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [Northeast] Key Pickup": TunicLocationData("Ruined Atoll", "Ruined Atoll"), - "Cathedral Gauntlet - Gauntlet Reward": TunicLocationData("Swamp", "Cathedral Gauntlet"), - "Cathedral - Secret Legend Trophy Chest": TunicLocationData("Swamp", "Cathedral Secret Legend Room"), - "Swamp - [Upper Graveyard] Obscured Behind Hill": TunicLocationData("Swamp", "Swamp"), + "Cathedral Gauntlet - Gauntlet Reward": TunicLocationData("Swamp", "Cathedral Gauntlet", ladder_region="Back of Swamp"), + "Cathedral - Secret Legend Trophy Chest": TunicLocationData("Swamp", "Cathedral Secret Legend Room", ladder_region="Swamp Middle"), + "Swamp - [Upper Graveyard] Obscured Behind Hill": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), "Swamp - [South Graveyard] 4 Orange Skulls": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Central] Near Ramps Up": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Upper Graveyard] Near Shield Fleemers": TunicLocationData("Swamp", "Swamp"), - "Swamp - [South Graveyard] Obscured Behind Ridge": TunicLocationData("Swamp", "Swamp"), + "Swamp - [Central] Near Ramps Up": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), + "Swamp - [Upper Graveyard] Near Shield Fleemers": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), + "Swamp - [South Graveyard] Obscured Behind Ridge": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), "Swamp - [South Graveyard] Obscured Beneath Telescope": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Entrance] Above Entryway": TunicLocationData("Swamp", "Back of Swamp Laurels Area"), - "Swamp - [Central] South Secret Passage": TunicLocationData("Swamp", "Swamp"), + "Swamp - [Entrance] Above Entryway": TunicLocationData("Swamp", "Back of Swamp Laurels Area", ladder_region="Back of Swamp"), + "Swamp - [Central] South Secret Passage": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), "Swamp - [South Graveyard] Upper Walkway On Pedestal": TunicLocationData("Swamp", "Swamp"), "Swamp - [South Graveyard] Guarded By Tentacles": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Upper Graveyard] Near Telescope": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Outside Cathedral] Near Moonlight Bridge Door": TunicLocationData("Swamp", "Swamp"), + "Swamp - [Upper Graveyard] Near Telescope": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), + "Swamp - [Outside Cathedral] Near Moonlight Bridge Door": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), "Swamp - [Entrance] Obscured Inside Watchtower": TunicLocationData("Swamp", "Swamp"), "Swamp - [Entrance] South Near Fence": TunicLocationData("Swamp", "Swamp"), "Swamp - [South Graveyard] Guarded By Big Skeleton": TunicLocationData("Swamp", "Swamp"), "Swamp - [South Graveyard] Chest Near Graves": TunicLocationData("Swamp", "Swamp"), "Swamp - [Entrance] North Small Island": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Outside Cathedral] Obscured Behind Memorial": TunicLocationData("Swamp", "Back of Swamp"), - "Swamp - [Central] Obscured Behind Northern Mountain": TunicLocationData("Swamp", "Swamp"), - "Swamp - [South Graveyard] Upper Walkway Dash Chest": TunicLocationData("Swamp", "Swamp"), + "Swamp - [Outside Cathedral] Obscured Behind Memorial": TunicLocationData("Swamp", "Back of Swamp", ladder_region="Back of Swamp"), + "Swamp - [Central] Obscured Behind Northern Mountain": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), + "Swamp - [South Graveyard] Upper Walkway Dash Chest": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), "Swamp - [South Graveyard] Above Big Skeleton": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Central] Beneath Memorial": TunicLocationData("Swamp", "Swamp"), + "Swamp - [Central] Beneath Memorial": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), "Hero's Grave - Feathers Relic": TunicLocationData("Swamp", "Hero Relic - Swamp"), "West Furnace - Chest": TunicLocationData("West Garden", "Furnace Walking Path"), "Overworld - [West] Near West Garden Entrance": TunicLocationData("West Garden", "Overworld to West Garden from Furnace"), - "West Garden - [Central Highlands] Holy Cross (Blue Lines)": TunicLocationData("West Garden", "West Garden", "holy cross"), - "West Garden - [West Lowlands] Tree Holy Cross Chest": TunicLocationData("West Garden", "West Garden", "holy cross"), + "West Garden - [Central Highlands] Holy Cross (Blue Lines)": TunicLocationData("West Garden", "West Garden", location_group="holy cross"), + "West Garden - [West Lowlands] Tree Holy Cross Chest": TunicLocationData("West Garden", "West Garden", location_group="holy cross"), "West Garden - [Southeast Lowlands] Outside Cave": TunicLocationData("West Garden", "West Garden"), "West Garden - [Central Lowlands] Chest Beneath Faeries": TunicLocationData("West Garden", "West Garden"), "West Garden - [North] Behind Holy Cross Door": TunicLocationData("West Garden", "West Garden", "holy cross"), @@ -307,7 +308,7 @@ class TunicLocationData(NamedTuple): "West Garden - [West Highlands] Upper Left Walkway": TunicLocationData("West Garden", "West Garden"), "West Garden - [Central Lowlands] Chest Beneath Save Point": TunicLocationData("West Garden", "West Garden"), "West Garden - [Central Highlands] Behind Guard Captain": TunicLocationData("West Garden", "West Garden"), - "West Garden - [Central Highlands] After Garden Knight": TunicLocationData("West Garden", "West Garden after Boss"), + "West Garden - [Central Highlands] After Garden Knight": TunicLocationData("Overworld", "West Garden after Boss", location_group="west garden"), "West Garden - [South Highlands] Secret Chest Beneath Fuse": TunicLocationData("West Garden", "West Garden"), "West Garden - [East Lowlands] Page Behind Ice Dagger House": TunicLocationData("West Garden", "West Garden Portal Item"), "West Garden - [North] Page Pickup": TunicLocationData("West Garden", "West Garden"), diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index f4790da36729..4a194d8c7ff2 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -131,6 +131,12 @@ class LaurelsLocation(Choice): default = 0 +class LadderRando(Toggle): + """Ladder rando description""" + internal_name = "ladder_rando" + display_name = "Ladder Rando" + + @dataclass class TunicOptions(PerGameCommonOptions): sword_progression: SwordProgression @@ -147,4 +153,5 @@ class TunicOptions(PerGameCommonOptions): lanternless: Lanternless maskless: Maskless laurels_location: LaurelsLocation + ladder_rando: LadderRando start_inventory_from_pool: StartInventoryPool diff --git a/worlds/tunic/regions.py b/worlds/tunic/regions.py index 70204c639733..d4e967ff1380 100644 --- a/worlds/tunic/regions.py +++ b/worlds/tunic/regions.py @@ -6,10 +6,10 @@ "Ruined Atoll", "Eastern Vault Fortress", "Beneath the Vault", "Quarry Back", "Quarry", "Swamp", "Spirit Arena"}, "Overworld Holy Cross": set(), - "East Forest": {"Eastern Vault Fortress"}, + "East Forest": set(), "Dark Tomb": {"West Garden"}, - "Beneath the Well": {"Dark Tomb"}, - "West Garden": {"Overworld", "Dark Tomb"}, + "Beneath the Well": set(), + "West Garden": set(), "Ruined Atoll": {"Frog's Domain", "Library"}, "Frog's Domain": set(), "Library": set(), @@ -23,3 +23,35 @@ "Cathedral": set(), "Spirit Arena": set() } + + +tunic_ladder_regions: Dict[str, Set[str]] = { + "Menu": {"Overworld"}, + "Overworld": {"Dark Tomb Front", "West Garden", "Ruined Atoll", "Beneath the Well", "Beneath the Well Back", + "Quarry", "Swamp", "Back of Swamp", "Spirit Arena", "Sealed Temple", "East Overworld", + "Upper Overworld", "Overworld Holy Cross", "East Forest"}, + "Overworld Holy Cross": set(), + "East Forest": set(), + "East Overworld": {"East Forest", "Eastern Vault Fortress", "Beneath the Vault"}, + "Upper Overworld": {"Quarry Back", "Sealed Temple"}, + "Dark Tomb Front": {"Dark Tomb"}, + "Dark Tomb": {"West Garden"}, + "Beneath the Well": {"Beneath the Well Back"}, + "Beneath the Well Back": {"Beneath the Well"}, + "West Garden": set(), + "Ruined Atoll": {"Frog's Domain", "Library"}, + "Frog's Domain": set(), + "Library": set(), + "Eastern Vault Fortress": {"Beneath the Vault"}, + "Beneath the Vault": {"Eastern Vault Fortress"}, + "Quarry Back": {"Quarry"}, + "Quarry": {"Lower Quarry", "Rooted Ziggurat"}, + "Lower Quarry": {"Rooted Ziggurat"}, + "Rooted Ziggurat": set(), + "Swamp": {"Swamp Middle"}, + "Swamp Middle": {"Cathedral"}, + "Cathedral": {"Back of Swamp"}, + "Back of Swamp": set(), + "Spirit Arena": set(), + "Sealed Temple": set() +} diff --git a/worlds/tunic/rules.py b/worlds/tunic/rules.py index b3dd0b683220..890d0b226ef7 100644 --- a/worlds/tunic/rules.py +++ b/worlds/tunic/rules.py @@ -103,18 +103,10 @@ def set_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> No multiworld.get_entrance("Overworld -> West Garden", player).access_rule = \ lambda state: state.has(laurels, player) \ or can_ladder_storage(state, player, options) - multiworld.get_entrance("Beneath the Well -> Dark Tomb", player).access_rule = \ - lambda state: has_lantern(state, player, options) - multiworld.get_entrance("West Garden -> Dark Tomb", player).access_rule = \ - lambda state: has_lantern(state, player, options) multiworld.get_entrance("Overworld -> Eastern Vault Fortress", player).access_rule = \ lambda state: state.has(laurels, player) \ or has_ice_grapple_logic(True, state, player, options, ability_unlocks) \ or can_ladder_storage(state, player, options) - multiworld.get_entrance("East Forest -> Eastern Vault Fortress", player).access_rule = \ - lambda state: state.has(laurels, player) \ - or has_ice_grapple_logic(True, state, player, options, ability_unlocks) \ - or can_ladder_storage(state, player, options) # using laurels or ls to get in is covered by the -> Eastern Vault Fortress rules multiworld.get_entrance("Overworld -> Beneath the Vault", player).access_rule = \ lambda state: has_lantern(state, player, options) and \ @@ -211,7 +203,8 @@ def set_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> lambda state: state.has(laurels, player)) set_rule(multiworld.get_location("Overworld - [West] Chest After Bell", player), lambda state: state.has(laurels, player) - or (has_lantern(state, player, options) and has_sword(state, player))) + or (has_lantern(state, player, options) and has_sword(state, player)) + or can_ladder_storage(state, player, options)) set_rule(multiworld.get_location("Overworld - [Northwest] Chest Beneath Quarry Gate", player), lambda state: state.has_any({grapple, laurels}, player) or options.logic_rules) set_rule(multiworld.get_location("Overworld - [East] Grapple Chest", player), @@ -228,6 +221,8 @@ def set_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> lambda state: state.has(laurels, player) or (has_lantern(state, player, options) and (has_sword(state, player) or state.has(fire_wand, player))) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) + set_rule(multiworld.get_location("West Furnace - Lantern Pickup", player), + lambda state: has_stick(state, player) or state.has_any({fire_wand, laurels}, player)) set_rule(multiworld.get_location("Secret Gathering Place - 10 Fairy Reward", player), lambda state: state.has(fairies, player, 10)) @@ -265,8 +260,8 @@ def set_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> set_rule(multiworld.get_location("West Garden - [Central Lowlands] Below Left Walkway", player), lambda state: state.has(laurels, player)) set_rule(multiworld.get_location("West Garden - [Central Highlands] After Garden Knight", player), - lambda state: has_sword(state, player) or state.has(laurels, player) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks) + lambda state: state.has(laurels, player) + or (has_lantern(state, player, options) and has_sword(state, player)) or can_ladder_storage(state, player, options)) # Ruined Atoll From ea9fb312dec439966090589d9be9a2f07a992090 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Wed, 28 Feb 2024 23:29:39 -0500 Subject: [PATCH 02/82] Some minor updates --- worlds/tunic/items.py | 19 ++++++++++--------- worlds/tunic/ladder_rules.py | 2 ++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index ffc45d0a83cd..1c8a5450da9a 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -144,21 +144,22 @@ class TunicItemData(NamedTuple): "Pages 52-53 (Icebolt)": TunicItemData(ItemClassification.progression, 1, 128, "pages"), "Pages 54-55": TunicItemData(ItemClassification.useful, 1, 129, "pages"), - "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), - "Ladders next to Dark Tomb": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), - "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), "Ladders next to Ruined Passage Exit": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), "Overworld Shortcut Ladders": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), - "Ladder by Temple Rafters Exit": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), - "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), - "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), - "Ladders next to West Belltower": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), - "Ladder to Well": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), "Ladder Drop to East Forest": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), "Ladders next to Patrol Cave": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), - "Dark Tomb Ladder": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), + "Ladder to Well": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), "Well Back Ladder": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), + "Ladders next to West Belltower": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), + "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), + "Dark Tomb Ladder": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), + "Ladders next to Dark Tomb": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), + "Ladder by Temple Rafters Exit": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), + "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), "Swamp Ladder": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), + "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), + "Frog's Domain Ladder": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), + "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), } fool_tiers: List[List[str]] = [ diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 6cd64c7e6c32..59f1b0375203 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -118,6 +118,8 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] multiworld.get_entrance("Overworld -> Ruined Atoll", player).access_rule = \ lambda state: state.has_any({"Ladder to Ruined Atoll", laurels, grapple}, player) \ or has_ability(state, player, prayer, options, ability_unlocks) + multiworld.get_entrance("Ruined Atoll -> Frog's Domain", player).access_rule = \ + lambda state: state.has("Frog's Domain Ladder", player) multiworld.get_entrance("Ruined Atoll -> Library", player).access_rule = \ lambda state: state.has_any({grapple, laurels}, player) and \ has_ability(state, player, prayer, options, ability_unlocks) From 5f07a92358b50a2d92867904e4f4c23ffa367f8d Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 29 Feb 2024 10:26:19 -0500 Subject: [PATCH 03/82] Renumber ladders --- worlds/tunic/items.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 1c8a5450da9a..338c55915fc4 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -144,22 +144,22 @@ class TunicItemData(NamedTuple): "Pages 52-53 (Icebolt)": TunicItemData(ItemClassification.progression, 1, 128, "pages"), "Pages 54-55": TunicItemData(ItemClassification.useful, 1, 129, "pages"), - "Ladders next to Ruined Passage Exit": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), - "Overworld Shortcut Ladders": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), - "Ladder Drop to East Forest": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), - "Ladders next to Patrol Cave": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), - "Ladder to Well": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), - "Well Back Ladder": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), - "Ladders next to West Belltower": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), - "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), - "Dark Tomb Ladder": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), - "Ladders next to Dark Tomb": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), - "Ladder by Temple Rafters Exit": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), - "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), - "Swamp Ladder": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), - "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), - "Frog's Domain Ladder": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), - "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), + "Ladders next to Ruined Passage Exit": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), + "Overworld Shortcut Ladders": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), + "Ladder Drop to East Forest": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), + "Ladders next to Patrol Cave": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), + "Ladder to Well": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), + "Well Back Ladder": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), + "Ladders next to West Belltower": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), + "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), + "Dark Tomb Ladder": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), + "Ladders next to Dark Tomb": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), + "Ladder by Temple Rafters Exit": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), + "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), + "Swamp Ladder": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), + "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), + "Frog's Domain Ladder": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), + "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), } fool_tiers: List[List[str]] = [ From 89b95d5d6982372051bffe96c6378a08b879cf63 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 29 Feb 2024 10:38:38 -0500 Subject: [PATCH 04/82] Rename frog ladder --- worlds/tunic/items.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 338c55915fc4..2fea965423dd 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -158,7 +158,7 @@ class TunicItemData(NamedTuple): "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), "Swamp Ladder": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), - "Frog's Domain Ladder": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), + "Frog's Domain Ladders": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), } From 148cd39ca39c62c280cb4bfaa3047d86905f93c9 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 29 Feb 2024 10:39:00 -0500 Subject: [PATCH 05/82] Rename frog ladders --- worlds/tunic/ladder_rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 59f1b0375203..25c06a6a0ac8 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -119,7 +119,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: state.has_any({"Ladder to Ruined Atoll", laurels, grapple}, player) \ or has_ability(state, player, prayer, options, ability_unlocks) multiworld.get_entrance("Ruined Atoll -> Frog's Domain", player).access_rule = \ - lambda state: state.has("Frog's Domain Ladder", player) + lambda state: state.has("Frog's Domain Ladders", player) multiworld.get_entrance("Ruined Atoll -> Library", player).access_rule = \ lambda state: state.has_any({grapple, laurels}, player) and \ has_ability(state, player, prayer, options, ability_unlocks) From 9df3be52ddaa06a832b0f0bff26849f0ffd497b9 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 29 Feb 2024 16:16:53 -0500 Subject: [PATCH 06/82] Add description for ladder rando --- worlds/tunic/options.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index 4a194d8c7ff2..e0ef887d90ba 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -132,7 +132,8 @@ class LaurelsLocation(Choice): class LadderRando(Toggle): - """Ladder rando description""" + """Removes several of the ladders from the game, requiring you to find their items to get them back. + Greatly increases the number of spheres, making it great for asyncs.""" internal_name = "ladder_rando" display_name = "Ladder Rando" From 3c297939b4ef24080a09846623fd47a519fc86e3 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 29 Feb 2024 20:17:15 -0500 Subject: [PATCH 07/82] Some renames, and more ladders --- worlds/tunic/items.py | 30 +++++++++++++----------- worlds/tunic/ladder_rules.py | 45 +++++++++++++++++++++--------------- worlds/tunic/locations.py | 12 +++++----- worlds/tunic/regions.py | 3 ++- 4 files changed, 51 insertions(+), 39 deletions(-) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 2fea965423dd..aeeac28bca83 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -144,22 +144,24 @@ class TunicItemData(NamedTuple): "Pages 52-53 (Icebolt)": TunicItemData(ItemClassification.progression, 1, 128, "pages"), "Pages 54-55": TunicItemData(ItemClassification.useful, 1, 129, "pages"), - "Ladders next to Ruined Passage Exit": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), + "Ladders near Weathervane": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), "Overworld Shortcut Ladders": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), "Ladder Drop to East Forest": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), - "Ladders next to Patrol Cave": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), - "Ladder to Well": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), - "Well Back Ladder": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), - "Ladders next to West Belltower": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), - "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), - "Dark Tomb Ladder": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), - "Ladders next to Dark Tomb": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), - "Ladder by Temple Rafters Exit": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), - "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), - "Swamp Ladder": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), - "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), - "Frog's Domain Ladders": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), - "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), + "Ladders to Lower Forest": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), + "Ladders near Patrol Cave": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), + "Ladder to Well": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), + "Well Back Ladder": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), + "Ladders to West Belltower": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), + "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), + "Dark Tomb Ladder": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), + "Ladders near Dark Tomb": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), + "Ladder near Temple Rafters": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), + "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), + "Central Swamp Ladder": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), + "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), + "South Atoll Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), + "Frog's Domain Ladders": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), + "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), } fool_tiers: List[List[str]] = [ diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 25c06a6a0ac8..adb2979232e6 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -28,10 +28,10 @@ def can_reach_east_overworld(state: CollectionState, player: int, options: TunicOptions, ability_unlocks: Dict[str, int]) -> bool: return ( - state.has_any({"Ladders next to Ruined Passage Exit", "Overworld Shortcut Ladders"}, player) + state.has_any({"Ladders near Weathervane", "Overworld Shortcut Ladders"}, player) or has_ice_grapple_logic(True, state, player, options, ability_unlocks) or (can_reach_upper_overworld(state, player, options, ability_unlocks) - and state.has("Ladders next to Patrol Cave", player)) + and state.has("Ladders near Patrol Cave", player)) or can_ladder_storage(state, player, options) or (state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) ) @@ -39,10 +39,10 @@ def can_reach_east_overworld(state: CollectionState, player: int, options: Tunic def can_reach_upper_overworld(state: CollectionState, player: int, options: TunicOptions, ability_unlocks: Dict[str, int]) -> bool: return ( - (state.has("Ladders next to Dark Tomb", player) and state.has_any({laurels, grapple}, player)) - or ((state.has_any({"Ladders next to Ruined Passage Exit", "Overworld Shortcut Ladders", grapple}, player) + (state.has("Ladders near Dark Tomb", player) and state.has_any({laurels, grapple}, player)) + or ((state.has_any({"Ladders near Weathervane", "Overworld Shortcut Ladders", grapple}, player) or can_ladder_storage(state, player, options)) - and (state.has("Ladders next to Patrol Cave", player) + and (state.has("Ladders near Patrol Cave", player) or has_ice_grapple_logic(True, state, player, options, ability_unlocks))) ) @@ -57,11 +57,11 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] multiworld.get_entrance("Overworld -> Sealed Temple", player).access_rule = \ lambda state: ((state.has("Ladder Drop to East Forest", player) and can_reach_east_overworld(state, player, options, ability_unlocks)) and - (state.has("Ladders next to West Belltower", player) and + (state.has("Ladders to West Belltower", player) and ((state.has(laurels, player) and (has_sword(state, player) or state.has(fire_wand, player))) or (state.has_all({lantern, "Dark Tomb Ladder"}, player) and has_sword(state, player)))) or (can_reach_upper_overworld(state, player, options, ability_unlocks) - and state.has_all({laurels, "Ladder by Temple Rafters Exit"}, player)) + and state.has_all({laurels, "Ladder near Temple Rafters"}, player)) or has_ice_grapple_logic(False, state, player, options, ability_unlocks) or can_ladder_storage(state, player, options) and state.has(laurels, player)) multiworld.get_entrance("Overworld -> East Overworld", player).access_rule = \ @@ -72,10 +72,12 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks) multiworld.get_entrance("East Overworld -> East Forest", player).access_rule = \ lambda state: state.has("Ladder Drop to East Forest", player) + multiworld.get_entrance("East Forest -> Lower Forest", player).access_rule = \ + lambda state: state.has("Ladders to Lower Forest", player) multiworld.get_entrance("Overworld -> Swamp", player).access_rule = \ lambda state: state.has("Ladder to Swamp", player) multiworld.get_entrance("Swamp -> Swamp Middle", player).access_rule = \ - lambda state: (state.has("Swamp Ladder", player) or state.has(laurels, player)) \ + lambda state: (state.has("Central Swamp Ladder", player) or state.has(laurels, player)) \ or (can_ladder_storage(state, player, options) and has_ability(state, player, holy_cross, options, ability_unlocks)) multiworld.get_entrance("Swamp Middle -> Cathedral", player).access_rule = \ @@ -92,7 +94,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: state.has("Dark Tomb Ladder", player) # dark tomb to west garden has no rule intentionally multiworld.get_entrance("Overworld -> West Garden", player).access_rule = \ - lambda state: (state.has(laurels, player) and state.has("Ladders next to West Belltower", player)) \ + lambda state: (state.has(laurels, player) and state.has("Ladders to West Belltower", player)) \ or can_ladder_storage(state, player, options) multiworld.get_entrance("Overworld -> Beneath the Well", player).access_rule = \ lambda state: state.has("Ladder to Well", player) @@ -122,7 +124,8 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: state.has("Frog's Domain Ladders", player) multiworld.get_entrance("Ruined Atoll -> Library", player).access_rule = \ lambda state: state.has_any({grapple, laurels}, player) and \ - has_ability(state, player, prayer, options, ability_unlocks) + has_ability(state, player, prayer, options, ability_unlocks) and \ + state.has("South Atoll Ladders", player) # have combat items, and the ladder to quarry, and the quarry ladder, or ls to skip those last two multiworld.get_entrance("Overworld -> Quarry", player).access_rule = \ lambda state: (has_sword(state, player) or state.has(fire_wand, player)) \ @@ -186,12 +189,12 @@ def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, in lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) and (can_reach_east_overworld(state, player, options, ability_unlocks) or ((can_reach_upper_overworld(state, player, options, ability_unlocks) or state.has(grapple, player)) - and state.has("Ladders next to Patrol Cave", player)))) + and state.has("Ladders near Patrol Cave", player)))) set_rule(multiworld.get_location("Sealed Temple - Holy Cross Chest", player), lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) set_rule(multiworld.get_location("Ruined Passage - Holy Cross Chest", player), lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) - and (state.has("Ladders next to Ruined Passage Exit", player) + and (state.has("Ladders near Weathervane", player) or state.has(key, player, 2) or (state.has(laurels, player) and options.logic_rules) or has_ice_grapple_logic(True, state, player, options, ability_unlocks) @@ -232,7 +235,7 @@ def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, in set_rule(multiworld.get_location("Overworld - [West] Chest After Bell", player), lambda state: state.has(laurels, player) or (has_lantern(state, player, options) and has_sword(state, player) - and state.has_all({"Ladders next to West Belltower", "Dark Tomb Ladder"}, player)) + and state.has_all({"Ladders to West Belltower", "Dark Tomb Ladder"}, player)) or can_ladder_storage(state, player, options)) set_rule(multiworld.get_location("Overworld - [Northwest] Chest Beneath Quarry Gate", player), lambda state: state.has_any({grapple, laurels}, player) or options.logic_rules) @@ -241,29 +244,29 @@ def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, in set_rule(multiworld.get_location("Special Shop - Secret Page Pickup", player), lambda state: state.has(laurels, player)) set_rule(multiworld.get_location("Ruined Passage - Page Pickup", player), - lambda state: state.has("Ladders next to Ruined Passage Exit", player) + lambda state: state.has("Ladders near Weathervane", player) or state.has(key, player, 2) or (state.has(laurels, player) and options.logic_rules) or has_ice_grapple_logic(True, state, player, options, ability_unlocks) or can_ladder_storage(state, player, options)) set_rule(multiworld.get_location("Overworld - [East] Between Ladders Near Ruined Passage", player), - lambda state: state.has("Ladders next to Ruined Passage Exit", player) + lambda state: state.has("Ladders near Weathervane", player) or state.has(key, player, 2) or (state.has(laurels, player) and options.logic_rules) or has_ice_grapple_logic(True, state, player, options, ability_unlocks) or can_ladder_storage(state, player, options)) set_rule(multiworld.get_location("Overworld - [East] Chest In Trees", player), - lambda state: state.has_any({laurels, "Ladders next to Ruined Passage Exit"}, player)) + lambda state: state.has_any({laurels, "Ladders near Weathervane"}, player)) set_rule(multiworld.get_location("Hourglass Cave - Holy Cross Chest", player), lambda state: state.has("Hourglass Cave Ladders", player)) set_rule(multiworld.get_location("Overworld - [Northwest] Chest Near Golden Obelisk", player), - lambda state: state.has("Ladders next to Dark Tomb", player) + lambda state: state.has("Ladders near Dark Tomb", player) or (can_reach_upper_overworld(state, player, options, ability_unlocks) and state.has_any({laurels, grapple}, player))) set_rule(multiworld.get_location("Patrol Cave - Normal Chest", player), lambda state: can_reach_east_overworld(state, player, options, ability_unlocks) or ((can_reach_upper_overworld(state, player, options, ability_unlocks) or state.has(grapple, player)) - and state.has("Ladders next to Patrol Cave", player))) + and state.has("Ladders near Patrol Cave", player))) set_rule(multiworld.get_location("Secret Gathering Place - 10 Fairy Reward", player), lambda state: state.has(fairies, player, 10)) @@ -314,6 +317,12 @@ def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, in lambda state: state.has_any({laurels, key}, player)) set_rule(multiworld.get_location("Librarian - Hexagon Green", player), lambda state: has_sword(state, player) or options.logic_rules) + set_rule(multiworld.get_location("Ruined Atoll - [Southeast] Chest Near Fuse", player), + lambda state: state.has("South Atoll Ladders", player)) + set_rule(multiworld.get_location("Ruined Atoll - [South] Upper Floor On Bricks", player), + lambda state: state.has("South Atoll Ladders", player)) + set_rule(multiworld.get_location("Ruined Atoll - [South] Upper Floor On Power Line", player), + lambda state: state.has("South Atoll Ladders", player)) # Frog's Domain set_rule(multiworld.get_location("Frog's Domain - Side Room Grapple Secret", player), diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index 1c34a4808f96..83d7243bc5aa 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -44,21 +44,21 @@ class TunicLocationData(NamedTuple): "Dark Tomb - Spike Maze Near Stairs": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - 1st Laser Room Obscured": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Guardhouse 2 - Upper Floor": TunicLocationData("East Forest", "Guard House 2"), - "Guardhouse 2 - Bottom Floor Secret": TunicLocationData("East Forest", "Guard House 2"), + "Guardhouse 2 - Bottom Floor Secret": TunicLocationData("East Forest", "Guard House 2", ladder_region="Lower Forest"), "Guardhouse 1 - Upper Floor Obscured": TunicLocationData("East Forest", "Guard House 1 East"), "Guardhouse 1 - Upper Floor": TunicLocationData("East Forest", "Guard House 1 East"), "East Forest - Dancing Fox Spirit Holy Cross": TunicLocationData("East Forest", "East Forest Dance Fox Spot", location_group="holy cross"), - "East Forest - Golden Obelisk Holy Cross": TunicLocationData("East Forest", "East Forest", "holy cross"), + "East Forest - Golden Obelisk Holy Cross": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest", location_group="holy cross"), "East Forest - Ice Rod Grapple Chest": TunicLocationData("East Forest", "East Forest"), "East Forest - Above Save Point": TunicLocationData("East Forest", "East Forest"), "East Forest - Above Save Point Obscured": TunicLocationData("East Forest", "East Forest"), "East Forest - From Guardhouse 1 Chest": TunicLocationData("East Forest", "East Forest Dance Fox Spot"), "East Forest - Near Save Point": TunicLocationData("East Forest", "East Forest"), - "East Forest - Beneath Spider Chest": TunicLocationData("East Forest", "East Forest"), + "East Forest - Beneath Spider Chest": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest"), "East Forest - Near Telescope": TunicLocationData("East Forest", "East Forest"), - "East Forest - Spider Chest": TunicLocationData("East Forest", "East Forest"), - "East Forest - Lower Dash Chest": TunicLocationData("East Forest", "East Forest"), - "East Forest - Lower Grapple Chest": TunicLocationData("East Forest", "East Forest"), + "East Forest - Spider Chest": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest"), + "East Forest - Lower Dash Chest": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest"), + "East Forest - Lower Grapple Chest": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest"), "East Forest - Bombable Wall": TunicLocationData("East Forest", "East Forest"), "East Forest - Page On Teleporter": TunicLocationData("East Forest", "East Forest"), "Forest Belltower - Near Save Point": TunicLocationData("East Forest", "Forest Belltower Lower"), diff --git a/worlds/tunic/regions.py b/worlds/tunic/regions.py index d4e967ff1380..b5e2fb7c917b 100644 --- a/worlds/tunic/regions.py +++ b/worlds/tunic/regions.py @@ -31,7 +31,8 @@ "Quarry", "Swamp", "Back of Swamp", "Spirit Arena", "Sealed Temple", "East Overworld", "Upper Overworld", "Overworld Holy Cross", "East Forest"}, "Overworld Holy Cross": set(), - "East Forest": set(), + "East Forest": {"Lower Forest"}, + "Lower Forest": set(), "East Overworld": {"East Forest", "Eastern Vault Fortress", "Beneath the Vault"}, "Upper Overworld": {"Quarry Back", "Sealed Temple"}, "Dark Tomb Front": {"Dark Tomb"}, From c78622afa6d5bdfa9e9f24c9add1c05c501d3446 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 1 Mar 2024 19:46:09 -0500 Subject: [PATCH 08/82] Rename swamp ladder --- worlds/tunic/items.py | 2 +- worlds/tunic/ladder_rules.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index aeeac28bca83..de2149492745 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -157,7 +157,7 @@ class TunicItemData(NamedTuple): "Ladders near Dark Tomb": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), "Ladder near Temple Rafters": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), - "Central Swamp Ladder": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), + "Swamp Ladders": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), "South Atoll Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), "Frog's Domain Ladders": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index adb2979232e6..e0b76b7c87eb 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -77,9 +77,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] multiworld.get_entrance("Overworld -> Swamp", player).access_rule = \ lambda state: state.has("Ladder to Swamp", player) multiworld.get_entrance("Swamp -> Swamp Middle", player).access_rule = \ - lambda state: (state.has("Central Swamp Ladder", player) or state.has(laurels, player)) \ - or (can_ladder_storage(state, player, options) - and has_ability(state, player, holy_cross, options, ability_unlocks)) + lambda state: state.has("Swamp Ladders", player) or state.has(laurels, player) multiworld.get_entrance("Swamp Middle -> Cathedral", player).access_rule = \ lambda state: (has_ability(state, player, prayer, options, ability_unlocks) and (state.has(laurels, player) From dea35afe119f9849c6d46eb335aa9a6115e863d0 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 1 Mar 2024 23:42:20 -0500 Subject: [PATCH 09/82] Most of the way through ER, just need to do rules --- worlds/tunic/er_data.py | 223 +++++++++++++++++++++++------------ worlds/tunic/er_rules.py | 160 ++++++++++++++++++++++++- worlds/tunic/items.py | 1 + worlds/tunic/ladder_rules.py | 6 + worlds/tunic/locations.py | 112 +++++++++--------- worlds/tunic/regions.py | 5 +- 6 files changed, 369 insertions(+), 138 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 7678d77fe034..5edaabd62adf 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -19,7 +19,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Sword Cave_"), Portal(name="Windmill Entrance", region="Overworld", destination="Windmill_"), - Portal(name="Well Ladder Entrance", region="Overworld", + Portal(name="Well Ladder Entrance", region="Overworld Well Ladder", destination="Sewer_entrance"), Portal(name="Entrance to Well from Well Rail", region="Overworld Well to Furnace Rail", destination="Sewer_west_aqueduct"), @@ -35,25 +35,25 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Furnace_gyro_west"), Portal(name="Entrance to Furnace from Beach", region="Overworld", destination="Furnace_gyro_lower"), - Portal(name="Caustic Light Cave Entrance", region="Overworld", + Portal(name="Caustic Light Cave Entrance", region="Overworld Swamp Lower Entry", destination="Overworld Cave_"), Portal(name="Swamp Upper Entrance", region="Overworld Swamp Upper Entry", destination="Swamp Redux 2_wall"), - Portal(name="Swamp Lower Entrance", region="Overworld", + Portal(name="Swamp Lower Entrance", region="Overworld Swamp Lower Entry", destination="Swamp Redux 2_conduit"), - Portal(name="Ruined Passage Not-Door Entrance", region="Overworld", + Portal(name="Ruined Passage Not-Door Entrance", region="After Ruined Passage", destination="Ruins Passage_east"), Portal(name="Ruined Passage Door Entrance", region="Overworld Ruined Passage Door", destination="Ruins Passage_west"), - Portal(name="Atoll Upper Entrance", region="Overworld", + Portal(name="Atoll Upper Entrance", region="Overworld to Atoll Upper", destination="Atoll Redux_upper"), - Portal(name="Atoll Lower Entrance", region="Overworld", + Portal(name="Atoll Lower Entrance", region="Overworld Beach", destination="Atoll Redux_lower"), Portal(name="Special Shop Entrance", region="Overworld Special Shop Entry", destination="ShopSpecial_"), - Portal(name="Maze Cave Entrance", region="Overworld", + Portal(name="Maze Cave Entrance", region="Overworld Beach", destination="Maze Room_"), - Portal(name="West Garden Entrance near Belltower", region="Overworld Belltower", + Portal(name="West Garden Entrance near Belltower", region="Overworld to West Garden Upper", destination="Archipelagos Redux_upper"), Portal(name="West Garden Entrance from Furnace", region="Overworld to West Garden from Furnace", destination="Archipelagos Redux_lower"), @@ -61,31 +61,31 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Archipelagos Redux_lowest"), Portal(name="Temple Door Entrance", region="Overworld Temple Door", destination="Temple_main"), - Portal(name="Temple Rafters Entrance", region="Overworld", + Portal(name="Temple Rafters Entrance", region="Upper Overworld", destination="Temple_rafters"), Portal(name="Ruined Shop Entrance", region="Overworld", destination="Ruined Shop_"), - Portal(name="Patrol Cave Entrance", region="Overworld", + Portal(name="Patrol Cave Entrance", region="Overworld at Patrol Cave", destination="PatrolCave_"), - Portal(name="Hourglass Cave Entrance", region="Overworld", + Portal(name="Hourglass Cave Entrance", region="Overworld Beach", destination="Town Basement_beach"), Portal(name="Changing Room Entrance", region="Overworld", destination="Changing Room_"), Portal(name="Cube Cave Entrance", region="Overworld", destination="CubeRoom_"), - Portal(name="Stairs from Overworld to Mountain", region="Overworld", + Portal(name="Stairs from Overworld to Mountain", region="Upper Overworld", destination="Mountain_"), - Portal(name="Overworld to Fortress", region="Overworld", + Portal(name="Overworld to Fortress", region="East Overworld", destination="Fortress Courtyard_"), Portal(name="Fountain HC Door Entrance", region="Overworld Fountain Cross Door", destination="Town_FiligreeRoom_"), Portal(name="Southeast HC Door Entrance", region="Overworld Southeast Cross Door", destination="EastFiligreeCache_"), - Portal(name="Overworld to Quarry Connector", region="Overworld", + Portal(name="Overworld to Quarry Connector", region="Overworld Quarry Entry", destination="Darkwoods Tunnel_"), Portal(name="Dark Tomb Main Entrance", region="Overworld", destination="Crypt Redux_"), - Portal(name="Overworld to Forest Belltower", region="Overworld", + Portal(name="Overworld to Forest Belltower", region="East Overworld", destination="Forest Belltower_"), Portal(name="Town to Far Shore", region="Overworld Town Portal", destination="Transit_teleporter_town"), @@ -166,7 +166,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th Portal(name="Temple Door Exit", region="Sealed Temple", destination="Overworld Redux_main"), - Portal(name="Well Ladder Exit", region="Beneath the Well Front", + Portal(name="Well Ladder Exit", region="Beneath Well the Ladder Exit", destination="Overworld Redux_entrance"), Portal(name="Well to Well Boss", region="Beneath the Well Back", destination="Sewer_Boss_"), @@ -213,18 +213,18 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Transit_teleporter_atoll"), Portal(name="Atoll Statue Teleporter", region="Ruined Atoll Statue", destination="Library Exterior_"), - Portal(name="Frog Stairs Eye Entrance", region="Ruined Atoll", + Portal(name="Frog Stairs Eye Entrance", region="Ruined Atoll Frog Eye Entrance", destination="Frog Stairs_eye"), Portal(name="Frog Stairs Mouth Entrance", region="Ruined Atoll Frog Mouth", destination="Frog Stairs_mouth"), - Portal(name="Frog Stairs Eye Exit", region="Frog's Domain Entry", + Portal(name="Frog Stairs Eye Exit", region="Frog Eye Exit", destination="Atoll Redux_eye"), - Portal(name="Frog Stairs Mouth Exit", region="Frog's Domain Entry", + Portal(name="Frog Stairs Mouth Exit", region="Frog Stairs Upper", destination="Atoll Redux_mouth"), - Portal(name="Frog Stairs to Frog's Domain's Entrance", region="Frog's Domain Entry", + Portal(name="Frog Stairs to Frog's Domain's Entrance", region="Frog Stairs to Frog's Domain", destination="frog cave main_Entrance"), - Portal(name="Frog Stairs to Frog's Domain's Exit", region="Frog's Domain Entry", + Portal(name="Frog Stairs to Frog's Domain's Exit", region="Frog Stairs Lower", destination="frog cave main_Exit"), Portal(name="Frog's Domain Ladder Exit", region="Frog's Domain", @@ -269,7 +269,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="East Forest Redux Laddercave_upper"), Portal(name="Forest to Far Shore", region="East Forest Portal", destination="Transit_teleporter_forest teleporter"), - Portal(name="Forest Guard House 2 Lower Entrance", region="East Forest", + Portal(name="Forest Guard House 2 Lower Entrance", region="Lower Forest", destination="East Forest Redux Interior_lower"), Portal(name="Forest Guard House 2 Upper Entrance", region="East Forest", destination="East Forest Redux Interior_upper"), @@ -294,9 +294,9 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th Portal(name="East Forest Hero's Grave", region="Forest Hero's Grave", destination="RelicVoid_teleporter_relic plinth"), - Portal(name="Guard House 2 Lower Exit", region="Guard House 2", + Portal(name="Guard House 2 Lower Exit", region="Guard House 2 Lower", destination="East Forest Redux_lower"), - Portal(name="Guard House 2 Upper Exit", region="Guard House 2", + Portal(name="Guard House 2 Upper Exit", region="Guard House 2 Upper", destination="East Forest Redux_upper"), Portal(name="Guard Captain Room Non-Gate Exit", region="Forest Boss Room", @@ -434,7 +434,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th Portal(name="Ziggurat to Far Shore", region="Rooted Ziggurat Portal", destination="Transit_teleporter_ziggurat teleporter"), - Portal(name="Swamp Lower Exit", region="Swamp", + Portal(name="Swamp Lower Exit", region="Swamp Front", destination="Overworld Redux_conduit"), Portal(name="Swamp to Cathedral Main Entrance", region="Swamp to Cathedral Main Entrance", destination="Cathedral Redux_main"), @@ -442,7 +442,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Cathedral Redux_secret"), Portal(name="Swamp to Gauntlet", region="Back of Swamp", destination="Cathedral Arena_"), - Portal(name="Swamp Shop", region="Swamp", + Portal(name="Swamp Shop", region="Swamp Front", destination="Shop_"), Portal(name="Swamp Upper Exit", region="Back of Swamp Laurels Area", destination="Overworld Redux_wall"), @@ -534,9 +534,24 @@ class Hint(IntEnum): "Overworld Holy Cross": RegionInfo("Fake", dead_end=DeadEnd.all_cats), "Overworld Belltower": RegionInfo("Overworld Redux"), # the area with the belltower and chest "Overworld Swamp Upper Entry": RegionInfo("Overworld Redux"), # upper swamp entry spot + "Overworld Swamp Lower Entry": RegionInfo("Overworld Redux"), # lower swamp entrance, rotating lights + "After Ruined Passage": RegionInfo("Overworld Redux"), # just the door and chest + "Above Ruined Passage": RegionInfo("Overworld Redux"), # one ladder up, just the chest in the trees + "East Overworld": RegionInfo("Overworld Redux"), # where the east forest and fortress entrances are "Overworld Special Shop Entry": RegionInfo("Overworld Redux"), # special shop entry spot + "Upper Overworld": RegionInfo("Overworld Redux"), # where the mountain stairs are + "Overworld above Quarry Entrance": RegionInfo("Overworld Redux"), + "Overworld after Temple Rafters": RegionInfo("Overworld Redux"), # the ledge after the rafter exit, before ladder + "Overworld Quarry Entry": RegionInfo("Overworld Redux"), # at the top of the ladder to darkwoods + "Overworld above Patrol Cave": RegionInfo("Overworld Redux"), # where the hook is, and one ladder up from patrol + "Overworld at Patrol Cave": RegionInfo("Overworld Redux"), # right at the patrol cave entrance "Overworld West Garden Laurels Entry": RegionInfo("Overworld Redux"), # west garden laurels entry + # todo: continue from here + "Overworld to West Garden Upper": RegionInfo("Overworld Redux"), # usually leads to garden knight # todo "Overworld to West Garden from Furnace": RegionInfo("Overworld Redux", hint=Hint.region), + "Overworld Well Ladder": RegionInfo("Overworld Redux"), # just the ladder entrance # todo + "Overworld Beach": RegionInfo("Overworld Redux"), # todo + "Overworld to Atoll Upper": RegionInfo("Overworld Redux"), # todo "Overworld Well to Furnace Rail": RegionInfo("Overworld Redux"), # the tiny rail passageway "Overworld Ruined Passage Door": RegionInfo("Overworld Redux"), # the small space betweeen the door and the portal "Overworld Old House Door": RegionInfo("Overworld Redux"), # the too-small space between the door and the portal @@ -564,7 +579,8 @@ class Hint(IntEnum): "Cube Cave": RegionInfo("CubeRoom", dead_end=DeadEnd.all_cats, hint=Hint.region), "Southeast Cross Room": RegionInfo("EastFiligreeCache", dead_end=DeadEnd.all_cats, hint=Hint.region), "Fountain Cross Room": RegionInfo("Town_FiligreeRoom", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Hourglass Cave": RegionInfo("Town Basement", dead_end=DeadEnd.all_cats, hint=Hint.region), + "Hourglass Cave": RegionInfo("Town Basement", dead_end=DeadEnd.all_cats), # todo + "Hourglass Cave Tower": RegionInfo("Town Basement", dead_end=DeadEnd.all_cats), # top of the tower # todo "Sealed Temple": RegionInfo("Temple", hint=Hint.scene), "Sealed Temple Rafters": RegionInfo("Temple", hint=Hint.scene), "Forest Belltower Upper": RegionInfo("Forest Belltower", hint=Hint.region), @@ -573,22 +589,26 @@ class Hint(IntEnum): "East Forest": RegionInfo("East Forest Redux"), "East Forest Dance Fox Spot": RegionInfo("East Forest Redux"), "East Forest Portal": RegionInfo("East Forest Redux"), + "Lower Forest": RegionInfo("East Forest Redux"), # bottom of the forest # todo "Guard House 1 East": RegionInfo("East Forest Redux Laddercave"), "Guard House 1 West": RegionInfo("East Forest Redux Laddercave"), - "Guard House 2": RegionInfo("East Forest Redux Interior"), + "Guard House 2 Upper": RegionInfo("East Forest Redux Interior"), # todo + "Guard House 2 Lower": RegionInfo("East Forest Redux Interior"), # todo "Forest Boss Room": RegionInfo("Forest Boss Room"), "Forest Grave Path Main": RegionInfo("Sword Access"), "Forest Grave Path Upper": RegionInfo("Sword Access"), "Forest Grave Path by Grave": RegionInfo("Sword Access"), "Forest Hero's Grave": RegionInfo("Sword Access"), "Dark Tomb Entry Point": RegionInfo("Crypt Redux"), # both upper exits + "Dark Tomb Upper": RegionInfo("Crypt Redux"), # the part with the casket and the top of the ladder # todo "Dark Tomb Main": RegionInfo("Crypt Redux"), "Dark Tomb Dark Exit": RegionInfo("Crypt Redux"), "Dark Tomb Checkpoint": RegionInfo("Sewer_Boss"), # can laurels backwards "Well Boss": RegionInfo("Sewer_Boss"), # can walk through (with bombs at least) - "Beneath the Well Front": RegionInfo("Sewer"), - "Beneath the Well Main": RegionInfo("Sewer"), - "Beneath the Well Back": RegionInfo("Sewer"), + "Beneath the Well Ladder Exit": RegionInfo("Sewer"), # just the ladder # todo + "Beneath the Well Front": RegionInfo("Sewer"), # the front, to separate it from the weapon requirement in the mid # todo + "Beneath the Well Main": RegionInfo("Sewer"), # the main section of it, requires a weapon # todo + "Beneath the Well Back": RegionInfo("Sewer"), # the back two portals, and all 4 upper chests # todo "West Garden": RegionInfo("Archipelagos Redux"), "Magic Dagger House": RegionInfo("archipelagos_house", dead_end=DeadEnd.all_cats, hint=Hint.region), "West Garden Portal": RegionInfo("Archipelagos Redux", dead_end=DeadEnd.restricted), @@ -598,10 +618,15 @@ class Hint(IntEnum): "West Garden Hero's Grave": RegionInfo("Archipelagos Redux"), "Ruined Atoll": RegionInfo("Atoll Redux"), "Ruined Atoll Lower Entry Area": RegionInfo("Atoll Redux"), + "Ruined Atoll Ladder Tops": RegionInfo("Atoll Redux"), # at the top of the 5 ladders in south Atoll # todo "Ruined Atoll Frog Mouth": RegionInfo("Atoll Redux"), "Ruined Atoll Portal": RegionInfo("Atoll Redux"), "Ruined Atoll Statue": RegionInfo("Atoll Redux"), - "Frog's Domain Entry": RegionInfo("Frog Stairs"), + "Frog Eye Entrance": RegionInfo("Atoll Redux"), # todo + "Frog Eye Exit": RegionInfo("Frog Stairs"), # todo + "Frog Stairs Upper": RegionInfo("Frog Stairs"), # todo + "Frog Stairs Lower": RegionInfo("Frog Stairs"), # todo + "Frog Stairs to Frog's Domain": RegionInfo("Frog Stairs"), # todo "Frog's Domain": RegionInfo("frog cave main", hint=Hint.region), "Frog's Domain Back": RegionInfo("frog cave main", hint=Hint.scene), "Library Exterior Tree": RegionInfo("Library Exterior"), @@ -657,9 +682,11 @@ class Hint(IntEnum): "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"), - "Swamp": RegionInfo("Swamp Redux 2"), - "Swamp to Cathedral Treasure Room": RegionInfo("Swamp Redux 2"), - "Swamp to Cathedral Main Entrance": RegionInfo("Swamp Redux 2"), + "Swamp Front": RegionInfo("Swamp Redux 2"), # from the main entry to the top of the ladder after south # todo + "Swamp Mid": RegionInfo("Swamp Redux 2"), # from the bottom of the ladder to the cathedral door # todo + "Swamp Ledge Under Cathedral Door": RegionInfo("Swamp Redux 2"), # the ledge with the chest and secret door # todo + "Swamp to Cathedral Treasure Room": RegionInfo("Swamp Redux 2"), # just the door # todo + "Swamp to Cathedral Main Entrance": RegionInfo("Swamp Redux 2"), # just the door # todo "Back of Swamp": RegionInfo("Swamp Redux 2"), # the area with hero grave and gauntlet entrance "Swamp Hero's Grave": RegionInfo("Swamp Redux 2"), "Back of Swamp Laurels Area": RegionInfo("Swamp Redux 2"), # the spots you need laurels to traverse @@ -734,11 +761,21 @@ class Hint(IntEnum): dependent_regions_restricted: Dict[Tuple[str, ...], List[str]] = { ("Overworld", "Overworld Belltower", "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 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", "Overworld Belltower", "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 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"], + ("Hourglass Cave",): + ["Hourglass Cave", "Hourglass Cave Tower"], ("Old House Front",): ["Old House Front", "Old House Back"], ("Furnace Fuse", "Furnace Ladder Area", "Furnace Walking Path"): @@ -748,27 +785,31 @@ class Hint(IntEnum): ["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"): - ["East Forest", "East Forest Dance Fox Spot", "East Forest Portal"], + ("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 Front", "Beneath the Well Main", "Beneath the Well Back"], - ("Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit"): - ["Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit"], + ("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", "West Garden after Boss", "West Garden Hero's Grave"): ["West Garden", "West Garden Laurels Exit", "West Garden after Boss", "West Garden Hero's Grave"], ("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 Statue", "Ruined Atoll Ladder Tops", "Frog Eye Entrance", "Ruined Atoll Ladder Tops"): ["Ruined Atoll", "Ruined Atoll Lower Entry Area", "Ruined Atoll Frog Mouth", "Ruined Atoll Portal", - "Ruined Atoll Statue"], + "Ruined Atoll Statue", "Ruined Atoll Ladder Tops", "Frog Eye Entrance", "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", "Frog's Domain Back"], ("Library Exterior Ladder", "Library Exterior Tree"): @@ -813,8 +854,9 @@ class Hint(IntEnum): ["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", "Swamp to Cathedral Treasure Room"): - ["Swamp", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance"], + ("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", + "Swamp Ledge Under Cathedral Door"], ("Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave"): ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave"], ("Cathedral Gauntlet Checkpoint",): @@ -830,14 +872,22 @@ class Hint(IntEnum): ("Overworld", "Overworld Belltower", "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 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", "Overworld Belltower", "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 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"], # 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"], @@ -845,16 +895,18 @@ class Hint(IntEnum): ["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"): - ["East Forest", "East Forest Dance Fox Spot", "East Forest Portal"], + ("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 Front", "Beneath the Well Main", "Beneath the Well Back"], - ("Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit"): - ["Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit"], + ("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", "West Garden after Boss", "West Garden Hero's Grave", @@ -862,9 +914,11 @@ class Hint(IntEnum): ["West Garden", "West Garden Laurels Exit", "West Garden after Boss", "West Garden Hero's Grave", "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 Statue", "Ruined Atoll Ladder Tops", "Frog Eye Entrance", "Ruined Atoll Ladder Tops"): ["Ruined Atoll", "Ruined Atoll Lower Entry Area", "Ruined Atoll Frog Mouth", "Ruined Atoll Portal", - "Ruined Atoll Statue"], + "Ruined Atoll Statue", "Ruined Atoll Ladder Tops", "Frog Eye Entrance", "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", "Frog's Domain Back"], ("Library Exterior Ladder", "Library Exterior Tree"): @@ -907,11 +961,13 @@ class Hint(IntEnum): ["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", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance"): - ["Swamp", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance"], + ("Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", + "Swamp Ledge Under Cathedral Door"): + ["Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", + "Swamp Ledge Under Cathedral Door"], ("Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave"): - ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp", - "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance"], + ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Front", "Swamp Mid", + "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", "Swamp Ledge Under Cathedral Door"], ("Cathedral Gauntlet Checkpoint",): ["Cathedral Gauntlet Checkpoint", "Cathedral Gauntlet Exit", "Cathedral Gauntlet"], ("Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", @@ -926,14 +982,23 @@ class Hint(IntEnum): ("Overworld", "Overworld Belltower", "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 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", "Overworld Belltower", "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 Well to Furnace Rail"], + "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"], # 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"], @@ -941,17 +1006,19 @@ class Hint(IntEnum): ["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"): - ["East Forest", "East Forest Dance Fox Spot", "East Forest Portal"], + ("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 Front", "Beneath the Well Main", "Beneath the Well Back"], - ("Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit"): - ["Dark Tomb Entry Point", "Dark Tomb Main", "Dark Tomb Dark Exit"], + ("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 @@ -960,9 +1027,11 @@ class Hint(IntEnum): ["West Garden", "West Garden Laurels Exit", "West Garden after Boss", "West Garden Hero's Grave", "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 Statue", "Ruined Atoll Ladder Tops", "Frog Eye Entrance", "Ruined Atoll Ladder Tops"): ["Ruined Atoll", "Ruined Atoll Lower Entry Area", "Ruined Atoll Frog Mouth", "Ruined Atoll Portal", - "Ruined Atoll Statue"], + "Ruined Atoll Statue", "Ruined Atoll Ladder Tops", "Frog Eye Entrance", "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", "Frog's Domain Back"], ("Library Exterior Ladder", "Library Exterior Tree"): @@ -1008,10 +1077,10 @@ class Hint(IntEnum): ["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", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", "Back of Swamp", - "Back of Swamp Laurels Area", "Swamp Hero's Grave"): - ["Swamp", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", "Back of Swamp", - "Back of Swamp Laurels Area", "Swamp Hero's Grave"], + ("Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", + "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Ledge Under Cathedral Door"): + ["Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", + "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Ledge Under Cathedral Door"], ("Cathedral Gauntlet Checkpoint",): ["Cathedral Gauntlet Checkpoint", "Cathedral Gauntlet Exit", "Cathedral Gauntlet"], ("Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index a7d0543c3f17..d5886ef44dc8 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1,8 +1,9 @@ -from typing import Dict, TYPE_CHECKING +from typing import Dict, Set, TYPE_CHECKING from worlds.generic.Rules import set_rule, forbid_item from .rules import has_ability, has_sword, has_stick, has_ice_grapple_logic, has_lantern, has_mask, can_ladder_storage from .er_data import Portal -from BaseClasses import Region +from .options import TunicOptions +from BaseClasses import Region, CollectionState if TYPE_CHECKING: from . import TunicWorld @@ -27,6 +28,27 @@ gold_hexagon = "Gold Questagon" +def has_ladder(ladder: str, state: CollectionState, player: int, options: TunicOptions): + if not options.ladder_rando: + return True + else: + return state.has(ladder, player) + + +def has_ladders(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): + if not options.ladder_rando: + return True + else: + return state.has_all(ladders, player) + + +def has_ladders_any(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): + if not options.ladder_rando: + return True + else: + return state.has_any(ladders, player) + + def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], regions: Dict[str, Region], portal_pairs: Dict[Portal, Portal]) -> None: player = world.player @@ -40,6 +62,13 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld Holy Cross"], rule=lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + regions["Overworld"].connect( + connecting_region=regions["Overworld Beach"], + rule=lambda state: has_ladder("West Overworld Ladders", state, player, options) or state.has(laurels, player)) + regions["Overworld Beach"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: has_ladder("West Overworld Ladders", state, player, options) or state.has(laurels, player)) + regions["Overworld"].connect( connecting_region=regions["Overworld Belltower"], rule=lambda state: state.has(laurels, player)) @@ -51,6 +80,40 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld Ruined Passage Door"], rule=lambda state: state.has(key, player, 2) or (state.has(laurels, player) and options.logic_rules)) + regions["Overworld Ruined Passage Door"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: state.has(laurels, player) and options.logic_rules) + + regions["Overworld"].connect( + connecting_region=regions["After Ruined Passage"], + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + regions["After Ruined Passage"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) + + regions["Overworld"].connect( + connecting_region=regions["Above Ruined Passage"], + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + or state.has(laurels, player)) + regions["Above Ruined Passage"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + or state.has(laurels, player)) + + regions["After Ruined Passage"].connect( + connecting_region=regions["Above Ruined Passage"], + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) + regions["Above Ruined Passage"].connect( + connecting_region=regions["After Ruined Passage"], + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) + + regions["Above Ruined Passage"].connect( + connecting_region=regions["East Overworld"], + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) + regions["East Overworld"].connect( + connecting_region=regions["Above Ruined Passage"], + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld Swamp Upper Entry"], @@ -59,6 +122,82 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld"], rule=lambda state: state.has(laurels, player)) + # todo: check if there's ice grapple logic + regions["Overworld"].connect( + connecting_region=regions["East Overworld"], + rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options)) + regions["East Overworld"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options)) + + regions["East Overworld"].connect( + connecting_region=regions["Overworld at Patrol Cave"]) + regions["Overworld at Patrol Cave"].connect( + connecting_region=regions["East Overworld"], + rule=lambda state: state.has(laurels, player)) + + regions["Overworld at Patrol Cave"].connect( + connecting_region=regions["Overworld above Patrol Cave"], + rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + regions["Overworld above Patrol Cave"].connect( + connecting_region=regions["Overworld at Patrol Cave"], + rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options)) + + regions["Overworld"].connect( + connecting_region=regions["Overworld above Patrol Cave"], + rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options) + or state.has(grapple, player)) + regions["Overworld above Patrol Cave"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options)) + + regions["East Overworld"].connect( + connecting_region=regions["Overworld above Patrol Cave"], + rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + regions["Overworld above Patrol Cave"].connect( + connecting_region=regions["East Overworld"], + rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options)) + + regions["Overworld above Patrol Cave"].connect( + connecting_region=regions["Upper Overworld"], + rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + regions["Upper Overworld"].connect( + connecting_region=regions["Overworld above Patrol Cave"], + rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options) + or state.has(grapple, player)) + + regions["Upper Overworld"].connect( + connecting_region=regions["Overworld above Quarry Entrance"], + rule=lambda state: state.has_any({grapple, laurels}, player)) + regions["Overworld above Quarry Entrance"].connect( + connecting_region=regions["Upper Overworld"], + rule=lambda state: state.has_any({grapple, laurels}, player)) + + regions["Upper Overworld"].connect( + connecting_region=regions["Overworld after Temple Rafters"], + rule=lambda state: has_ladder("Ladder near Temple Rafters", state, player, options)) + regions["Overworld after Temple Rafters"].connect( + connecting_region=regions["Upper Overworld"], + rule=lambda state: has_ladder("Ladder near Temple Rafters", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + + regions["Overworld above Quarry Entrance"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: has_ladder("Ladders near Dark Tomb", state, player, options)) + regions["Overworld"].connect( + connecting_region=regions["Overworld above Quarry Entrance"], + rule=lambda state: has_ladder("Ladders near Dark Tomb", state, player, options)) + + regions["Overworld"].connect( + connecting_region=regions["Overworld Swamp Lower Entry"], + rule=lambda state: has_ladder("Ladder to Swamp", state, player, options)) + regions["Overworld Swamp Lower Entry"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: has_ladder("Ladder to Swamp", state, player, options)) + regions["Overworld"].connect( connecting_region=regions["Overworld Special Shop Entry"], rule=lambda state: state.has(laurels, player)) @@ -109,10 +248,15 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: ice grapple through temple door regions["Overworld"].connect( connecting_region=regions["Overworld Temple Door"], - name="Overworld Temple Door", + name="Overworld to Temple Door", rule=lambda state: state.has_all({"Ring Eastern Bell", "Ring Western Bell"}, player) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) + regions["Overworld Temple Door"].connect( + connecting_region=regions["Overworld above Patrol Cave"], + name="Temple Door to Overworld Grapple", + rule=lambda state: state.has(grapple, player)) + # Overworld side areas regions["Old House Front"].connect( connecting_region=regions["Old House Back"]) @@ -838,6 +982,16 @@ def set_er_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) set_rule(multiworld.get_location("Cathedral - Secret Legend Trophy Chest", player), lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Southwest] Flowers Holy Cross", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [East] Weathervane Holy Cross", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Northeast] Flowers Holy Cross", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Southwest] Haiku Holy Cross", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Northwest] Golden Obelisk Page", player), + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) # Overworld set_rule(multiworld.get_location("Overworld - [Southwest] Grapple Chest Over Walkway", player), diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index de2149492745..20056b058dd0 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -162,6 +162,7 @@ class TunicItemData(NamedTuple): "South Atoll Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), "Frog's Domain Ladders": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), + "West Overworld Ladders": TunicItemData(ItemClassification.progression, 0, 148, "ladders") } fool_tiers: List[List[str]] = [ diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index e0b76b7c87eb..492894594363 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -68,6 +68,12 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: can_reach_east_overworld(state, player, options, ability_unlocks) multiworld.get_entrance("Overworld -> Upper Overworld", player).access_rule = \ lambda state: can_reach_upper_overworld(state, player, options, ability_unlocks) + multiworld.get_entrance("Overworld -> Overworld Beach", player).access_rule = \ + lambda state: state.has_any({"West Overworld Ladders", laurels}, player) + multiworld.get_entrance("Overworld Beach -> West Garden", player).access_rule = \ + lambda state: state.has(laurels, player) + multiworld.get_entrance("West Garden -> Overworld Beach", player).access_rule = \ + lambda state: state.has(laurels, player) multiworld.get_entrance("Overworld -> East Forest", player).access_rule = \ lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks) multiworld.get_entrance("East Overworld -> East Forest", player).access_rule = \ diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index 83d7243bc5aa..3d652d19d7a1 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -40,25 +40,25 @@ class TunicLocationData(NamedTuple): "Dark Tomb - 2nd Laser Room": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - 1st Laser Room": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - Spike Maze Upper Walkway": TunicLocationData("Dark Tomb", "Dark Tomb Main"), - "Dark Tomb - Skulls Chest": TunicLocationData("Dark Tomb", "Dark Tomb Main", ladder_region="Dark Tomb Front"), + "Dark Tomb - Skulls Chest": TunicLocationData("Dark Tomb", "Dark Tomb Upper", ladder_region="Dark Tomb Front"), "Dark Tomb - Spike Maze Near Stairs": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - 1st Laser Room Obscured": TunicLocationData("Dark Tomb", "Dark Tomb Main"), - "Guardhouse 2 - Upper Floor": TunicLocationData("East Forest", "Guard House 2"), - "Guardhouse 2 - Bottom Floor Secret": TunicLocationData("East Forest", "Guard House 2", ladder_region="Lower Forest"), + "Guardhouse 2 - Upper Floor": TunicLocationData("East Forest", "Guard House 2 Upper"), + "Guardhouse 2 - Bottom Floor Secret": TunicLocationData("East Forest", "Guard House 2 Lower", ladder_region="Lower Forest"), "Guardhouse 1 - Upper Floor Obscured": TunicLocationData("East Forest", "Guard House 1 East"), "Guardhouse 1 - Upper Floor": TunicLocationData("East Forest", "Guard House 1 East"), "East Forest - Dancing Fox Spirit Holy Cross": TunicLocationData("East Forest", "East Forest Dance Fox Spot", location_group="holy cross"), - "East Forest - Golden Obelisk Holy Cross": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest", location_group="holy cross"), + "East Forest - Golden Obelisk Holy Cross": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest", location_group="holy cross"), "East Forest - Ice Rod Grapple Chest": TunicLocationData("East Forest", "East Forest"), "East Forest - Above Save Point": TunicLocationData("East Forest", "East Forest"), "East Forest - Above Save Point Obscured": TunicLocationData("East Forest", "East Forest"), "East Forest - From Guardhouse 1 Chest": TunicLocationData("East Forest", "East Forest Dance Fox Spot"), "East Forest - Near Save Point": TunicLocationData("East Forest", "East Forest"), - "East Forest - Beneath Spider Chest": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest"), + "East Forest - Beneath Spider Chest": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest"), "East Forest - Near Telescope": TunicLocationData("East Forest", "East Forest"), - "East Forest - Spider Chest": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest"), - "East Forest - Lower Dash Chest": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest"), - "East Forest - Lower Grapple Chest": TunicLocationData("East Forest", "East Forest", ladder_region="Lower Forest"), + "East Forest - Spider Chest": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest"), + "East Forest - Lower Dash Chest": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest"), + "East Forest - Lower Grapple Chest": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest"), "East Forest - Bombable Wall": TunicLocationData("East Forest", "East Forest"), "East Forest - Page On Teleporter": TunicLocationData("East Forest", "East Forest"), "Forest Belltower - Near Save Point": TunicLocationData("East Forest", "Forest Belltower Lower"), @@ -119,46 +119,46 @@ class TunicLocationData(NamedTuple): "Fortress Courtyard - Below Walkway": TunicLocationData("Overworld", "Fortress Exterior from Overworld", ladder_region="East Overworld"), "Fortress Courtyard - Page Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave", ladder_region="East Overworld"), "West Furnace - Lantern Pickup": TunicLocationData("Overworld", "Furnace Fuse", ladder_region="Beneath the Well Back"), - "Maze Cave - Maze Room Chest": TunicLocationData("Overworld", "Maze Cave"), + "Maze Cave - Maze Room Chest": TunicLocationData("Overworld", "Maze Cave", ladder_region="Overworld Beach"), "Old House - Normal Chest": TunicLocationData("Overworld", "Old House Front"), "Old House - Shield Pickup": TunicLocationData("Overworld", "Old House Front"), "Overworld - [West] Obscured Behind Windmill": TunicLocationData("Overworld", "Overworld"), - "Overworld - [South] Beach Chest": TunicLocationData("Overworld", "Overworld"), + "Overworld - [South] Beach Chest": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), "Overworld - [West] Obscured Near Well": TunicLocationData("Overworld", "Overworld"), "Overworld - [Central] Bombable Wall": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Chest Near Turret": TunicLocationData("Overworld", "Overworld"), - "Overworld - [East] Chest Near Pots": TunicLocationData("Overworld", "Overworld", ladder_region="East Overworld"), - "Overworld - [Northwest] Chest Near Golden Obelisk": TunicLocationData("Overworld", "Overworld"), + "Overworld - [East] Chest Near Pots": TunicLocationData("Overworld", "East Overworld", ladder_region="East Overworld"), + "Overworld - [Northwest] Chest Near Golden Obelisk": TunicLocationData("Overworld", "Overworld above Quarry Entrance"), "Overworld - [Southwest] South Chest Near Guard": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Southwest] West Beach Guarded By Turret": TunicLocationData("Overworld", "Overworld"), + "Overworld - [Southwest] West Beach Guarded By Turret": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), "Overworld - [Southwest] Chest Guarded By Turret": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Shadowy Corner Chest": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Obscured In Tunnel To Beach": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Grapple Chest Over Walkway": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Chest Beneath Quarry Gate": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Southeast] Chest Near Swamp": TunicLocationData("Overworld", "Overworld", ladder_region="Swamp"), - "Overworld - [Southwest] From West Garden": TunicLocationData("Overworld", "Overworld"), - "Overworld - [East] Grapple Chest": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Southwest] West Beach Guarded By Turret 2": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Southwest] Beach Chest Near Flowers": TunicLocationData("Overworld", "Overworld"), + "Overworld - [Southeast] Chest Near Swamp": TunicLocationData("Overworld", "Overworld Swamp Lower Entry", ladder_region="Swamp"), + "Overworld - [Southwest] From West Garden": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), + "Overworld - [East] Grapple Chest": TunicLocationData("Overworld", "Overworld above Patrol Cave"), + "Overworld - [Southwest] West Beach Guarded By Turret 2": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), + "Overworld - [Southwest] Beach Chest Near Flowers": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), "Overworld - [Southwest] Bombable Wall Near Fountain": TunicLocationData("Overworld", "Overworld"), "Overworld - [West] Chest After Bell": TunicLocationData("Overworld", "Overworld Belltower"), "Overworld - [Southwest] Tunnel Guarded By Turret": TunicLocationData("Overworld", "Overworld"), - "Overworld - [East] Between Ladders Near Ruined Passage": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Northeast] Chest Above Patrol Cave": TunicLocationData("Overworld", "Overworld", ladder_region="Upper Overworld"), - "Overworld - [Southwest] Beach Chest Beneath Guard": TunicLocationData("Overworld", "Overworld"), + "Overworld - [East] Between Ladders Near Ruined Passage": TunicLocationData("Overworld", "After Ruined Passage"), + "Overworld - [Northeast] Chest Above Patrol Cave": TunicLocationData("Overworld", "Upper Overworld", ladder_region="Upper Overworld"), + "Overworld - [Southwest] Beach Chest Beneath Guard": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), "Overworld - [Central] Chest Across From Well": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Chest Near Quarry Gate": TunicLocationData("Overworld", "Overworld"), - "Overworld - [East] Chest In Trees": TunicLocationData("Overworld", "Overworld"), + "Overworld - [East] Chest In Trees": TunicLocationData("Overworld", "Above Ruined Passage"), "Overworld - [West] Chest Behind Moss Wall": TunicLocationData("Overworld", "Overworld"), - "Overworld - [South] Beach Page": TunicLocationData("Overworld", "Overworld"), + "Overworld - [South] Beach Page": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), "Overworld - [Southeast] Page on Pillar by Swamp": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Key Pickup": TunicLocationData("Overworld", "Overworld"), "Overworld - [West] Key Pickup": TunicLocationData("Overworld", "Overworld"), - "Overworld - [East] Page Near Secret Shop": TunicLocationData("Overworld", "Overworld", ladder_region="East Overworld"), + "Overworld - [East] Page Near Secret Shop": TunicLocationData("Overworld", "East Overworld", ladder_region="East Overworld"), "Overworld - [Southwest] Fountain Page": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Page on Pillar by Dark Tomb": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Northwest] Fire Wand Pickup": TunicLocationData("Overworld", "Overworld", ladder_region="Upper Overworld"), + "Overworld - [Northwest] Fire Wand Pickup": TunicLocationData("Overworld", "Upper Overworld", ladder_region="Upper Overworld"), "Overworld - [West] Page On Teleporter": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Page By Well": TunicLocationData("Overworld", "Overworld"), "Patrol Cave - Normal Chest": TunicLocationData("Overworld", "Patrol Cave"), @@ -173,7 +173,7 @@ class TunicLocationData(NamedTuple): "Special Shop - Secret Page Pickup": TunicLocationData("Overworld", "Special Shop", ladder_region="East Overworld"), "Stick House - Stick Chest": TunicLocationData("Overworld", "Stick House"), "Sealed Temple - Page Pickup": TunicLocationData("Overworld", "Sealed Temple", ladder_region="Sealed Temple"), - "Hourglass Cave - Hourglass Chest": TunicLocationData("Overworld", "Hourglass Cave"), + "Hourglass Cave - Hourglass Chest": TunicLocationData("Overworld", "Hourglass Cave", ladder_region="Overworld Beach"), "Far Shore - Secret Chest": TunicLocationData("Overworld", "Far Shore"), "Far Shore - Page Pickup": TunicLocationData("Overworld", "Far Shore to Spawn"), "Coins in the Well - 10 Coins": TunicLocationData("Overworld", "Overworld", location_group="well"), @@ -183,26 +183,26 @@ class TunicLocationData(NamedTuple): "Secret Gathering Place - 20 Fairy Reward": TunicLocationData("Overworld", "Secret Gathering Place", location_group="fairies"), "Secret Gathering Place - 10 Fairy Reward": TunicLocationData("Overworld", "Secret Gathering Place", location_group="fairies"), "Overworld - [West] Moss Wall Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), - "Overworld - [Southwest] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), + "Overworld - [Southwest] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Beach", ladder_region="Overworld Beach", location_group="holy cross"), "Overworld - [Southwest] Fountain Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), - "Overworld - [Northeast] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", ladder_region="East Overworld", location_group="holy cross"), - "Overworld - [East] Weathervane Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", ladder_region="East Overworld", location_group="holy cross"), + "Overworld - [Northeast] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "East Overworld", ladder_region="East Overworld", location_group="holy cross"), + "Overworld - [East] Weathervane Holy Cross": TunicLocationData("Overworld Holy Cross", "East Overworld", ladder_region="East Overworld", location_group="holy cross"), "Overworld - [West] Windmill Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), - "Overworld - [Southwest] Haiku Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), + "Overworld - [Southwest] Haiku Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Beach", ladder_region="Overworld Beach", location_group="holy cross"), "Overworld - [West] Windchimes Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), "Overworld - [South] Starting Platform Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), - "Overworld - [Northwest] Golden Obelisk Page": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", ladder_region="Upper Overworld", location_group="holy cross"), + "Overworld - [Northwest] Golden Obelisk Page": TunicLocationData("Overworld Holy Cross", "Upper Overworld", ladder_region="Upper Overworld", location_group="holy cross"), "Old House - Holy Cross Door Page": TunicLocationData("Overworld Holy Cross", "Old House Back", location_group="holy cross"), "Cube Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Cube Cave", location_group="holy cross"), "Southeast Cross Door - Chest 3": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), "Southeast Cross Door - Chest 2": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), "Southeast Cross Door - Chest 1": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), - "Maze Cave - Maze Room Holy Cross": TunicLocationData("Overworld Holy Cross", "Maze Cave", "holy cross"), + "Maze Cave - Maze Room Holy Cross": TunicLocationData("Overworld Holy Cross", "Maze Cave", ladder_region="Overworld Beach", location_group="holy cross"), "Caustic Light Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Caustic Light Cave", ladder_region="Swamp", location_group="holy cross"), "Old House - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Old House Front", "holy cross"), "Patrol Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Patrol Cave", "holy cross"), "Ruined Passage - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Ruined Passage", ladder_region="Overworld", location_group="holy cross"), - "Hourglass Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Hourglass Cave", "holy cross"), + "Hourglass Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Hourglass Cave Tower", ladder_region="Overworld Beach", location_group="holy cross"), "Sealed Temple - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Sealed Temple", ladder_region="Sealed Temple", location_group="holy cross"), "Fountain Cross Door - Page Pickup": TunicLocationData("Overworld Holy Cross", "Fountain Cross Room", "holy cross"), "Secret Gathering Place - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Secret Gathering Place", location_group="holy cross"), @@ -249,13 +249,13 @@ class TunicLocationData(NamedTuple): "Rooted Ziggurat Lower - Guarded By Double Turrets 2": TunicLocationData("Rooted Ziggurat", "Rooted Ziggurat Lower Front"), "Rooted Ziggurat Lower - Hexagon Blue": TunicLocationData("Rooted Ziggurat", "Rooted Ziggurat Lower Back"), "Ruined Atoll - [West] Near Kevin Block": TunicLocationData("Ruined Atoll", "Ruined Atoll"), - "Ruined Atoll - [South] Upper Floor On Power Line": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - [South] Upper Floor On Power Line": TunicLocationData("Ruined Atoll", "Ruined Atoll Ladder Tops"), "Ruined Atoll - [South] Chest Near Big Crabs": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [North] Guarded By Bird": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [Northeast] Chest Beneath Brick Walkway": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [Northwest] Bombable Wall": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [North] Obscured Beneath Bridge": TunicLocationData("Ruined Atoll", "Ruined Atoll"), - "Ruined Atoll - [South] Upper Floor On Bricks": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - [South] Upper Floor On Bricks": TunicLocationData("Ruined Atoll", "Ruined Atoll Ladder Tops"), "Ruined Atoll - [South] Near Birds": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [Northwest] Behind Envoy": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [Southwest] Obscured Behind Fuse": TunicLocationData("Ruined Atoll", "Ruined Atoll"), @@ -263,32 +263,32 @@ class TunicLocationData(NamedTuple): "Ruined Atoll - [North] From Lower Overworld Entrance": TunicLocationData("Ruined Atoll", "Ruined Atoll Lower Entry Area"), "Ruined Atoll - [East] Locked Room Lower Chest": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [Northeast] Chest On Brick Walkway": TunicLocationData("Ruined Atoll", "Ruined Atoll"), - "Ruined Atoll - [Southeast] Chest Near Fuse": TunicLocationData("Ruined Atoll", "Ruined Atoll"), + "Ruined Atoll - [Southeast] Chest Near Fuse": TunicLocationData("Ruined Atoll", "Ruined Atoll Ladder Tops"), "Ruined Atoll - [Northeast] Key Pickup": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Cathedral Gauntlet - Gauntlet Reward": TunicLocationData("Swamp", "Cathedral Gauntlet", ladder_region="Back of Swamp"), "Cathedral - Secret Legend Trophy Chest": TunicLocationData("Swamp", "Cathedral Secret Legend Room", ladder_region="Swamp Middle"), - "Swamp - [Upper Graveyard] Obscured Behind Hill": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), - "Swamp - [South Graveyard] 4 Orange Skulls": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Central] Near Ramps Up": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), - "Swamp - [Upper Graveyard] Near Shield Fleemers": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), - "Swamp - [South Graveyard] Obscured Behind Ridge": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), - "Swamp - [South Graveyard] Obscured Beneath Telescope": TunicLocationData("Swamp", "Swamp"), + "Swamp - [Upper Graveyard] Obscured Behind Hill": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [South Graveyard] 4 Orange Skulls": TunicLocationData("Swamp", "Swamp Front"), + "Swamp - [Central] Near Ramps Up": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [Upper Graveyard] Near Shield Fleemers": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [South Graveyard] Obscured Behind Ridge": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [South Graveyard] Obscured Beneath Telescope": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [Entrance] Above Entryway": TunicLocationData("Swamp", "Back of Swamp Laurels Area", ladder_region="Back of Swamp"), - "Swamp - [Central] South Secret Passage": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), - "Swamp - [South Graveyard] Upper Walkway On Pedestal": TunicLocationData("Swamp", "Swamp"), - "Swamp - [South Graveyard] Guarded By Tentacles": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Upper Graveyard] Near Telescope": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), - "Swamp - [Outside Cathedral] Near Moonlight Bridge Door": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), - "Swamp - [Entrance] Obscured Inside Watchtower": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Entrance] South Near Fence": TunicLocationData("Swamp", "Swamp"), - "Swamp - [South Graveyard] Guarded By Big Skeleton": TunicLocationData("Swamp", "Swamp"), - "Swamp - [South Graveyard] Chest Near Graves": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Entrance] North Small Island": TunicLocationData("Swamp", "Swamp"), + "Swamp - [Central] South Secret Passage": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [South Graveyard] Upper Walkway On Pedestal": TunicLocationData("Swamp", "Swamp Front"), + "Swamp - [South Graveyard] Guarded By Tentacles": TunicLocationData("Swamp", "Swamp Front"), + "Swamp - [Upper Graveyard] Near Telescope": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [Outside Cathedral] Near Moonlight Bridge Door": TunicLocationData("Swamp", "Swamp Ledge Under Cathedral Door", ladder_region="Swamp Middle"), + "Swamp - [Entrance] Obscured Inside Watchtower": TunicLocationData("Swamp", "Swamp Front"), + "Swamp - [Entrance] South Near Fence": TunicLocationData("Swamp", "Swamp Front"), + "Swamp - [South Graveyard] Guarded By Big Skeleton": TunicLocationData("Swamp", "Swamp Front"), + "Swamp - [South Graveyard] Chest Near Graves": TunicLocationData("Swamp", "Swamp Front"), + "Swamp - [Entrance] North Small Island": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [Outside Cathedral] Obscured Behind Memorial": TunicLocationData("Swamp", "Back of Swamp", ladder_region="Back of Swamp"), - "Swamp - [Central] Obscured Behind Northern Mountain": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), - "Swamp - [South Graveyard] Upper Walkway Dash Chest": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), - "Swamp - [South Graveyard] Above Big Skeleton": TunicLocationData("Swamp", "Swamp"), - "Swamp - [Central] Beneath Memorial": TunicLocationData("Swamp", "Swamp", ladder_region="Swamp Middle"), + "Swamp - [Central] Obscured Behind Northern Mountain": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [South Graveyard] Upper Walkway Dash Chest": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [South Graveyard] Above Big Skeleton": TunicLocationData("Swamp", "Swamp Front"), + "Swamp - [Central] Beneath Memorial": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), "Hero's Grave - Feathers Relic": TunicLocationData("Swamp", "Hero Relic - Swamp"), "West Furnace - Chest": TunicLocationData("West Garden", "Furnace Walking Path"), "Overworld - [West] Near West Garden Entrance": TunicLocationData("West Garden", "Overworld to West Garden from Furnace"), diff --git a/worlds/tunic/regions.py b/worlds/tunic/regions.py index b5e2fb7c917b..dd9878865e8f 100644 --- a/worlds/tunic/regions.py +++ b/worlds/tunic/regions.py @@ -29,17 +29,18 @@ "Menu": {"Overworld"}, "Overworld": {"Dark Tomb Front", "West Garden", "Ruined Atoll", "Beneath the Well", "Beneath the Well Back", "Quarry", "Swamp", "Back of Swamp", "Spirit Arena", "Sealed Temple", "East Overworld", - "Upper Overworld", "Overworld Holy Cross", "East Forest"}, + "Upper Overworld", "Overworld Holy Cross", "East Forest", "Overworld Beach"}, "Overworld Holy Cross": set(), "East Forest": {"Lower Forest"}, "Lower Forest": set(), "East Overworld": {"East Forest", "Eastern Vault Fortress", "Beneath the Vault"}, "Upper Overworld": {"Quarry Back", "Sealed Temple"}, + "Overworld Beach": {"West Garden"}, "Dark Tomb Front": {"Dark Tomb"}, "Dark Tomb": {"West Garden"}, "Beneath the Well": {"Beneath the Well Back"}, "Beneath the Well Back": {"Beneath the Well"}, - "West Garden": set(), + "West Garden": {"Overworld Beach"}, "Ruined Atoll": {"Frog's Domain", "Library"}, "Frog's Domain": set(), "Library": set(), From 51083690b0af9e07fd553d0d2cb903cd7f3ffd81 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 2 Mar 2024 12:22:03 -0500 Subject: [PATCH 10/82] Finished with ER except for ladder storage rules --- worlds/tunic/er_data.py | 84 ++++++++-------- worlds/tunic/er_rules.py | 189 ++++++++++++++++++++++++++++++----- worlds/tunic/er_scripts.py | 2 +- worlds/tunic/items.py | 2 +- worlds/tunic/ladder_rules.py | 10 +- 5 files changed, 212 insertions(+), 75 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 5edaabd62adf..9fb4509c3232 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -166,7 +166,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th Portal(name="Temple Door Exit", region="Sealed Temple", destination="Overworld Redux_main"), - Portal(name="Well Ladder Exit", region="Beneath Well the Ladder Exit", + Portal(name="Well Ladder Exit", region="Beneath the Well Ladder Exit", destination="Overworld Redux_entrance"), Portal(name="Well to Well Boss", region="Beneath the Well Back", destination="Sewer_Boss_"), @@ -213,12 +213,12 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Transit_teleporter_atoll"), Portal(name="Atoll Statue Teleporter", region="Ruined Atoll Statue", destination="Library Exterior_"), - Portal(name="Frog Stairs Eye Entrance", region="Ruined Atoll Frog Eye Entrance", + Portal(name="Frog Stairs Eye Entrance", region="Ruined Atoll Frog Eye", destination="Frog Stairs_eye"), Portal(name="Frog Stairs Mouth Entrance", region="Ruined Atoll Frog Mouth", destination="Frog Stairs_mouth"), - Portal(name="Frog Stairs Eye Exit", region="Frog Eye Exit", + Portal(name="Frog Stairs Eye Exit", region="Frog Stairs Eye Exit", destination="Atoll Redux_eye"), Portal(name="Frog Stairs Mouth Exit", region="Frog Stairs Upper", destination="Atoll Redux_mouth"), @@ -533,6 +533,7 @@ class Hint(IntEnum): "Overworld": RegionInfo("Overworld Redux"), "Overworld Holy Cross": RegionInfo("Fake", dead_end=DeadEnd.all_cats), "Overworld Belltower": RegionInfo("Overworld Redux"), # the area with the belltower and chest + "Overworld Belltower at Bell": RegionInfo("Overworld Redux"), # the belltower itself, being able to ring it "Overworld Swamp Upper Entry": RegionInfo("Overworld Redux"), # upper swamp entry spot "Overworld Swamp Lower Entry": RegionInfo("Overworld Redux"), # lower swamp entrance, rotating lights "After Ruined Passage": RegionInfo("Overworld Redux"), # just the door and chest @@ -546,12 +547,11 @@ class Hint(IntEnum): "Overworld above Patrol Cave": RegionInfo("Overworld Redux"), # where the hook is, and one ladder up from patrol "Overworld at Patrol Cave": RegionInfo("Overworld Redux"), # right at the patrol cave entrance "Overworld West Garden Laurels Entry": RegionInfo("Overworld Redux"), # west garden laurels entry - # todo: continue from here - "Overworld to West Garden Upper": RegionInfo("Overworld Redux"), # usually leads to garden knight # todo + "Overworld to West Garden Upper": RegionInfo("Overworld Redux"), # usually leads to garden knight "Overworld to West Garden from Furnace": RegionInfo("Overworld Redux", hint=Hint.region), - "Overworld Well Ladder": RegionInfo("Overworld Redux"), # just the ladder entrance # todo - "Overworld Beach": RegionInfo("Overworld Redux"), # todo - "Overworld to Atoll Upper": RegionInfo("Overworld Redux"), # todo + "Overworld Well Ladder": RegionInfo("Overworld Redux"), # just the ladder entrance + "Overworld Beach": RegionInfo("Overworld Redux"), + "Overworld to Atoll Upper": RegionInfo("Overworld Redux"), "Overworld Well to Furnace Rail": RegionInfo("Overworld Redux"), # the tiny rail passageway "Overworld Ruined Passage Door": RegionInfo("Overworld Redux"), # the small space betweeen the door and the portal "Overworld Old House Door": RegionInfo("Overworld Redux"), # the too-small space between the door and the portal @@ -579,8 +579,8 @@ class Hint(IntEnum): "Cube Cave": RegionInfo("CubeRoom", dead_end=DeadEnd.all_cats, hint=Hint.region), "Southeast Cross Room": RegionInfo("EastFiligreeCache", dead_end=DeadEnd.all_cats, hint=Hint.region), "Fountain Cross Room": RegionInfo("Town_FiligreeRoom", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Hourglass Cave": RegionInfo("Town Basement", dead_end=DeadEnd.all_cats), # todo - "Hourglass Cave Tower": RegionInfo("Town Basement", dead_end=DeadEnd.all_cats), # top of the tower # todo + "Hourglass Cave": RegionInfo("Town Basement", dead_end=DeadEnd.all_cats), + "Hourglass Cave Tower": RegionInfo("Town Basement", dead_end=DeadEnd.all_cats), # top of the tower "Sealed Temple": RegionInfo("Temple", hint=Hint.scene), "Sealed Temple Rafters": RegionInfo("Temple", hint=Hint.scene), "Forest Belltower Upper": RegionInfo("Forest Belltower", hint=Hint.region), @@ -589,26 +589,26 @@ class Hint(IntEnum): "East Forest": RegionInfo("East Forest Redux"), "East Forest Dance Fox Spot": RegionInfo("East Forest Redux"), "East Forest Portal": RegionInfo("East Forest Redux"), - "Lower Forest": RegionInfo("East Forest Redux"), # bottom of the forest # todo + "Lower Forest": RegionInfo("East Forest Redux"), # bottom of the forest "Guard House 1 East": RegionInfo("East Forest Redux Laddercave"), "Guard House 1 West": RegionInfo("East Forest Redux Laddercave"), - "Guard House 2 Upper": RegionInfo("East Forest Redux Interior"), # todo - "Guard House 2 Lower": RegionInfo("East Forest Redux Interior"), # todo + "Guard House 2 Upper": RegionInfo("East Forest Redux Interior"), + "Guard House 2 Lower": RegionInfo("East Forest Redux Interior"), "Forest Boss Room": RegionInfo("Forest Boss Room"), "Forest Grave Path Main": RegionInfo("Sword Access"), "Forest Grave Path Upper": RegionInfo("Sword Access"), "Forest Grave Path by Grave": RegionInfo("Sword Access"), "Forest Hero's Grave": RegionInfo("Sword Access"), "Dark Tomb Entry Point": RegionInfo("Crypt Redux"), # both upper exits - "Dark Tomb Upper": RegionInfo("Crypt Redux"), # the part with the casket and the top of the ladder # todo + "Dark Tomb Upper": RegionInfo("Crypt Redux"), # the part with the casket and the top of the ladder "Dark Tomb Main": RegionInfo("Crypt Redux"), "Dark Tomb Dark Exit": RegionInfo("Crypt Redux"), "Dark Tomb Checkpoint": RegionInfo("Sewer_Boss"), # can laurels backwards "Well Boss": RegionInfo("Sewer_Boss"), # can walk through (with bombs at least) - "Beneath the Well Ladder Exit": RegionInfo("Sewer"), # just the ladder # todo - "Beneath the Well Front": RegionInfo("Sewer"), # the front, to separate it from the weapon requirement in the mid # todo - "Beneath the Well Main": RegionInfo("Sewer"), # the main section of it, requires a weapon # todo - "Beneath the Well Back": RegionInfo("Sewer"), # the back two portals, and all 4 upper chests # todo + "Beneath the Well Ladder Exit": RegionInfo("Sewer"), # just the ladder + "Beneath the Well Front": RegionInfo("Sewer"), # the front, to separate it from the weapon requirement in the mid + "Beneath the Well Main": RegionInfo("Sewer"), # the main section of it, requires a weapon + "Beneath the Well Back": RegionInfo("Sewer"), # the back two portals, and all 4 upper chests "West Garden": RegionInfo("Archipelagos Redux"), "Magic Dagger House": RegionInfo("archipelagos_house", dead_end=DeadEnd.all_cats, hint=Hint.region), "West Garden Portal": RegionInfo("Archipelagos Redux", dead_end=DeadEnd.restricted), @@ -618,15 +618,15 @@ class Hint(IntEnum): "West Garden Hero's Grave": RegionInfo("Archipelagos Redux"), "Ruined Atoll": RegionInfo("Atoll Redux"), "Ruined Atoll Lower Entry Area": RegionInfo("Atoll Redux"), - "Ruined Atoll Ladder Tops": RegionInfo("Atoll Redux"), # at the top of the 5 ladders in south Atoll # todo + "Ruined Atoll Ladder Tops": RegionInfo("Atoll Redux"), # at the top of the 5 ladders in south Atoll "Ruined Atoll Frog Mouth": RegionInfo("Atoll Redux"), + "Ruined Atoll Frog Eye": RegionInfo("Atoll Redux"), "Ruined Atoll Portal": RegionInfo("Atoll Redux"), "Ruined Atoll Statue": RegionInfo("Atoll Redux"), - "Frog Eye Entrance": RegionInfo("Atoll Redux"), # todo - "Frog Eye Exit": RegionInfo("Frog Stairs"), # todo - "Frog Stairs Upper": RegionInfo("Frog Stairs"), # todo - "Frog Stairs Lower": RegionInfo("Frog Stairs"), # todo - "Frog Stairs to Frog's Domain": RegionInfo("Frog Stairs"), # todo + "Frog Stairs Eye Exit": RegionInfo("Frog Stairs"), + "Frog Stairs Upper": RegionInfo("Frog Stairs"), + "Frog Stairs Lower": RegionInfo("Frog Stairs"), + "Frog Stairs to Frog's Domain": RegionInfo("Frog Stairs"), "Frog's Domain": RegionInfo("frog cave main", hint=Hint.region), "Frog's Domain Back": RegionInfo("frog cave main", hint=Hint.scene), "Library Exterior Tree": RegionInfo("Library Exterior"), @@ -682,11 +682,11 @@ class Hint(IntEnum): "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"), - "Swamp Front": RegionInfo("Swamp Redux 2"), # from the main entry to the top of the ladder after south # todo - "Swamp Mid": RegionInfo("Swamp Redux 2"), # from the bottom of the ladder to the cathedral door # todo - "Swamp Ledge Under Cathedral Door": RegionInfo("Swamp Redux 2"), # the ledge with the chest and secret door # todo - "Swamp to Cathedral Treasure Room": RegionInfo("Swamp Redux 2"), # just the door # todo - "Swamp to Cathedral Main Entrance": RegionInfo("Swamp Redux 2"), # just the door # todo + "Swamp Front": RegionInfo("Swamp Redux 2"), # from the main entry to the top of the ladder after south + "Swamp Mid": RegionInfo("Swamp Redux 2"), # from the bottom of the ladder to the cathedral door + "Swamp Ledge under Cathedral Door": RegionInfo("Swamp Redux 2"), # the ledge with the chest and secret door + "Swamp to Cathedral Treasure Room": RegionInfo("Swamp Redux 2"), # just the door + "Swamp to Cathedral Main Entrance": RegionInfo("Swamp Redux 2"), # just the door "Back of Swamp": RegionInfo("Swamp Redux 2"), # the area with hero grave and gauntlet entrance "Swamp Hero's Grave": RegionInfo("Swamp Redux 2"), "Back of Swamp Laurels Area": RegionInfo("Swamp Redux 2"), # the spots you need laurels to traverse @@ -805,9 +805,9 @@ class Hint(IntEnum): ["West Garden", "West Garden Laurels Exit", "West Garden after Boss", "West Garden Hero's Grave"], ("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", "Frog Eye Entrance", "Ruined Atoll Ladder Tops"): + "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", "Frog Eye Entrance", "Ruined Atoll Ladder Tops"], + "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",): @@ -854,9 +854,9 @@ class Hint(IntEnum): ["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 Ledge under Cathedral Door"): ["Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", - "Swamp Ledge Under Cathedral Door"], + "Swamp Ledge under Cathedral Door"], ("Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave"): ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave"], ("Cathedral Gauntlet Checkpoint",): @@ -914,9 +914,9 @@ class Hint(IntEnum): ["West Garden", "West Garden Laurels Exit", "West Garden after Boss", "West Garden Hero's Grave", "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", "Frog Eye Entrance", "Ruined Atoll Ladder Tops"): + "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", "Frog Eye Entrance", "Ruined Atoll Ladder Tops"], + "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",): @@ -962,12 +962,12 @@ class Hint(IntEnum): ("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", - "Swamp Ledge Under Cathedral Door"): + "Swamp Ledge under Cathedral Door"): ["Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", - "Swamp Ledge Under Cathedral Door"], + "Swamp Ledge under Cathedral Door"], ("Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave"): ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Front", "Swamp Mid", - "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", "Swamp Ledge Under Cathedral Door"], + "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", "Swamp Ledge under Cathedral Door"], ("Cathedral Gauntlet Checkpoint",): ["Cathedral Gauntlet Checkpoint", "Cathedral Gauntlet Exit", "Cathedral Gauntlet"], ("Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", @@ -1027,9 +1027,9 @@ class Hint(IntEnum): ["West Garden", "West Garden Laurels Exit", "West Garden after Boss", "West Garden Hero's Grave", "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", "Frog Eye Entrance", "Ruined Atoll Ladder Tops"): + "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", "Frog Eye Entrance", "Ruined Atoll Ladder Tops"], + "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",): @@ -1078,9 +1078,9 @@ class Hint(IntEnum): ("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", - "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Ledge Under Cathedral Door"): + "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Ledge under Cathedral Door"): ["Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", - "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Ledge Under Cathedral Door"], + "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Ledge under Cathedral Door"], ("Cathedral Gauntlet Checkpoint",): ["Cathedral Gauntlet Checkpoint", "Cathedral Gauntlet Exit", "Cathedral Gauntlet"], ("Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index d5886ef44dc8..2d350ebc69f7 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -69,12 +69,49 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld"], rule=lambda state: has_ladder("West Overworld Ladders", state, player, options) or state.has(laurels, player)) + regions["Overworld Beach"].connect( + connecting_region=regions["Overworld West Garden Laurels Entry"], + rule=lambda state: state.has(laurels, player)) + regions["Overworld West Garden Laurels Entry"].connect( + connecting_region=regions["Overworld Beach"], + rule=lambda state: state.has(laurels, player)) + + regions["Overworld Beach"].connect( + connecting_region=regions["Overworld to Atoll Upper"], + rule=lambda state: has_ladder("Ladder to Ruined Atoll", state, player, options)) + regions["Overworld to Atoll Upper"].connect( + connecting_region=regions["Overworld Beach"], + rule=lambda state: has_ladder("Ladder to Ruined Atoll", state, player, options)) + + regions["Overworld"].connect( + connecting_region=regions["Overworld to Atoll Upper"], + rule=lambda state: state.has(laurels, player)) + regions["Overworld to Atoll Upper"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: state.has_any({laurels, grapple}, player)) + regions["Overworld"].connect( connecting_region=regions["Overworld Belltower"], rule=lambda state: state.has(laurels, player)) regions["Overworld Belltower"].connect( connecting_region=regions["Overworld"]) + regions["Overworld Belltower"].connect( + connecting_region=regions["Overworld to West Garden Upper"], + rule=lambda state: has_ladder("Ladders to West Belltower", state, player, options)) + regions["Overworld to West Garden Upper"].connect( + connecting_region=regions["Overworld Belltower"], + rule=lambda state: has_ladder("Ladders to West Belltower", state, player, options)) + + regions["Overworld Belltower"].connect( + connecting_region=regions["Overworld Belltower at Bell"], + rule=lambda state: has_ladder("Ladders to West Belltower", state, player, options)) + + # long dong, do not make a reverse connection here or to belltower + regions["Overworld above Patrol Cave"].connect( + connecting_region=regions["Overworld Belltower at Bell"], + rule=lambda state: options.logic_rules and state.has(fire_wand, player)) + # nmg: can laurels through the ruined passage door regions["Overworld"].connect( connecting_region=regions["Overworld Ruined Passage Door"], @@ -115,17 +152,26 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Above Ruined Passage"], rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) - regions["Overworld"].connect( - connecting_region=regions["Overworld Swamp Upper Entry"], - rule=lambda state: state.has(laurels, player)) - regions["Overworld Swamp Upper Entry"].connect( - connecting_region=regions["Overworld"], + # nmg: ice grapple the slimes, works both ways consistently + regions["East Overworld"].connect( + connecting_region=regions["After Ruined Passage"], + rule=lambda state: has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + regions["After Ruined Passage"].connect( + connecting_region=regions["East Overworld"], + rule=lambda state: has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + + regions["East Overworld"].connect( + connecting_region=regions["Above Ruined Passage"], rule=lambda state: state.has(laurels, player)) + regions["Above Ruined Passage"].connect( + connecting_region=regions["East Overworld"], + rule=lambda state: state.has(laurels, player) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) - # todo: check if there's ice grapple logic regions["Overworld"].connect( connecting_region=regions["East Overworld"], - rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options)) + rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["East Overworld"].connect( connecting_region=regions["Overworld"], rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options)) @@ -191,6 +237,13 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld above Quarry Entrance"], rule=lambda state: has_ladder("Ladders near Dark Tomb", state, player, options)) + regions["Overworld"].connect( + connecting_region=regions["Overworld Swamp Upper Entry"], + rule=lambda state: state.has(laurels, player)) + regions["Overworld Swamp Upper Entry"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: state.has(laurels, player)) + regions["Overworld"].connect( connecting_region=regions["Overworld Swamp Lower Entry"], rule=lambda state: has_ladder("Ladder to Swamp", state, player, options)) @@ -206,11 +259,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re rule=lambda state: state.has(laurels, player)) regions["Overworld"].connect( - connecting_region=regions["Overworld West Garden Laurels Entry"], - rule=lambda state: state.has(laurels, player)) - regions["Overworld West Garden Laurels Entry"].connect( - connecting_region=regions["Overworld"], - rule=lambda state: state.has(laurels, player)) + connecting_region=regions["Overworld Well Ladder"], + rule=lambda state: has_ladder("Ladder to Well", state, player, options)) + regions["Overworld Well Ladder"].connect( + connecting_region=regions["Overworld"]) # nmg: can ice grapple through the door regions["Overworld"].connect( @@ -292,6 +344,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Furnace Fuse"], rule=lambda state: state.has(laurels, player)) + regions["Hourglass Cave"].connect( + connecting_region=regions["Hourglass Cave Tower"], + rule=lambda state: has_ladder("Hourglass Cave Ladders", state, player, options)) + # East Forest regions["Forest Belltower Upper"].connect( connecting_region=regions["Forest Belltower Main"]) @@ -315,12 +371,28 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["East Forest Portal"].connect( connecting_region=regions["East Forest"]) + regions["East Forest"].connect( + connecting_region=regions["Lower Forest"], + rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options) + or (state.has_all({grapple, fire_wand, ice_dagger}, player) # do ice slime, then go to the lower hook + and has_ability(state, player, icebolt, options, ability_unlocks))) + regions["Lower Forest"].connect( + connecting_region=regions["East Forest"], + rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options)) + regions["Guard House 1 East"].connect( connecting_region=regions["Guard House 1 West"]) regions["Guard House 1 West"].connect( connecting_region=regions["Guard House 1 East"], rule=lambda state: state.has(laurels, player)) + regions["Guard House 2 Upper"].connect( + connecting_region=regions["Guard House 2 Lower"], + rule=lambda state: has_ladder("Lower Forest Ladders", state, player, options)) + regions["Guard House 2 Lower"].connect( + connecting_region=regions["Guard House 2 Upper"], + rule=lambda state: has_ladder("Lower Forest Ladders", state, player, options)) + # nmg: ice grapple from upper grave path exit to the rest of it regions["Forest Grave Path Upper"].connect( connecting_region=regions["Forest Grave Path Main"], @@ -345,6 +417,14 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Forest Grave Path by Grave"]) # Beneath the Well and Dark Tomb + # don't need the ladder when entering at the ladder spot + regions["Beneath the Well Ladder Exit"].connect( + connecting_region=regions["Beneath the Well Front"], + rule=lambda state: has_ladder("Ladder to Well", state, player, options)) + regions["Beneath the Well Front"].connect( + connecting_region=regions["Beneath the Well Ladder Exit"], + rule=lambda state: has_ladder("Ladder to Well", state, player, options)) + regions["Beneath the Well Front"].connect( connecting_region=regions["Beneath the Well Main"], rule=lambda state: has_stick(state, player) or state.has(fire_wand, player)) @@ -352,12 +432,13 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Beneath the Well Front"], rule=lambda state: has_stick(state, player) or state.has(fire_wand, player)) - regions["Beneath the Well Back"].connect( - connecting_region=regions["Beneath the Well Main"], - rule=lambda state: has_stick(state, player) or state.has(fire_wand, player)) regions["Beneath the Well Main"].connect( connecting_region=regions["Beneath the Well Back"], - rule=lambda state: has_stick(state, player) or state.has(fire_wand, player)) + rule=lambda state: has_ladder("Well Back Ladder", state, player, options)) + regions["Beneath the Well Back"].connect( + connecting_region=regions["Beneath the Well Main"], + rule=lambda state: has_ladder("Well Back Ladder", state, player, options) + and (has_stick(state, player) or state.has(fire_wand, player))) regions["Well Boss"].connect( connecting_region=regions["Dark Tomb Checkpoint"]) @@ -367,15 +448,20 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re rule=lambda state: state.has(laurels, player) and options.logic_rules) regions["Dark Tomb Entry Point"].connect( - connecting_region=regions["Dark Tomb Main"], + connecting_region=regions["Dark Tomb Upper"], rule=lambda state: has_lantern(state, player, options)) + regions["Dark Tomb Upper"].connect( + connecting_region=regions["Dark Tomb Entry Point"]) + + regions["Dark Tomb Upper"].connect( + connecting_region=regions["Dark Tomb Main"], + rule=lambda state: has_ladder("Dark Tomb Ladder", state, player, options)) regions["Dark Tomb Main"].connect( - connecting_region=regions["Dark Tomb Entry Point"], - rule=lambda state: has_lantern(state, player, options)) + connecting_region=regions["Dark Tomb Upper"], + rule=lambda state: has_ladder("Dark Tomb Ladder", state, player, options)) regions["Dark Tomb Main"].connect( - connecting_region=regions["Dark Tomb Dark Exit"], - rule=lambda state: has_lantern(state, player, options)) + connecting_region=regions["Dark Tomb Dark Exit"]) regions["Dark Tomb Dark Exit"].connect( connecting_region=regions["Dark Tomb Main"], rule=lambda state: has_lantern(state, player, options)) @@ -426,6 +512,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Ruined Atoll"], rule=lambda state: state.has(laurels, player) or state.has(grapple, player)) + regions["Ruined Atoll"].connect( + connecting_region=regions["Ruined Atoll Ladder Tops"], + rule=lambda state: has_ladder("South Atoll Ladders", state, player, options)) + regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Frog Mouth"], rule=lambda state: state.has(laurels, player) or state.has(grapple, player)) @@ -433,6 +523,13 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Ruined Atoll"], rule=lambda state: state.has(laurels, player) or state.has(grapple, player)) + regions["Ruined Atoll"].connect( + connecting_region=regions["Ruined Atoll Frog Eye"], + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + regions["Ruined Atoll Frog Eye"].connect( + connecting_region=regions["Ruined Atoll"], + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Portal"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks)) @@ -445,6 +542,27 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Ruined Atoll Statue"].connect( connecting_region=regions["Ruined Atoll"]) + regions["Frog Stairs Eye Exit"].connect( + connecting_region=regions["Frog Stairs Upper"], + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + regions["Frog Stairs Upper"].connect( + connecting_region=regions["Frog Stairs Eye Exit"], + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + + regions["Frog Stairs Upper"].connect( + connecting_region=regions["Frog Stairs Lower"], + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + regions["Frog Stairs Lower"].connect( + connecting_region=regions["Frog Stairs Upper"], + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + + regions["Frog Stairs Lower"].connect( + connecting_region=regions["Frog Stairs to Frog's Domain"], + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + regions["Frog Stairs to Frog's Domain"].connect( + connecting_region=regions["Frog Stairs Lower"], + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + regions["Frog's Domain"].connect( connecting_region=regions["Frog's Domain Back"], rule=lambda state: state.has(grapple, player)) @@ -675,20 +793,39 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks)) # Swamp and Cathedral + regions["Swamp Front"].connect( + connecting_region=regions["Swamp Mid"], + rule=lambda state: has_ladder("Swamp Ladders", state, player, options) + or state.has(laurels, player) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) # nmg: ice grapple through gate + regions["Swamp Mid"].connect( + connecting_region=regions["Swamp Front"], + rule=lambda state: has_ladder("Swamp Ladders", state, player, options) + or state.has(laurels, player) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) # nmg: ice grapple through gate + # nmg: ice grapple through cathedral door, can do it both ways - regions["Swamp"].connect( + regions["Swamp Mid"].connect( connecting_region=regions["Swamp to Cathedral Main Entrance"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) regions["Swamp to Cathedral Main Entrance"].connect( - connecting_region=regions["Swamp"], + connecting_region=regions["Swamp Mid"], rule=lambda state: has_ice_grapple_logic(False, state, player, options, ability_unlocks)) - regions["Swamp"].connect( + regions["Swamp Mid"].connect( + connecting_region=regions["Swamp Ledge under Cathedral Door"], + rule=lambda state: has_ladder("Swamp Ladders", state, player, options)) + regions["Swamp Ledge under Cathedral Door"].connect( + connecting_region=regions["Swamp Mid"], + rule=lambda state: has_ladder("Swamp Ladders", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) # nmg: ice grapple the enemy at door + + regions["Swamp Ledge under Cathedral Door"].connect( connecting_region=regions["Swamp to Cathedral Treasure Room"], rule=lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) regions["Swamp to Cathedral Treasure Room"].connect( - connecting_region=regions["Swamp"]) + connecting_region=regions["Swamp Ledge under Cathedral Door"]) regions["Back of Swamp"].connect( connecting_region=regions["Back of Swamp Laurels Area"], @@ -699,7 +836,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: can ice grapple down while you're on the pillars regions["Back of Swamp Laurels Area"].connect( - connecting_region=regions["Swamp"], + connecting_region=regions["Swamp Mid"], rule=lambda state: state.has(laurels, player) and has_ice_grapple_logic(True, state, player, options, ability_unlocks)) diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index d2b854f5df0e..19b8887edabd 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -151,7 +151,7 @@ def hint_helper(portal: Portal, hint_string: str = "") -> str: tunic_events: Dict[str, str] = { "Eastern Bell": "Forest Belltower Upper", - "Western Bell": "Overworld Belltower", + "Western Bell": "Overworld Belltower at Bell", "Furnace Fuse": "Furnace Fuse", "South and West Fortress Exterior Fuses": "Fortress Exterior from Overworld", "Upper and Central Fortress Exterior Fuses": "Fortress Courtyard Upper", diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 20056b058dd0..491fee6e1e4a 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -160,7 +160,7 @@ class TunicItemData(NamedTuple): "Swamp Ladders": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), "South Atoll Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), - "Frog's Domain Ladders": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), + "Ladders to Frog's Domain": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), "West Overworld Ladders": TunicItemData(ItemClassification.progression, 0, 148, "ladders") } diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 492894594363..c3ad6176c7eb 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -79,7 +79,9 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] multiworld.get_entrance("East Overworld -> East Forest", player).access_rule = \ lambda state: state.has("Ladder Drop to East Forest", player) multiworld.get_entrance("East Forest -> Lower Forest", player).access_rule = \ - lambda state: state.has("Ladders to Lower Forest", player) + lambda state: state.has("Ladders to Lower Forest", player) \ + or (state.has_all({grapple, fire_wand, ice_dagger}, player) # do ice slime, then go to the lower hook + and has_ability(state, player, icebolt, options, ability_unlocks)) multiworld.get_entrance("Overworld -> Swamp", player).access_rule = \ lambda state: state.has("Ladder to Swamp", player) multiworld.get_entrance("Swamp -> Swamp Middle", player).access_rule = \ @@ -102,10 +104,8 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] or can_ladder_storage(state, player, options) multiworld.get_entrance("Overworld -> Beneath the Well", player).access_rule = \ lambda state: state.has("Ladder to Well", player) - # todo: make sure this ice grapple actually works with enemy rando off multiworld.get_entrance("Beneath the Well -> Beneath the Well Back", player).access_rule = \ - lambda state: state.has("Well Back Ladder", player) \ - or has_ice_grapple_logic(True, state, player, options, ability_unlocks) + lambda state: state.has("Well Back Ladder", player) # dash to the fuse and have the rear ladder, or dash through the well boss gate in nmg multiworld.get_entrance("Overworld -> Beneath the Well Back", player).access_rule = \ lambda state: state.has(laurels, player) and (state.has("Well Back Ladder", player) @@ -125,7 +125,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: state.has_any({"Ladder to Ruined Atoll", laurels, grapple}, player) \ or has_ability(state, player, prayer, options, ability_unlocks) multiworld.get_entrance("Ruined Atoll -> Frog's Domain", player).access_rule = \ - lambda state: state.has("Frog's Domain Ladders", player) + lambda state: state.has("Ladders to Frog's Domain", player) multiworld.get_entrance("Ruined Atoll -> Library", player).access_rule = \ lambda state: state.has_any({grapple, laurels}, player) and \ has_ability(state, player, prayer, options, ability_unlocks) and \ From ac8a3eb7407556594b144c9768c68533487d70d6 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 2 Mar 2024 15:22:33 -0500 Subject: [PATCH 11/82] Wrote up ladder storage rules, need to merge in the hint changes here since they're now dependent due to the entrance cache thing --- worlds/tunic/er_data.py | 65 +++++----- worlds/tunic/er_rules.py | 235 +++++++++++++++++++++++++++++++------ worlds/tunic/er_scripts.py | 2 +- worlds/tunic/locations.py | 2 +- 4 files changed, 236 insertions(+), 68 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 9fb4509c3232..2f11c8805af0 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -541,7 +541,7 @@ class Hint(IntEnum): "East Overworld": RegionInfo("Overworld Redux"), # where the east forest and fortress entrances are "Overworld Special Shop Entry": RegionInfo("Overworld Redux"), # special shop entry spot "Upper Overworld": RegionInfo("Overworld Redux"), # where the mountain stairs are - "Overworld above Quarry Entrance": RegionInfo("Overworld Redux"), + "Overworld above Quarry Entrance": RegionInfo("Overworld Redux"), # top of the ladder where the chest is "Overworld after Temple Rafters": RegionInfo("Overworld Redux"), # the ledge after the rafter exit, before ladder "Overworld Quarry Entry": RegionInfo("Overworld Redux"), # at the top of the ladder to darkwoods "Overworld above Patrol Cave": RegionInfo("Overworld Redux"), # where the hook is, and one ladder up from patrol @@ -759,21 +759,21 @@ class Hint(IntEnum): # 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 dependent_regions_restricted: Dict[Tuple[str, ...], List[str]] = { - ("Overworld", "Overworld Belltower", "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", "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", "Overworld Belltower", "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", "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"], ("Hourglass Cave",): ["Hourglass Cave", "Hourglass Cave Tower"], ("Old House Front",): @@ -861,6 +861,8 @@ class Hint(IntEnum): ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave"], ("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", "Far Shore to East Forest", "Far Shore to Quarry", "Far Shore to Fortress", "Far Shore to Library", "Far Shore to West Garden"): ["Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", @@ -869,20 +871,21 @@ class Hint(IntEnum): dependent_regions_nmg: Dict[Tuple[str, ...], List[str]] = { - ("Overworld", "Overworld Belltower", "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", "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", "Overworld Belltower", "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", "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"], # can laurels through the gate ("Old House Front", "Old House Back"): ["Old House Front", "Old House Back"], @@ -970,6 +973,8 @@ class Hint(IntEnum): "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", "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", "Far Shore to East Forest", "Far Shore to Quarry", "Far Shore to Fortress", "Far Shore to Library", "Far Shore to West Garden"): ["Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", @@ -979,16 +984,16 @@ class Hint(IntEnum): dependent_regions_ur: Dict[Tuple[str, ...], List[str]] = { # can use ladder storage to get to the well rail - ("Overworld", "Overworld Belltower", "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", "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", "Overworld Belltower", "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", "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", @@ -1083,6 +1088,8 @@ class Hint(IntEnum): "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "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", "Far Shore to East Forest", "Far Shore to Quarry", "Far Shore to Fortress", "Far Shore to Library", "Far Shore to West Garden"): ["Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 2d350ebc69f7..b46eda8e5a99 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -35,14 +35,7 @@ def has_ladder(ladder: str, state: CollectionState, player: int, options: TunicO return state.has(ladder, player) -def has_ladders(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): - if not options.ladder_rando: - return True - else: - return state.has_all(ladders, player) - - -def has_ladders_any(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): +def has_any_ladders(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): if not options.ladder_rando: return True else: @@ -147,10 +140,13 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Above Ruined Passage"].connect( connecting_region=regions["East Overworld"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + or state.has(laurels, player) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["East Overworld"].connect( connecting_region=regions["Above Ruined Passage"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + or state.has(laurels, player)) # nmg: ice grapple the slimes, works both ways consistently regions["East Overworld"].connect( @@ -160,14 +156,6 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["East Overworld"], rule=lambda state: has_ice_grapple_logic(True, state, player, options, ability_unlocks)) - regions["East Overworld"].connect( - connecting_region=regions["Above Ruined Passage"], - rule=lambda state: state.has(laurels, player)) - regions["Above Ruined Passage"].connect( - connecting_region=regions["East Overworld"], - rule=lambda state: state.has(laurels, player) - or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) - regions["Overworld"].connect( connecting_region=regions["East Overworld"], rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options) @@ -237,6 +225,16 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld above Quarry Entrance"], rule=lambda state: has_ladder("Ladders near Dark Tomb", state, player, options)) + regions["Overworld"].connect( + connecting_region=regions["Overworld Quarry Entry"], + rule=lambda state: (has_ladder("Ladder to Quarry", state, player, options) + and state.has_any({laurels, grapple}, player)) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) + regions["Overworld Quarry Entry"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: has_ladder("Ladder to Quarry", state, player, options) and state.has(laurels, player) + or state.has(grapple, player)) + regions["Overworld"].connect( connecting_region=regions["Overworld Swamp Upper Entry"], rule=lambda state: state.has(laurels, player)) @@ -388,10 +386,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Guard House 2 Upper"].connect( connecting_region=regions["Guard House 2 Lower"], - rule=lambda state: has_ladder("Lower Forest Ladders", state, player, options)) + rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options)) regions["Guard House 2 Lower"].connect( connecting_region=regions["Guard House 2 Upper"], - rule=lambda state: has_ladder("Lower Forest Ladders", state, player, options)) + rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options)) # nmg: ice grapple from upper grave path exit to the rest of it regions["Forest Grave Path Upper"].connect( @@ -538,7 +536,8 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Statue"], - rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks)) + rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) + and has_ladder("South Atoll Ladders", state, player, options)) regions["Ruined Atoll Statue"].connect( connecting_region=regions["Ruined Atoll"]) @@ -933,31 +932,191 @@ def get_paired_region(portal_sd: str) -> str: # The upper Swamp entrance regions["Overworld"].connect( regions[get_paired_region("Overworld Redux, Swamp Redux 2_wall")], - rule=lambda state: has_stick(state, player)) - # Western Furnace entrance, next to the sign that leads to West Garden + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}, + state, player, options)) + # Furnace entrance, next to the sign that leads to West Garden regions["Overworld"].connect( regions[get_paired_region("Overworld Redux, Furnace_gyro_west")], - rule=lambda state: has_stick(state, player)) + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}, + state, player, options)) + # Upper West Garden entry, by the belltower regions["Overworld"].connect( regions[get_paired_region("Overworld Redux, Archipelagos Redux_upper")], - rule=lambda state: has_stick(state, player)) - # West Garden entry by the Furnace - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Archipelagos Redux_lower")], - rule=lambda state: has_stick(state, player)) - # West Garden laurels entrance, by the beach + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}, + state, player, options)) + + # Ruined Passage regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Archipelagos Redux_lowest")], - rule=lambda state: has_stick(state, player)) + regions[get_paired_region("Overworld Redux, Ruins Passage_east")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}, + state, player, options)) + # Well rail, west side. Can ls in town, get extra height by going over the portal pad regions["Overworld"].connect( regions[get_paired_region("Overworld Redux, Sewer_west_aqueduct")], - rule=lambda state: has_stick(state, player)) + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", + "Ladder to Quarry"}, state, player, options)) # Well rail, east side. Need some height from the temple stairs regions["Overworld"].connect( regions[get_paired_region("Overworld Redux, Furnace_gyro_upper_north")], - rule=lambda state: has_stick(state, player)) + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", + "Ladder to Quarry"}, state, player, options)) + + # Quarry entry + regions["Overworld"].connect( + regions[get_paired_region("Overworld Redux, Darkwoods Tunnel_")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", + "Ladder to Well"}, state, player, options)) + + # East Forest entry + regions["Overworld"].connect( + regions[get_paired_region("Overworld Redux, Forest Belltower_")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", + "Ladder to Well", "Ladders near Patrol Cave", "Ladder to Quarry", + "Ladders near Dark Tomb"}, state, player, options)) + + # Fortress entry + regions["Overworld"].connect( + regions[get_paired_region("Overworld Redux, Fortress Courtyard_")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", + "Ladder to Well", "Ladders near Patrol Cave", "Ladder to Quarry", + "Ladders near Dark Tomb"}, state, player, options)) + + # Patrol Cave entry + regions["Overworld"].connect( + regions[get_paired_region("Overworld Redux, PatrolCave_")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", + "Ladder to Well", "Overworld Shortcut Ladders", "Ladder to Quarry", + "Ladders near Dark Tomb"}, state, player, options)) + + # Special Shop entry + regions["Overworld"].connect( + regions[get_paired_region("Overworld Redux, ShopSpecial_")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", + "Ladder to Well", "Overworld Shortcut Ladders", "Ladders near Patrol Cave", + "Ladder to Quarry", "Ladders near Dark Tomb"}, state, player, options)) + + # Temple Rafters + regions["Overworld"].connect( + regions[get_paired_region("Overworld Redux, Temple_rafters")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", + "Ladder to Well", "Overworld Shortcut Ladders", "Ladders near Patrol Cave", + "Ladder to Quarry", "Ladders near Dark Tomb"}, state, player, options)) + + # Mountain Stairs + regions["Overworld above Quarry Entrance"].connect( + regions[get_paired_region("Overworld Redux, Mountain_")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders near Dark Tomb", state, player, options)) + + # ladders to west belltower -> ruined passage back, well rail, quarry, and higher + + # West Garden entry by the Furnace + regions["Overworld Beach"].connect( + regions[get_paired_region("Overworld Redux, Archipelagos Redux_lower")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"West Overworld Ladders", "Ladder to Ruined Atoll"}, state, player, options)) + # West Garden laurels entry + regions["Overworld Beach"].connect( + regions[get_paired_region("Overworld Redux, Archipelagos Redux_lowest")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"West Overworld Ladders", "Ladder to Ruined Atoll"}, state, player, options)) + # Swamp lower entrance + regions["Overworld Beach"].connect( + regions[get_paired_region("Overworld Redux, Swamp Redux 2_conduit")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"West Overworld Ladders", "Ladder to Ruined Atoll"}, state, player, options)) + # Rotating Lights entrance + regions["Overworld Beach"].connect( + regions[get_paired_region("Overworld Redux, Overworld Cave_")], + rule=lambda state: has_stick(state, player) + and has_any_ladders({"West Overworld Ladders", "Ladder to Ruined Atoll"}, state, player, options)) + + # West Garden main entry from swamp ladder + regions["Overworld Swamp Lower Entry"].connect( + regions[get_paired_region("Overworld Redux, Archipelagos Redux_lower")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladder to Swamp", state, player, options)) + # Maze Cave entry from swamp ladder + regions["Overworld Swamp Lower Entry"].connect( + regions[get_paired_region("Overworld Redux, Maze Room_")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladder to Swamp", state, player, options)) + # Hourglass Cave entry from swamp ladder + regions["Overworld Swamp Lower Entry"].connect( + regions[get_paired_region("Overworld Redux, Town Basement_beach")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladder to Swamp", state, player, options)) + # Lower Atoll entry from swamp ladder + regions["Overworld Swamp Lower Entry"].connect( + regions[get_paired_region("Overworld Redux, Atoll Redux_lower")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladder to Swamp", state, player, options)) + # Lowest West Garden entry from swamp ladder + regions["Overworld Swamp Lower Entry"].connect( + regions[get_paired_region("Overworld Redux, Archipelagos Redux_lowest")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladder to Swamp", state, player, options)) + + # from the ladders by the belltower + # Ruined Passage + regions["Overworld to West Garden Upper"].connect( + regions[get_paired_region("Overworld Redux, Ruins Passage_east")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders to West Belltower", state, player, options)) + # Well rail, west side. Can ls in town, get extra height by going over the portal pad + regions["Overworld to West Garden Upper"].connect( + regions[get_paired_region("Overworld Redux, Sewer_west_aqueduct")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders to West Belltower", state, player, options)) + # Well rail, east side. Need some height from the temple stairs + regions["Overworld to West Garden Upper"].connect( + regions[get_paired_region("Overworld Redux, Furnace_gyro_upper_north")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders to West Belltower", state, player, options)) + # Quarry entry + regions["Overworld to West Garden Upper"].connect( + regions[get_paired_region("Overworld Redux, Darkwoods Tunnel_")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders to West Belltower", state, player, options)) + # East Forest entry + regions["Overworld to West Garden Upper"].connect( + regions[get_paired_region("Overworld Redux, Forest Belltower_")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders to West Belltower", state, player, options)) + # Fortress entry + regions["Overworld to West Garden Upper"].connect( + regions[get_paired_region("Overworld Redux, Fortress Courtyard_")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders to West Belltower", state, player, options)) + # Patrol Cave entry + regions["Overworld to West Garden Upper"].connect( + regions[get_paired_region("Overworld Redux, PatrolCave_")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders to West Belltower", state, player, options)) + # Special Shop entry + regions["Overworld to West Garden Upper"].connect( + regions[get_paired_region("Overworld Redux, ShopSpecial_")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders to West Belltower", state, player, options)) + # Temple Rafters + regions["Overworld to West Garden Upper"].connect( + regions[get_paired_region("Overworld Redux, Temple_rafters")], + rule=lambda state: has_stick(state, player) + and has_ladder("Ladders to West Belltower", state, player, options)) # Furnace ladder to the fuse entrance regions["Furnace Ladder Area"].connect( @@ -1071,13 +1230,15 @@ def get_paired_region(portal_sd: str) -> str: rule=lambda state: has_stick(state, player)) # Swamp to Gauntlet - regions["Swamp"].connect( + regions["Swamp Mid"].connect( regions[get_paired_region("Swamp Redux 2, Cathedral Arena_")], - rule=lambda state: has_stick(state, player)) + rule=lambda state: has_stick(state, player) + and has_ladder("Swamp Ladders", state, player, options)) # Swamp to Overworld upper regions["Swamp"].connect( regions[get_paired_region("Swamp Redux 2, Overworld Redux_wall")], - rule=lambda state: has_stick(state, player)) + rule=lambda state: has_stick(state, player) + and has_ladder("Swamp Ladders", state, player, options)) # Ladder by the hero grave regions["Back of Swamp"].connect( regions[get_paired_region("Swamp Redux 2, Overworld Redux_conduit")], diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 19b8887edabd..982f3af1fd5e 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -451,7 +451,7 @@ def gate_before_switch(check_portal: Portal, two_plus: List[Portal]) -> bool: elif check_portal.scene_destination() == "Swamp Redux 2, Cathedral Redux_main": i = 0 for portal in two_plus: - if portal.region == "Swamp": + if portal.region in ["Swamp Front", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance"]: i += 1 if i == 4: return True diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index 3d652d19d7a1..3cfe845ceffe 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -278,7 +278,7 @@ class TunicLocationData(NamedTuple): "Swamp - [South Graveyard] Upper Walkway On Pedestal": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [South Graveyard] Guarded By Tentacles": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [Upper Graveyard] Near Telescope": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), - "Swamp - [Outside Cathedral] Near Moonlight Bridge Door": TunicLocationData("Swamp", "Swamp Ledge Under Cathedral Door", ladder_region="Swamp Middle"), + "Swamp - [Outside Cathedral] Near Moonlight Bridge Door": TunicLocationData("Swamp", "Swamp Ledge under Cathedral Door", ladder_region="Swamp Middle"), "Swamp - [Entrance] Obscured Inside Watchtower": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [Entrance] South Near Fence": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [South Graveyard] Guarded By Big Skeleton": TunicLocationData("Swamp", "Swamp Front"), From 06ab1a8efb3826bf070465f123edff1a25341d64 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 2 Mar 2024 15:46:07 -0500 Subject: [PATCH 12/82] Ported hint branch over --- worlds/tunic/__init__.py | 33 ++++- worlds/tunic/er_data.py | 294 ++++++++++++++++--------------------- worlds/tunic/er_rules.py | 76 ++++------ worlds/tunic/er_scripts.py | 113 +------------- worlds/tunic/locations.py | 2 +- 5 files changed, 197 insertions(+), 321 deletions(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index e08cd21cb46f..1dec6c882f6f 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -8,6 +8,7 @@ from .ladder_rules import set_ladder_region_rules, set_ladder_location_rules from .regions import tunic_regions, tunic_ladder_regions from .er_scripts import create_er_regions +from .er_data import portal_mapping from .options import TunicOptions from worlds.AutoWorld import WebWorld, World from decimal import Decimal, ROUND_HALF_UP @@ -190,12 +191,10 @@ def create_regions(self) -> None: self.ability_unlocks["Pages 52-53 (Icebolt)"] = passthrough["Hexagon Quest Icebolt"] if self.options.entrance_rando: - portal_pairs, portal_hints = create_er_regions(self) + portal_pairs = create_er_regions(self) for portal1, portal2 in portal_pairs.items(): self.tunic_portal_pairs[portal1.scene_destination()] = portal2.scene_destination() - self.er_portal_hints = portal_hints - else: if self.options.ladder_rando: region_list = tunic_ladder_regions @@ -239,7 +238,33 @@ def get_filler_item_name(self) -> str: def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]): if self.options.entrance_rando: - hint_data[self.player] = self.er_portal_hints + hint_data.update({self.player: {}}) + # all state seems to have efficient paths + all_state = self.multiworld.get_all_state(True) + all_state.update_reachable_regions(self.player) + paths = all_state.path + portal_names = [portal.name for portal in portal_mapping] + for location in self.multiworld.get_locations(self.player): + # skipping event locations + if not location.address: + continue + path_to_loc = [] + previous_name = "placeholder" + name, connection = paths[location.parent_region] + while connection != ("Menu", None): + name, connection = connection + if name.endswith("(LS)"): + name = name.replace(" (LS)", "") + # was getting some cases like Library Grave -> Library Grave -> other place + if name in portal_names and name != previous_name: + previous_name = name + path_to_loc.append(name) + hint_text = "" + for transition in reversed(path_to_loc): + hint_text += f"{transition} -> " + hint_text = hint_text.rstrip("-> ") + if hint_text: + hint_data[self.player][location.address] = hint_text def fill_slot_data(self) -> Dict[str, Any]: slot_data: Dict[str, Any] = { diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 2f11c8805af0..fd26f24533dd 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -193,9 +193,9 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Overworld Redux_upper"), Portal(name="West Garden Shop", region="West Garden", destination="Shop_"), - Portal(name="West Garden Laurels Exit", region="West Garden Laurels Exit", + Portal(name="West Garden Laurels Exit", region="West Garden Laurels Exit Region", destination="Overworld Redux_lowest"), - Portal(name="West Garden Hero's Grave", region="West Garden Hero's Grave", + Portal(name="West Garden Hero's Grave", region="West Garden Hero's Grave Region", destination="RelicVoid_teleporter_relic plinth"), Portal(name="West Garden to Far Shore", region="West Garden Portal", destination="Transit_teleporter_archipelagos_teleporter"), @@ -232,14 +232,14 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th Portal(name="Frog's Domain Orb Exit", region="Frog's Domain Back", destination="Frog Stairs_Exit"), - Portal(name="Library Exterior Tree", region="Library Exterior Tree", + Portal(name="Library Exterior Tree", region="Library Exterior Tree Region", destination="Atoll Redux_"), - Portal(name="Library Exterior Ladder", region="Library Exterior Ladder", + Portal(name="Library Exterior Ladder", region="Library Exterior Ladder Region", destination="Library Hall_"), Portal(name="Library Hall Bookshelf Exit", region="Library Hall", destination="Library Exterior_"), - Portal(name="Library Hero's Grave", region="Library Hero's Grave", + Portal(name="Library Hero's Grave", region="Library Hero's Grave Region", destination="RelicVoid_teleporter_relic plinth"), Portal(name="Library Hall to Rotunda", region="Library Hall", destination="Library Rotunda_"), @@ -357,11 +357,11 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th Portal(name="Fortress Grave Path Lower Exit", region="Fortress Grave Path", destination="Fortress Courtyard_Lower"), - Portal(name="Fortress Hero's Grave", region="Fortress Grave Path", + Portal(name="Fortress Hero's Grave", region="Fortress Hero's Grave Region", destination="RelicVoid_teleporter_relic plinth"), Portal(name="Fortress Grave Path Upper Exit", region="Fortress Grave Path Upper", destination="Fortress Courtyard_Upper"), - Portal(name="Fortress Grave Path Dusty Entrance", region="Fortress Grave Path Dusty Entrance", + Portal(name="Fortress Grave Path Dusty Entrance", region="Fortress Grave Path Dusty Entrance Region", destination="Dusty_"), Portal(name="Dusty Exit", region="Fortress Leaf Piles", @@ -406,7 +406,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Quarry Redux_back"), Portal(name="Monastery Front Exit", region="Monastery Front", destination="Quarry Redux_front"), - Portal(name="Monastery Hero's Grave", region="Monastery Hero's Grave", + Portal(name="Monastery Hero's Grave", region="Monastery Hero's Grave Region", destination="RelicVoid_teleporter_relic plinth"), Portal(name="Ziggurat Entry Hallway to Ziggurat Upper", region="Rooted Ziggurat Entry", @@ -436,7 +436,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th Portal(name="Swamp Lower Exit", region="Swamp Front", destination="Overworld Redux_conduit"), - Portal(name="Swamp to Cathedral Main Entrance", region="Swamp to Cathedral Main Entrance", + Portal(name="Swamp to Cathedral Main Entrance", region="Swamp to Cathedral Main Entrance Region", destination="Cathedral Redux_main"), Portal(name="Swamp to Cathedral Secret Legend Room Entrance", region="Swamp to Cathedral Treasure Room", destination="Cathedral Redux_secret"), @@ -446,7 +446,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Shop_"), Portal(name="Swamp Upper Exit", region="Back of Swamp Laurels Area", destination="Overworld Redux_wall"), - Portal(name="Swamp Hero's Grave", region="Swamp Hero's Grave", + Portal(name="Swamp Hero's Grave", region="Swamp Hero's Grave Region", destination="RelicVoid_teleporter_relic plinth"), Portal(name="Cathedral Main Exit", region="Cathedral", @@ -476,15 +476,15 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th Portal(name="Hero's Grave to Swamp", region="Hero Relic - Swamp", destination="Swamp Redux 2_teleporter_relic plinth"), - Portal(name="Far Shore to West Garden", region="Far Shore to West Garden", + Portal(name="Far Shore to West Garden", region="Far Shore to West Garden Region", destination="Archipelagos Redux_teleporter_archipelagos_teleporter"), - Portal(name="Far Shore to Library", region="Far Shore to Library", + Portal(name="Far Shore to Library", region="Far Shore to Library Region", destination="Library Lab_teleporter_library teleporter"), - Portal(name="Far Shore to Quarry", region="Far Shore to Quarry", + Portal(name="Far Shore to Quarry", region="Far Shore to Quarry Region", destination="Quarry Redux_teleporter_quarry teleporter"), - Portal(name="Far Shore to East Forest", region="Far Shore to East Forest", + Portal(name="Far Shore to East Forest", region="Far Shore to East Forest Region", destination="East Forest Redux_teleporter_forest teleporter"), - Portal(name="Far Shore to Fortress", region="Far Shore to Fortress", + Portal(name="Far Shore to Fortress", region="Far Shore to Fortress Region", destination="Fortress Arena_teleporter_spidertank"), Portal(name="Far Shore to Atoll", region="Far Shore", destination="Atoll Redux_teleporter_atoll"), @@ -494,7 +494,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Spirit Arena_teleporter_spirit arena"), Portal(name="Far Shore to Town", region="Far Shore", destination="Overworld Redux_teleporter_town"), - Portal(name="Far Shore to Spawn", region="Far Shore to Spawn", + Portal(name="Far Shore to Spawn", region="Far Shore to Spawn Region", destination="Overworld Redux_teleporter_starting island"), Portal(name="Heir Arena Exit", region="Spirit Arena", @@ -520,13 +520,6 @@ class DeadEnd(IntEnum): # there's no dead ends that are only in unrestricted -class Hint(IntEnum): - none = 0 # big areas, empty hallways, etc. - region = 1 # at least one of the portals must not be a dead end - scene = 2 # multiple regions in the scene, so using region could mean no valid hints - special = 3 # for if there's a weird case of specific regions being viable - - # key is the AP region name. "Fake" in region info just means the mod won't receive that info at all tunic_er_regions: Dict[str, RegionInfo] = { "Menu": RegionInfo("Fake", dead_end=DeadEnd.all_cats), @@ -548,7 +541,7 @@ class Hint(IntEnum): "Overworld at Patrol Cave": RegionInfo("Overworld Redux"), # right at the patrol cave entrance "Overworld West Garden Laurels Entry": RegionInfo("Overworld Redux"), # west garden laurels entry "Overworld to West Garden Upper": RegionInfo("Overworld Redux"), # usually leads to garden knight - "Overworld to West Garden from Furnace": RegionInfo("Overworld Redux", hint=Hint.region), + "Overworld to West Garden from Furnace": RegionInfo("Overworld Redux"), "Overworld Well Ladder": RegionInfo("Overworld Redux"), # just the ladder entrance "Overworld Beach": RegionInfo("Overworld Redux"), "Overworld to Atoll Upper": RegionInfo("Overworld Redux"), @@ -560,7 +553,7 @@ class Hint(IntEnum): "Overworld Temple Door": RegionInfo("Overworld Redux"), # the small space betweeen the door and the portal "Overworld Town Portal": RegionInfo("Overworld Redux"), "Overworld Spawn Portal": RegionInfo("Overworld Redux"), - "Stick House": RegionInfo("Sword Cave", dead_end=DeadEnd.all_cats, hint=Hint.region), + "Stick House": RegionInfo("Sword Cave", dead_end=DeadEnd.all_cats), "Windmill": RegionInfo("Windmill"), "Old House Back": RegionInfo("Overworld Interiors"), # part with the hc door "Old House Front": RegionInfo("Overworld Interiors"), # part with the bedroom @@ -568,22 +561,22 @@ class Hint(IntEnum): "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, hint=Hint.region), - "Changing Room": RegionInfo("Changing Room", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Patrol Cave": RegionInfo("PatrolCave", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Ruined Shop": RegionInfo("Ruined Shop", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Ruined Passage": RegionInfo("Ruins Passage", hint=Hint.region), - "Special Shop": RegionInfo("ShopSpecial", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Caustic Light Cave": RegionInfo("Overworld Cave", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Maze Cave": RegionInfo("Maze Room", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Cube Cave": RegionInfo("CubeRoom", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Southeast Cross Room": RegionInfo("EastFiligreeCache", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Fountain Cross Room": RegionInfo("Town_FiligreeRoom", dead_end=DeadEnd.all_cats, hint=Hint.region), + "Secret Gathering Place": RegionInfo("Waterfall", dead_end=DeadEnd.all_cats), + "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), + "Ruined Passage": RegionInfo("Ruins Passage"), + "Special Shop": RegionInfo("ShopSpecial", dead_end=DeadEnd.all_cats), + "Caustic Light Cave": RegionInfo("Overworld Cave", dead_end=DeadEnd.all_cats), + "Maze Cave": RegionInfo("Maze Room", dead_end=DeadEnd.all_cats), + "Cube Cave": RegionInfo("CubeRoom", dead_end=DeadEnd.all_cats), + "Southeast Cross Room": RegionInfo("EastFiligreeCache", dead_end=DeadEnd.all_cats), + "Fountain Cross Room": RegionInfo("Town_FiligreeRoom", dead_end=DeadEnd.all_cats), "Hourglass Cave": RegionInfo("Town Basement", dead_end=DeadEnd.all_cats), "Hourglass Cave Tower": RegionInfo("Town Basement", dead_end=DeadEnd.all_cats), # top of the tower - "Sealed Temple": RegionInfo("Temple", hint=Hint.scene), - "Sealed Temple Rafters": RegionInfo("Temple", hint=Hint.scene), - "Forest Belltower Upper": RegionInfo("Forest Belltower", hint=Hint.region), + "Sealed Temple": RegionInfo("Temple"), + "Sealed Temple Rafters": RegionInfo("Temple"), + "Forest Belltower Upper": RegionInfo("Forest Belltower"), "Forest Belltower Main": RegionInfo("Forest Belltower"), "Forest Belltower Lower": RegionInfo("Forest Belltower"), "East Forest": RegionInfo("East Forest Redux"), @@ -610,12 +603,12 @@ class Hint(IntEnum): "Beneath the Well Main": RegionInfo("Sewer"), # the main section of it, requires a weapon "Beneath the Well Back": RegionInfo("Sewer"), # the back two portals, and all 4 upper chests "West Garden": RegionInfo("Archipelagos Redux"), - "Magic Dagger House": RegionInfo("archipelagos_house", dead_end=DeadEnd.all_cats, hint=Hint.region), + "Magic Dagger House": RegionInfo("archipelagos_house", dead_end=DeadEnd.all_cats), "West Garden Portal": RegionInfo("Archipelagos Redux", dead_end=DeadEnd.restricted), - "West Garden Portal Item": RegionInfo("Archipelagos Redux", dead_end=DeadEnd.restricted, hint=Hint.special), - "West Garden Laurels Exit": RegionInfo("Archipelagos Redux"), + "West Garden Portal Item": RegionInfo("Archipelagos Redux", dead_end=DeadEnd.restricted), + "West Garden Laurels Exit Region": RegionInfo("Archipelagos Redux"), "West Garden after Boss": RegionInfo("Archipelagos Redux"), - "West Garden Hero's Grave": RegionInfo("Archipelagos Redux"), + "West Garden Hero's Grave Region": RegionInfo("Archipelagos Redux"), "Ruined Atoll": RegionInfo("Atoll Redux"), "Ruined Atoll Lower Entry Area": RegionInfo("Atoll Redux"), "Ruined Atoll Ladder Tops": RegionInfo("Atoll Redux"), # at the top of the 5 ladders in south Atoll @@ -627,38 +620,38 @@ class Hint(IntEnum): "Frog Stairs Upper": RegionInfo("Frog Stairs"), "Frog Stairs Lower": RegionInfo("Frog Stairs"), "Frog Stairs to Frog's Domain": RegionInfo("Frog Stairs"), - "Frog's Domain": RegionInfo("frog cave main", hint=Hint.region), - "Frog's Domain Back": RegionInfo("frog cave main", hint=Hint.scene), - "Library Exterior Tree": RegionInfo("Library Exterior"), - "Library Exterior Ladder": RegionInfo("Library Exterior"), + "Frog's Domain": RegionInfo("frog cave main"), + "Frog's Domain Back": RegionInfo("frog cave main"), + "Library Exterior Tree Region": RegionInfo("Library Exterior"), + "Library Exterior Ladder Region": RegionInfo("Library Exterior"), "Library Hall": RegionInfo("Library Hall"), - "Library Hero's Grave": RegionInfo("Library Hall"), + "Library Hero's Grave Region": RegionInfo("Library Hall"), "Library Rotunda": RegionInfo("Library Rotunda"), "Library Lab": RegionInfo("Library Lab"), "Library Lab Lower": RegionInfo("Library Lab"), "Library Portal": RegionInfo("Library Lab"), - "Library Arena": RegionInfo("Library Arena", dead_end=DeadEnd.all_cats, hint=Hint.region), + "Library Arena": RegionInfo("Library Arena", dead_end=DeadEnd.all_cats), "Fortress Exterior from East Forest": RegionInfo("Fortress Courtyard"), "Fortress Exterior from Overworld": RegionInfo("Fortress Courtyard"), "Fortress Exterior near cave": RegionInfo("Fortress Courtyard"), # where the shop and beneath the earth entry are "Fortress Courtyard": RegionInfo("Fortress Courtyard"), "Fortress Courtyard Upper": RegionInfo("Fortress Courtyard"), - "Beneath the Vault Front": RegionInfo("Fortress Basement", hint=Hint.scene), # the vanilla entry point - "Beneath the Vault Back": RegionInfo("Fortress Basement", hint=Hint.scene), # the vanilla exit point + "Beneath the Vault Front": 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"), "Fortress East Shortcut Upper": RegionInfo("Fortress East"), "Fortress East Shortcut Lower": RegionInfo("Fortress East"), "Fortress Grave Path": RegionInfo("Fortress Reliquary"), - "Fortress Grave Path Upper": RegionInfo("Fortress Reliquary", dead_end=DeadEnd.restricted, hint=Hint.region), - "Fortress Grave Path Dusty Entrance": RegionInfo("Fortress Reliquary"), - "Fortress Hero's Grave": RegionInfo("Fortress Reliquary"), - "Fortress Leaf Piles": RegionInfo("Dusty", dead_end=DeadEnd.all_cats, hint=Hint.region), + "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"), + "Fortress Leaf Piles": RegionInfo("Dusty", dead_end=DeadEnd.all_cats), "Fortress Arena": RegionInfo("Fortress Arena"), "Fortress Arena Portal": RegionInfo("Fortress Arena"), "Lower Mountain": RegionInfo("Mountain"), "Lower Mountain Stairs": RegionInfo("Mountain"), - "Top of the Mountain": RegionInfo("Mountaintop", dead_end=DeadEnd.all_cats, hint=Hint.region), + "Top of the Mountain": RegionInfo("Mountaintop", dead_end=DeadEnd.all_cats), "Quarry Connector": RegionInfo("Darkwoods Tunnel"), "Quarry Entry": RegionInfo("Quarry Redux"), "Quarry": RegionInfo("Quarry Redux"), @@ -667,7 +660,7 @@ class Hint(IntEnum): "Quarry Monastery Entry": RegionInfo("Quarry Redux"), "Monastery Front": RegionInfo("Monastery"), "Monastery Back": RegionInfo("Monastery"), - "Monastery Hero's Grave": RegionInfo("Monastery"), + "Monastery Hero's Grave Region": RegionInfo("Monastery"), "Monastery Rope": RegionInfo("Quarry Redux"), "Lower Quarry": RegionInfo("Quarry Redux"), "Lower Quarry Zig Door": RegionInfo("Quarry Redux"), @@ -686,28 +679,28 @@ class Hint(IntEnum): "Swamp Mid": RegionInfo("Swamp Redux 2"), # from the bottom of the ladder to the cathedral door "Swamp Ledge under Cathedral Door": RegionInfo("Swamp Redux 2"), # the ledge with the chest and secret door "Swamp to Cathedral Treasure Room": RegionInfo("Swamp Redux 2"), # just the door - "Swamp to Cathedral Main Entrance": RegionInfo("Swamp Redux 2"), # just the door + "Swamp to Cathedral Main Entrance Region": RegionInfo("Swamp Redux 2"), # just the door "Back of Swamp": RegionInfo("Swamp Redux 2"), # the area with hero grave and gauntlet entrance - "Swamp Hero's Grave": RegionInfo("Swamp Redux 2"), + "Swamp Hero's Grave Region": RegionInfo("Swamp Redux 2"), "Back of Swamp Laurels Area": RegionInfo("Swamp Redux 2"), # the spots you need laurels to traverse "Cathedral": RegionInfo("Cathedral Redux"), - "Cathedral Secret Legend Room": RegionInfo("Cathedral Redux", dead_end=DeadEnd.all_cats, hint=Hint.region), + "Cathedral Secret Legend Room": RegionInfo("Cathedral Redux", dead_end=DeadEnd.all_cats), "Cathedral Gauntlet Checkpoint": RegionInfo("Cathedral Arena"), "Cathedral Gauntlet": RegionInfo("Cathedral Arena"), "Cathedral Gauntlet Exit": RegionInfo("Cathedral Arena"), "Far Shore": RegionInfo("Transit"), - "Far Shore to Spawn": RegionInfo("Transit"), - "Far Shore to East Forest": RegionInfo("Transit"), - "Far Shore to Quarry": RegionInfo("Transit"), - "Far Shore to Fortress": RegionInfo("Transit"), - "Far Shore to Library": RegionInfo("Transit"), - "Far Shore to West Garden": RegionInfo("Transit"), - "Hero Relic - Fortress": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Hero Relic - Quarry": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Hero Relic - West Garden": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Hero Relic - East Forest": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Hero Relic - Library": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats, hint=Hint.region), - "Hero Relic - Swamp": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats, hint=Hint.region), + "Far Shore to Spawn Region": RegionInfo("Transit"), + "Far Shore to East Forest Region": RegionInfo("Transit"), + "Far Shore to Quarry Region": RegionInfo("Transit"), + "Far Shore to Fortress Region": RegionInfo("Transit"), + "Far Shore to Library Region": RegionInfo("Transit"), + "Far Shore to West Garden Region": RegionInfo("Transit"), + "Hero Relic - Fortress": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats), + "Hero Relic - Quarry": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats), + "Hero Relic - West Garden": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats), + "Hero Relic - East Forest": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats), + "Hero Relic - Library": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats), + "Hero Relic - Swamp": RegionInfo("RelicVoid", dead_end=DeadEnd.all_cats), "Purgatory": RegionInfo("Purgatory"), "Shop Entrance 1": RegionInfo("Shop", dead_end=DeadEnd.all_cats), "Shop Entrance 2": RegionInfo("Shop", dead_end=DeadEnd.all_cats), @@ -716,46 +709,11 @@ class Hint(IntEnum): "Shop Entrance 5": RegionInfo("Shop", dead_end=DeadEnd.all_cats), "Shop Entrance 6": RegionInfo("Shop", dead_end=DeadEnd.all_cats), "Shop": RegionInfo("Shop", dead_end=DeadEnd.all_cats), - "Spirit Arena": RegionInfo("Spirit Arena", dead_end=DeadEnd.all_cats, hint=Hint.region), + "Spirit Arena": RegionInfo("Spirit Arena", dead_end=DeadEnd.all_cats), "Spirit Arena Victory": RegionInfo("Spirit Arena", dead_end=DeadEnd.all_cats) } -# so we can just loop over this instead of doing some complicated thing to deal with hallways in the hints -hallways: Dict[str, str] = { - "Overworld Redux, Furnace_gyro_west": "Overworld Redux, Archipelagos Redux_lower", - "Overworld Redux, Furnace_gyro_upper_north": "Overworld Redux, Sewer_west_aqueduct", - "Ruins Passage, Overworld Redux_east": "Ruins Passage, Overworld Redux_west", - "East Forest Redux Interior, East Forest Redux_upper": "East Forest Redux Interior, East Forest Redux_lower", - "Forest Boss Room, East Forest Redux Laddercave_": "Forest Boss Room, Forest Belltower_", - "Library Exterior, Atoll Redux_": "Library Exterior, Library Hall_", - "Library Rotunda, Library Lab_": "Library Rotunda, Library Hall_", - "Darkwoods Tunnel, Quarry Redux_": "Darkwoods Tunnel, Overworld Redux_", - "ziggurat2020_0, Quarry Redux_": "ziggurat2020_0, ziggurat2020_1_", - "Purgatory, Purgatory_bottom": "Purgatory, Purgatory_top", -} -hallway_helper: Dict[str, str] = {} -for p1, p2 in hallways.items(): - hallway_helper[p1] = p2 - hallway_helper[p2] = p1 - -# so we can just loop over this instead of doing some complicated thing to deal with hallways in the hints -hallways_ur: Dict[str, str] = { - "Ruins Passage, Overworld Redux_east": "Ruins Passage, Overworld Redux_west", - "East Forest Redux Interior, East Forest Redux_upper": "East Forest Redux Interior, East Forest Redux_lower", - "Forest Boss Room, East Forest Redux Laddercave_": "Forest Boss Room, Forest Belltower_", - "Library Exterior, Atoll Redux_": "Library Exterior, Library Hall_", - "Library Rotunda, Library Lab_": "Library Rotunda, Library Hall_", - "Darkwoods Tunnel, Quarry Redux_": "Darkwoods Tunnel, Overworld Redux_", - "ziggurat2020_0, Quarry Redux_": "ziggurat2020_0, ziggurat2020_1_", - "Purgatory, Purgatory_bottom": "Purgatory, Purgatory_top", -} -hallway_helper_ur: Dict[str, str] = {} -for p1, p2 in hallways_ur.items(): - hallway_helper_ur[p1] = p2 - hallway_helper_ur[p2] = p1 - - # 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 dependent_regions_restricted: Dict[Tuple[str, ...], List[str]] = { @@ -801,8 +759,8 @@ class Hint(IntEnum): ["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", "West Garden after Boss", "West Garden Hero's Grave"): - ["West Garden", "West Garden Laurels Exit", "West Garden after Boss", "West Garden Hero's Grave"], + ("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"): @@ -812,10 +770,10 @@ class Hint(IntEnum): ["Frog Stairs Upper", "Frog Stairs Lower", "Frog Stairs to Frog's Domain"], ("Frog's Domain",): ["Frog's Domain", "Frog's Domain Back"], - ("Library Exterior Ladder", "Library Exterior Tree"): - ["Library Exterior Ladder", "Library Exterior Tree"], - ("Library Hall", "Library Hero's Grave"): - ["Library Hall", "Library Hero's Grave"], + ("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", "Library Hero's Grave Region"], ("Library Lab", "Library Lab Lower", "Library Portal"): ["Library Lab", "Library Lab Lower", "Library Portal"], ("Fortress Courtyard Upper",): @@ -831,16 +789,16 @@ class Hint(IntEnum): ["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", "Fortress Hero's Grave"): - ["Fortress Grave Path", "Fortress Grave Path Dusty Entrance", "Fortress Hero's Grave"], + ("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"], - ("Monastery Back", "Monastery Hero's Grave"): - ["Monastery Back", "Monastery Hero's Grave"], + ["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"): ["Quarry", "Quarry Portal", "Lower Quarry", "Quarry Entry", "Quarry Back", "Quarry Monastery Entry", "Lower Quarry Zig Door"], @@ -855,18 +813,18 @@ class Hint(IntEnum): ("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", + ["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"): - ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave"], + ("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", "Far Shore to East Forest", "Far Shore to Quarry", - "Far Shore to Fortress", "Far Shore to Library", "Far Shore to West Garden"): - ["Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", - "Far Shore to Fortress", "Far Shore to Library", "Far Shore to West Garden"] + ("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"] } @@ -912,9 +870,9 @@ class Hint(IntEnum): ["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", "West Garden after Boss", "West Garden Hero's Grave", + ("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", "West Garden after Boss", "West Garden Hero's Grave", + ["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"): @@ -924,10 +882,10 @@ class Hint(IntEnum): ["Frog Stairs Upper", "Frog Stairs Lower", "Frog Stairs to Frog's Domain"], ("Frog's Domain",): ["Frog's Domain", "Frog's Domain Back"], - ("Library Exterior Ladder", "Library Exterior Tree"): - ["Library Exterior Ladder", "Library Exterior Tree"], - ("Library Hall", "Library Hero's Grave"): - ["Library Hall", "Library Hero's Grave"], + ("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", "Library Hero's Grave Region"], ("Library Lab", "Library Lab Lower", "Library Portal"): ["Library Lab", "Library Lab Lower", "Library Portal"], ("Fortress Exterior from East Forest", "Fortress Exterior from Overworld", @@ -940,17 +898,17 @@ class Hint(IntEnum): ["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", "Fortress Hero's Grave"): - ["Fortress Grave Path", "Fortress Grave Path Dusty Entrance", "Fortress Hero's Grave"], + ("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", - "Fortress Hero's Grave"], + ["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"): - ["Monastery Front", "Monastery Back", "Monastery Hero's Grave"], + ("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"): ["Quarry", "Quarry Portal", "Lower Quarry", "Quarry Entry", "Quarry Back", "Quarry Monastery Entry", "Lower Quarry Zig Door"], @@ -964,21 +922,22 @@ class Hint(IntEnum): ["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", + ("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", + ["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"], - ("Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave"): - ["Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Front", "Swamp Mid", - "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", "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", "Far Shore to East Forest", "Far Shore to Quarry", - "Far Shore to Fortress", "Far Shore to Library", "Far Shore to West Garden"): - ["Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", - "Far Shore to Fortress", "Far Shore to Library", "Far Shore to West Garden"] + ("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"] } @@ -1027,9 +986,9 @@ class Hint(IntEnum): ("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", "West Garden after Boss", "West Garden Hero's Grave", + ("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", "West Garden after Boss", "West Garden Hero's Grave", + ["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"): @@ -1039,10 +998,10 @@ class Hint(IntEnum): ["Frog Stairs Upper", "Frog Stairs Lower", "Frog Stairs to Frog's Domain"], ("Frog's Domain",): ["Frog's Domain", "Frog's Domain Back"], - ("Library Exterior Ladder", "Library Exterior Tree"): - ["Library Exterior Ladder", "Library Exterior Tree"], - ("Library Hall", "Library Hero's Grave"): - ["Library Hall", "Library Hero's Grave"], + ("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", "Library Hero's Grave Region"], ("Library Lab", "Library Lab Lower", "Library Portal"): ["Library Lab", "Library Lab Lower", "Library Portal"], # can use ice grapple or ladder storage to get from any ladder to upper @@ -1057,18 +1016,18 @@ class Hint(IntEnum): ["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", "Fortress Hero's Grave"): - ["Fortress Grave Path", "Fortress Grave Path Dusty Entrance", "Fortress Hero's Grave"], + ("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", - "Fortress Hero's Grave"], + ["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"): - ["Monastery Front", "Monastery Back", "Monastery Hero's Grave"], + ("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"): @@ -1082,16 +1041,17 @@ class Hint(IntEnum): ["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", - "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "Swamp Ledge under Cathedral Door"): - ["Swamp Front", "Swamp Mid", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance", - "Back of Swamp", "Back of Swamp Laurels Area", "Swamp Hero's Grave", "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"): + ["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", "Far Shore to East Forest", "Far Shore to Quarry", - "Far Shore to Fortress", "Far Shore to Library", "Far Shore to West Garden"): - ["Far Shore", "Far Shore to Spawn", "Far Shore to East Forest", "Far Shore to Quarry", - "Far Shore to Fortress", "Far Shore to Library", "Far Shore to West Garden"] + ("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"] } diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index b46eda8e5a99..0e84dd654739 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -298,13 +298,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: ice grapple through temple door regions["Overworld"].connect( connecting_region=regions["Overworld Temple Door"], - name="Overworld to Temple Door", rule=lambda state: state.has_all({"Ring Eastern Bell", "Ring Western Bell"}, player) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) regions["Overworld Temple Door"].connect( connecting_region=regions["Overworld above Patrol Cave"], - name="Temple Door to Overworld Grapple", rule=lambda state: state.has(grapple, player)) # Overworld side areas @@ -465,11 +463,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re rule=lambda state: has_lantern(state, player, options)) # West Garden - regions["West Garden Laurels Exit"].connect( + regions["West Garden Laurels Exit Region"].connect( connecting_region=regions["West Garden"], rule=lambda state: state.has(laurels, player)) regions["West Garden"].connect( - connecting_region=regions["West Garden Laurels Exit"], + connecting_region=regions["West Garden Laurels Exit Region"], rule=lambda state: state.has(laurels, player)) regions["West Garden after Boss"].connect( @@ -480,9 +478,9 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re rule=lambda state: state.has(laurels, player) or has_sword(state, player)) regions["West Garden"].connect( - connecting_region=regions["West Garden Hero's Grave"], + connecting_region=regions["West Garden Hero's Grave Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - regions["West Garden Hero's Grave"].connect( + regions["West Garden Hero's Grave Region"].connect( connecting_region=regions["West Garden"]) regions["West Garden Portal"].connect( @@ -567,18 +565,18 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re rule=lambda state: state.has(grapple, player)) # Library - regions["Library Exterior Tree"].connect( - connecting_region=regions["Library Exterior Ladder"], + regions["Library Exterior Tree Region"].connect( + connecting_region=regions["Library Exterior Ladder Region"], rule=lambda state: state.has(grapple, player) or state.has(laurels, player)) - regions["Library Exterior Ladder"].connect( - connecting_region=regions["Library Exterior Tree"], + regions["Library Exterior Ladder Region"].connect( + connecting_region=regions["Library Exterior Tree Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) and (state.has(grapple, player) or state.has(laurels, player))) regions["Library Hall"].connect( - connecting_region=regions["Library Hero's Grave"], + connecting_region=regions["Library Hero's Grave Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - regions["Library Hero's Grave"].connect( + regions["Library Hero's Grave Region"].connect( connecting_region=regions["Library Hall"]) regions["Library Lab Lower"].connect( @@ -644,26 +642,24 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: ice grapple through the big gold door, can do it both ways regions["Eastern Vault Fortress"].connect( connecting_region=regions["Eastern Vault Fortress Gold Door"], - name="Fortress to Gold Door", rule=lambda state: state.has_all({"Activate Eastern Vault West Fuses", "Activate Eastern Vault East Fuse"}, player) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) regions["Eastern Vault Fortress Gold Door"].connect( connecting_region=regions["Eastern Vault Fortress"], - name="Gold Door to Fortress", rule=lambda state: has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Fortress Grave Path"].connect( - connecting_region=regions["Fortress Grave Path Dusty Entrance"], + connecting_region=regions["Fortress Grave Path Dusty Entrance Region"], rule=lambda state: state.has(laurels, player)) - regions["Fortress Grave Path Dusty Entrance"].connect( + regions["Fortress Grave Path Dusty Entrance Region"].connect( connecting_region=regions["Fortress Grave Path"], rule=lambda state: state.has(laurels, player)) regions["Fortress Grave Path"].connect( - connecting_region=regions["Fortress Hero's Grave"], + connecting_region=regions["Fortress Hero's Grave Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - regions["Fortress Hero's Grave"].connect( + regions["Fortress Hero's Grave Region"].connect( connecting_region=regions["Fortress Grave Path"]) # nmg: ice grapple from upper grave path to lower @@ -673,7 +669,6 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Fortress Arena"].connect( connecting_region=regions["Fortress Arena Portal"], - name="Fortress Arena to Fortress Portal", rule=lambda state: state.has("Activate Eastern Vault West Fuses", player)) regions["Fortress Arena Portal"].connect( connecting_region=regions["Fortress Arena"]) @@ -688,7 +683,6 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Quarry Entry"].connect( connecting_region=regions["Quarry Portal"], - name="Quarry to Quarry Portal", rule=lambda state: state.has("Activate Quarry Fuse", player)) regions["Quarry Portal"].connect( connecting_region=regions["Quarry Entry"]) @@ -728,7 +722,6 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: bring a scav over, then ice grapple through the door regions["Lower Quarry"].connect( connecting_region=regions["Lower Quarry Zig Door"], - name="Quarry to Zig Door", rule=lambda state: state.has("Activate Quarry Fuse", player) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) @@ -745,9 +738,9 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re rule=lambda state: state.has(laurels, player) and options.logic_rules) regions["Monastery Back"].connect( - connecting_region=regions["Monastery Hero's Grave"], + connecting_region=regions["Monastery Hero's Grave Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - regions["Monastery Hero's Grave"].connect( + regions["Monastery Hero's Grave Region"].connect( connecting_region=regions["Monastery Back"]) # Ziggurat @@ -785,7 +778,6 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Rooted Ziggurat Portal"].connect( connecting_region=regions["Rooted Ziggurat Portal Room Exit"], - name="Zig Portal Room Exit", rule=lambda state: state.has("Activate Ziggurat Fuse", player)) regions["Rooted Ziggurat Portal Room Exit"].connect( connecting_region=regions["Rooted Ziggurat Portal"], @@ -805,10 +797,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: ice grapple through cathedral door, can do it both ways regions["Swamp Mid"].connect( - connecting_region=regions["Swamp to Cathedral Main Entrance"], + connecting_region=regions["Swamp to Cathedral Main Entrance Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) - regions["Swamp to Cathedral Main Entrance"].connect( + regions["Swamp to Cathedral Main Entrance Region"].connect( connecting_region=regions["Swamp Mid"], rule=lambda state: has_ice_grapple_logic(False, state, player, options, ability_unlocks)) @@ -840,9 +832,9 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re and has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Back of Swamp"].connect( - connecting_region=regions["Swamp Hero's Grave"], + connecting_region=regions["Swamp Hero's Grave Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - regions["Swamp Hero's Grave"].connect( + regions["Swamp Hero's Grave Region"].connect( connecting_region=regions["Back of Swamp"]) regions["Cathedral Gauntlet Checkpoint"].connect( @@ -857,45 +849,41 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # Far Shore regions["Far Shore"].connect( - connecting_region=regions["Far Shore to Spawn"], + connecting_region=regions["Far Shore to Spawn Region"], rule=lambda state: state.has(laurels, player)) - regions["Far Shore to Spawn"].connect( + regions["Far Shore to Spawn Region"].connect( connecting_region=regions["Far Shore"], rule=lambda state: state.has(laurels, player)) regions["Far Shore"].connect( - connecting_region=regions["Far Shore to East Forest"], + connecting_region=regions["Far Shore to East Forest Region"], rule=lambda state: state.has(laurels, player)) - regions["Far Shore to East Forest"].connect( + regions["Far Shore to East Forest Region"].connect( connecting_region=regions["Far Shore"], rule=lambda state: state.has(laurels, player)) regions["Far Shore"].connect( - connecting_region=regions["Far Shore to West Garden"], - name="Far Shore to West Garden", + connecting_region=regions["Far Shore to West Garden Region"], rule=lambda state: state.has("Activate West Garden Fuse", player)) - regions["Far Shore to West Garden"].connect( + regions["Far Shore to West Garden Region"].connect( connecting_region=regions["Far Shore"]) regions["Far Shore"].connect( - connecting_region=regions["Far Shore to Quarry"], - name="Far Shore to Quarry", + connecting_region=regions["Far Shore to Quarry Region"], rule=lambda state: state.has("Activate Quarry Fuse", player)) - regions["Far Shore to Quarry"].connect( + regions["Far Shore to Quarry Region"].connect( connecting_region=regions["Far Shore"]) regions["Far Shore"].connect( - connecting_region=regions["Far Shore to Fortress"], - name="Far Shore to Fortress", + connecting_region=regions["Far Shore to Fortress Region"], rule=lambda state: state.has("Activate Eastern Vault West Fuses", player)) - regions["Far Shore to Fortress"].connect( + regions["Far Shore to Fortress Region"].connect( connecting_region=regions["Far Shore"]) regions["Far Shore"].connect( - connecting_region=regions["Far Shore to Library"], - name="Far Shore to Library", + connecting_region=regions["Far Shore to Library Region"], rule=lambda state: state.has("Activate Library Fuse", player)) - regions["Far Shore to Library"].connect( + regions["Far Shore to Library Region"].connect( connecting_region=regions["Far Shore"]) # Misc diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 982f3af1fd5e..8bd8bea2697a 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -1,7 +1,7 @@ from typing import Dict, List, Set, Tuple, TYPE_CHECKING from BaseClasses import Region, ItemClassification, Item, Location from .locations import location_table -from .er_data import Portal, tunic_er_regions, portal_mapping, hallway_helper, hallway_helper_ur, \ +from .er_data import Portal, tunic_er_regions, portal_mapping, \ dependent_regions_restricted, dependent_regions_nmg, dependent_regions_ur from .er_rules import set_er_region_rules from worlds.generic import PlandoConnection @@ -18,118 +18,23 @@ class TunicERLocation(Location): game: str = "TUNIC" -def create_er_regions(world: "TunicWorld") -> Tuple[Dict[Portal, Portal], Dict[int, str]]: +def create_er_regions(world: "TunicWorld") -> Dict[Portal, Portal]: regions: Dict[str, Region] = {} portal_pairs: Dict[Portal, Portal] = pair_portals(world) - logic_rules = world.options.logic_rules # output the entrances to the spoiler log here for convenience for portal1, portal2 in portal_pairs.items(): world.multiworld.spoiler.set_entrance(portal1.name, portal2.name, "both", world.player) - # check if a portal leads to a hallway. if it does, update the hint text accordingly - def hint_helper(portal: Portal, hint_string: str = "") -> str: - # start by setting it as the name of the portal, for the case we're not using the hallway helper - if hint_string == "": - hint_string = portal.name - - # unrestricted has fewer hallways, like the well rail - if logic_rules == "unrestricted": - hallways = hallway_helper_ur - else: - hallways = hallway_helper - - if portal.scene_destination() in hallways: - # if we have a hallway, we want the region rather than the portal name - if hint_string == portal.name: - hint_string = portal.region - # library exterior is two regions, we just want to fix up the name - if hint_string in {"Library Exterior Tree", "Library Exterior Ladder"}: - hint_string = "Library Exterior" - - # search through the list for the other end of the hallway - for portala, portalb in portal_pairs.items(): - if portala.scene_destination() == hallways[portal.scene_destination()]: - # if we find that we have a chain of hallways, do recursion - if portalb.scene_destination() in hallways: - hint_region = portalb.region - if hint_region in {"Library Exterior Tree", "Library Exterior Ladder"}: - hint_region = "Library Exterior" - hint_string = hint_region + " then " + hint_string - hint_string = hint_helper(portalb, hint_string) - else: - # if we didn't find a chain, get the portal name for the end of the chain - hint_string = portalb.name + " then " + hint_string - return hint_string - # and then the same thing for the other portal, since we have to check each separately - if portalb.scene_destination() == hallways[portal.scene_destination()]: - if portala.scene_destination() in hallways: - hint_region = portala.region - if hint_region in {"Library Exterior Tree", "Library Exterior Ladder"}: - hint_region = "Library Exterior" - hint_string = hint_region + " then " + hint_string - hint_string = hint_helper(portala, hint_string) - else: - hint_string = portala.name + " then " + hint_string - return hint_string - return hint_string - - # create our regions, give them hint text if they're in a spot where it makes sense to - # we're limiting which ones get hints so that it still gets that ER feel with a little less BS for region_name, region_data in tunic_er_regions.items(): - hint_text = "error" - if region_data.hint == 1: - for portal1, portal2 in portal_pairs.items(): - if portal1.region == region_name: - hint_text = hint_helper(portal2) - break - if portal2.region == region_name: - hint_text = hint_helper(portal1) - break - regions[region_name] = Region(region_name, world.player, world.multiworld, hint_text) - elif region_data.hint == 2: - for portal1, portal2 in portal_pairs.items(): - if portal1.scene() == tunic_er_regions[region_name].game_scene: - hint_text = hint_helper(portal2) - break - if portal2.scene() == tunic_er_regions[region_name].game_scene: - hint_text = hint_helper(portal1) - break - regions[region_name] = Region(region_name, world.player, world.multiworld, hint_text) - elif region_data.hint == 3: - # west garden portal item is at a dead end in restricted, otherwise just in west garden - if region_name == "West Garden Portal Item": - if world.options.logic_rules: - for portal1, portal2 in portal_pairs.items(): - if portal1.scene() == "Archipelagos Redux": - hint_text = hint_helper(portal2) - break - if portal2.scene() == "Archipelagos Redux": - hint_text = hint_helper(portal1) - break - regions[region_name] = Region(region_name, world.player, world.multiworld, hint_text) - else: - for portal1, portal2 in portal_pairs.items(): - if portal1.region == "West Garden Portal": - hint_text = hint_helper(portal2) - break - if portal2.region == "West Garden Portal": - hint_text = hint_helper(portal1) - break - regions[region_name] = Region(region_name, world.player, world.multiworld, hint_text) - else: - regions[region_name] = Region(region_name, world.player, world.multiworld) + regions[region_name] = Region(region_name, world.player, world.multiworld) set_er_region_rules(world, world.ability_unlocks, regions, portal_pairs) - er_hint_data: Dict[int, str] = {} for location_name, location_id in world.location_name_to_id.items(): region = regions[location_table[location_name].er_region] location = TunicERLocation(world.player, location_name, location_id, region) region.locations.append(location) - if region.name == region.hint_text: - continue - er_hint_data[location.address] = region.hint_text create_randomized_entrances(portal_pairs, regions) @@ -144,9 +49,7 @@ def hint_helper(portal: Portal, hint_string: str = "") -> str: world.multiworld.completion_condition[world.player] = lambda state: state.has("Victory", world.player) victory_region.locations.append(victory_location) - portals_and_hints = (portal_pairs, er_hint_data) - - return portals_and_hints + return portal_pairs tunic_events: Dict[str, str] = { @@ -351,7 +254,7 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: break if portal1 is None: raise Exception("Too many shops in the pool, or something else went wrong") - portal2 = Portal(name="Shop Portal", region=f"Shop Entrance {i + 1}", destination="Previous Region_") + portal2 = Portal(name=f"Shop Portal {i + 1}", region=f"Shop Entrance {i + 1}", destination="Previous Region_") portal_pairs[portal1] = portal2 # connect dead ends to random non-dead ends @@ -379,10 +282,10 @@ def create_randomized_entrances(portal_pairs: Dict[Portal, Portal], regions: Dic for portal1, portal2 in portal_pairs.items(): region1 = regions[portal1.region] region2 = regions[portal2.region] - region1.connect(region2, f"{portal1.name} -> {portal2.name}") + region1.connect(connecting_region=region2, name=portal1.name) # prevent the logic from thinking you can get to any shop-connected region from the shop if portal2.name != "Shop": - region2.connect(region1, f"{portal2.name} -> {portal1.name}") + region2.connect(connecting_region=region1, name=portal2.name) # loop through the static connections, return regions you can reach from this region @@ -451,7 +354,7 @@ def gate_before_switch(check_portal: Portal, two_plus: List[Portal]) -> bool: 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"]: + if portal.region in ["Swamp Front", "Swamp to Cathedral Treasure Room", "Swamp to Cathedral Main Entrance Region"]: i += 1 if i == 4: return True diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index 3cfe845ceffe..fdd014ba7310 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -175,7 +175,7 @@ class TunicLocationData(NamedTuple): "Sealed Temple - Page Pickup": TunicLocationData("Overworld", "Sealed Temple", ladder_region="Sealed Temple"), "Hourglass Cave - Hourglass Chest": TunicLocationData("Overworld", "Hourglass Cave", ladder_region="Overworld Beach"), "Far Shore - Secret Chest": TunicLocationData("Overworld", "Far Shore"), - "Far Shore - Page Pickup": TunicLocationData("Overworld", "Far Shore to Spawn"), + "Far Shore - Page Pickup": TunicLocationData("Overworld", "Far Shore to Spawn Region"), "Coins in the Well - 10 Coins": TunicLocationData("Overworld", "Overworld", location_group="well"), "Coins in the Well - 15 Coins": TunicLocationData("Overworld", "Overworld", location_group="well"), "Coins in the Well - 3 Coins": TunicLocationData("Overworld", "Overworld", location_group="well"), From ebaf64daea17935e153eb108b37c9140987bd58a Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 2 Mar 2024 16:40:34 -0500 Subject: [PATCH 13/82] Updated ls er rules --- worlds/tunic/__init__.py | 4 +- worlds/tunic/er_rules.py | 543 ++++++++++++++++----------------------- 2 files changed, 218 insertions(+), 329 deletions(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index 1dec6c882f6f..e271bf1d9bad 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -253,11 +253,11 @@ def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]): name, connection = paths[location.parent_region] while connection != ("Menu", None): name, connection = connection - if name.endswith("(LS)"): - name = name.replace(" (LS)", "") # was getting some cases like Library Grave -> Library Grave -> other place if name in portal_names and name != previous_name: previous_name = name + if "(LS)" in name: + name, _ = name.split(" (LS) ") path_to_loc.append(name) hint_text = "" for transition in reversed(path_to_loc): diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 0e84dd654739..53d25e91e7c2 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1,4 +1,4 @@ -from typing import Dict, Set, TYPE_CHECKING +from typing import Dict, Set, List, Tuple, TYPE_CHECKING from worlds.generic.Rules import set_rule, forbid_item from .rules import has_ability, has_sword, has_stick, has_ice_grapple_logic, has_lantern, has_mask, can_ladder_storage from .er_data import Portal @@ -35,7 +35,7 @@ def has_ladder(ladder: str, state: CollectionState, player: int, options: TunicO return state.has(ladder, player) -def has_any_ladders(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): +def has_any_ladder(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): if not options.ladder_rando: return True else: @@ -909,336 +909,225 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # connecting the regions portals are in to other portals you can access via ladder storage # using has_stick instead of can_ladder_storage since it's already checking the logic rules if options.logic_rules == "unrestricted": - def get_paired_region(portal_sd: str) -> str: + def get_portal_info(portal_sd: str) -> (str, str): for portal1, portal2 in portal_pairs.items(): if portal1.scene_destination() == portal_sd: - return portal2.region + return portal1.name, portal2.region if portal2.scene_destination() == portal_sd: - return portal1.region + return portal2.name, portal1.region raise Exception("no matches found in get_paired_region") - # The upper Swamp entrance - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Swamp Redux 2_wall")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}, - state, player, options)) - # Furnace entrance, next to the sign that leads to West Garden - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Furnace_gyro_west")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}, - state, player, options)) - - # Upper West Garden entry, by the belltower - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Archipelagos Redux_upper")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}, - state, player, options)) - - # Ruined Passage - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Ruins Passage_east")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}, - state, player, options)) - - # Well rail, west side. Can ls in town, get extra height by going over the portal pad - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Sewer_west_aqueduct")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", - "Ladder to Quarry"}, state, player, options)) - # Well rail, east side. Need some height from the temple stairs - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Furnace_gyro_upper_north")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", - "Ladder to Quarry"}, state, player, options)) - - # Quarry entry - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Darkwoods Tunnel_")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", - "Ladder to Well"}, state, player, options)) - - # East Forest entry - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Forest Belltower_")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", - "Ladder to Well", "Ladders near Patrol Cave", "Ladder to Quarry", - "Ladders near Dark Tomb"}, state, player, options)) - - # Fortress entry - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Fortress Courtyard_")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", - "Ladder to Well", "Ladders near Patrol Cave", "Ladder to Quarry", - "Ladders near Dark Tomb"}, state, player, options)) - - # Patrol Cave entry - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, PatrolCave_")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", - "Ladder to Well", "Overworld Shortcut Ladders", "Ladder to Quarry", - "Ladders near Dark Tomb"}, state, player, options)) - - # Special Shop entry - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, ShopSpecial_")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", - "Ladder to Well", "Overworld Shortcut Ladders", "Ladders near Patrol Cave", - "Ladder to Quarry", "Ladders near Dark Tomb"}, state, player, options)) - - # Temple Rafters - regions["Overworld"].connect( - regions[get_paired_region("Overworld Redux, Temple_rafters")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", - "Ladder to Well", "Overworld Shortcut Ladders", "Ladders near Patrol Cave", - "Ladder to Quarry", "Ladders near Dark Tomb"}, state, player, options)) - - # Mountain Stairs - regions["Overworld above Quarry Entrance"].connect( - regions[get_paired_region("Overworld Redux, Mountain_")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders near Dark Tomb", state, player, options)) - - # ladders to west belltower -> ruined passage back, well rail, quarry, and higher - - # West Garden entry by the Furnace - regions["Overworld Beach"].connect( - regions[get_paired_region("Overworld Redux, Archipelagos Redux_lower")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"West Overworld Ladders", "Ladder to Ruined Atoll"}, state, player, options)) - # West Garden laurels entry - regions["Overworld Beach"].connect( - regions[get_paired_region("Overworld Redux, Archipelagos Redux_lowest")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"West Overworld Ladders", "Ladder to Ruined Atoll"}, state, player, options)) - # Swamp lower entrance - regions["Overworld Beach"].connect( - regions[get_paired_region("Overworld Redux, Swamp Redux 2_conduit")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"West Overworld Ladders", "Ladder to Ruined Atoll"}, state, player, options)) - # Rotating Lights entrance - regions["Overworld Beach"].connect( - regions[get_paired_region("Overworld Redux, Overworld Cave_")], - rule=lambda state: has_stick(state, player) - and has_any_ladders({"West Overworld Ladders", "Ladder to Ruined Atoll"}, state, player, options)) - - # West Garden main entry from swamp ladder - regions["Overworld Swamp Lower Entry"].connect( - regions[get_paired_region("Overworld Redux, Archipelagos Redux_lower")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladder to Swamp", state, player, options)) - # Maze Cave entry from swamp ladder - regions["Overworld Swamp Lower Entry"].connect( - regions[get_paired_region("Overworld Redux, Maze Room_")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladder to Swamp", state, player, options)) - # Hourglass Cave entry from swamp ladder - regions["Overworld Swamp Lower Entry"].connect( - regions[get_paired_region("Overworld Redux, Town Basement_beach")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladder to Swamp", state, player, options)) - # Lower Atoll entry from swamp ladder - regions["Overworld Swamp Lower Entry"].connect( - regions[get_paired_region("Overworld Redux, Atoll Redux_lower")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladder to Swamp", state, player, options)) - # Lowest West Garden entry from swamp ladder - regions["Overworld Swamp Lower Entry"].connect( - regions[get_paired_region("Overworld Redux, Archipelagos Redux_lowest")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladder to Swamp", state, player, options)) - - # from the ladders by the belltower - # Ruined Passage - regions["Overworld to West Garden Upper"].connect( - regions[get_paired_region("Overworld Redux, Ruins Passage_east")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders to West Belltower", state, player, options)) - # Well rail, west side. Can ls in town, get extra height by going over the portal pad - regions["Overworld to West Garden Upper"].connect( - regions[get_paired_region("Overworld Redux, Sewer_west_aqueduct")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders to West Belltower", state, player, options)) - # Well rail, east side. Need some height from the temple stairs - regions["Overworld to West Garden Upper"].connect( - regions[get_paired_region("Overworld Redux, Furnace_gyro_upper_north")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders to West Belltower", state, player, options)) - # Quarry entry - regions["Overworld to West Garden Upper"].connect( - regions[get_paired_region("Overworld Redux, Darkwoods Tunnel_")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders to West Belltower", state, player, options)) - # East Forest entry - regions["Overworld to West Garden Upper"].connect( - regions[get_paired_region("Overworld Redux, Forest Belltower_")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders to West Belltower", state, player, options)) - # Fortress entry - regions["Overworld to West Garden Upper"].connect( - regions[get_paired_region("Overworld Redux, Fortress Courtyard_")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders to West Belltower", state, player, options)) - # Patrol Cave entry - regions["Overworld to West Garden Upper"].connect( - regions[get_paired_region("Overworld Redux, PatrolCave_")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders to West Belltower", state, player, options)) - # Special Shop entry - regions["Overworld to West Garden Upper"].connect( - regions[get_paired_region("Overworld Redux, ShopSpecial_")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders to West Belltower", state, player, options)) - # Temple Rafters - regions["Overworld to West Garden Upper"].connect( - regions[get_paired_region("Overworld Redux, Temple_rafters")], - rule=lambda state: has_stick(state, player) - and has_ladder("Ladders to West Belltower", state, player, options)) - - # Furnace ladder to the fuse entrance - regions["Furnace Ladder Area"].connect( - regions[get_paired_region("Furnace, Overworld Redux_gyro_upper_north")], - rule=lambda state: has_stick(state, player)) - # Furnace ladder to Dark Tomb - regions["Furnace Ladder Area"].connect( - regions[get_paired_region("Furnace, Crypt Redux_")], - rule=lambda state: has_stick(state, player)) - # Furnace ladder to the West Garden connector - regions["Furnace Ladder Area"].connect( - regions[get_paired_region("Furnace, Overworld Redux_gyro_west")], - rule=lambda state: has_stick(state, player)) - - # West Garden exit after Garden Knight - regions["West Garden"].connect( - regions[get_paired_region("Archipelagos Redux, Overworld Redux_upper")], - rule=lambda state: has_stick(state, player)) - # West Garden laurels exit - regions["West Garden"].connect( - regions[get_paired_region("Archipelagos Redux, Overworld Redux_lowest")], - rule=lambda state: has_stick(state, player)) - - # Frog mouth entrance - regions["Ruined Atoll"].connect( - regions[get_paired_region("Atoll Redux, Frog Stairs_mouth")], - rule=lambda state: has_stick(state, player)) - - # Entrance by the dancing fox holy cross spot - regions["East Forest"].connect( - regions[get_paired_region("East Forest Redux, East Forest Redux Laddercave_upper")], - rule=lambda state: has_stick(state, player)) - - # From the west side of guard house 1 to the east side - regions["Guard House 1 West"].connect( - regions[get_paired_region("East Forest Redux Laddercave, East Forest Redux_gate")], - rule=lambda state: has_stick(state, player)) - regions["Guard House 1 West"].connect( - regions[get_paired_region("East Forest Redux Laddercave, Forest Boss Room_")], - rule=lambda state: has_stick(state, player)) - - # Upper exit from the Forest Grave Path, use ls at the ladder by the gate switch - regions["Forest Grave Path Main"].connect( - regions[get_paired_region("Sword Access, East Forest Redux_upper")], - rule=lambda state: has_stick(state, player)) - - # Fortress exterior shop, ls at the ladder by the telescope - regions["Fortress Exterior from Overworld"].connect( - regions[get_paired_region("Fortress Courtyard, Shop_")], - rule=lambda state: has_stick(state, player)) - # Fortress main entry and grave path lower entry, ls at the ladder by the telescope - regions["Fortress Exterior from Overworld"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress Main_Big Door")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior from Overworld"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress Reliquary_Lower")], - rule=lambda state: has_stick(state, player)) - # Upper exits from the courtyard. Use the ramp in the courtyard, then the blocks north of the first fuse - regions["Fortress Exterior from Overworld"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress Reliquary_Upper")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior from Overworld"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress East_")], - rule=lambda state: has_stick(state, player)) - - # same as above, except from the east side of the area - regions["Fortress Exterior from East Forest"].connect( - regions[get_paired_region("Fortress Courtyard, Overworld Redux_")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior from East Forest"].connect( - regions[get_paired_region("Fortress Courtyard, Shop_")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior from East Forest"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress Main_Big Door")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior from East Forest"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress Reliquary_Lower")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior from East Forest"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress Reliquary_Upper")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior from East Forest"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress East_")], - rule=lambda state: has_stick(state, player)) - - # same as above, except from the Beneath the Vault entrance ladder - regions["Fortress Exterior near cave"].connect( - regions[get_paired_region("Fortress Courtyard, Overworld Redux_")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior near cave"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress Main_Big Door")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior near cave"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress Reliquary_Lower")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior near cave"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress Reliquary_Upper")], - rule=lambda state: has_stick(state, player)) - regions["Fortress Exterior near cave"].connect( - regions[get_paired_region("Fortress Courtyard, Fortress East_")], - rule=lambda state: has_stick(state, player)) - - # ls at the ladder, need to gain a little height to get up the stairs - regions["Lower Mountain"].connect( - regions[get_paired_region("Mountain, Mountaintop_")], - rule=lambda state: has_stick(state, player)) - - # Where the rope is behind Monastery. Connecting here since, if you have this region, you don't need a sword - regions["Quarry Monastery Entry"].connect( - regions[get_paired_region("Quarry Redux, Monastery_back")], - rule=lambda state: has_stick(state, player)) - - # Swamp to Gauntlet - regions["Swamp Mid"].connect( - regions[get_paired_region("Swamp Redux 2, Cathedral Arena_")], - rule=lambda state: has_stick(state, player) - and has_ladder("Swamp Ladders", state, player, options)) - # Swamp to Overworld upper - regions["Swamp"].connect( - regions[get_paired_region("Swamp Redux 2, Overworld Redux_wall")], - rule=lambda state: has_stick(state, player) - and has_ladder("Swamp Ladders", state, player, options)) - # Ladder by the hero grave - regions["Back of Swamp"].connect( - regions[get_paired_region("Swamp Redux 2, Overworld Redux_conduit")], - rule=lambda state: has_stick(state, player)) - regions["Back of Swamp"].connect( - regions[get_paired_region("Swamp Redux 2, Shop_")], - rule=lambda state: has_stick(state, player)) - # Need to put the cathedral HC code mid-flight - regions["Back of Swamp"].connect( - regions[get_paired_region("Swamp Redux 2, Cathedral Redux_secret")], - rule=lambda state: has_stick(state, player) - and has_ability(state, player, holy_cross, options, ability_unlocks)) + ladder_storages: List[Tuple[str, str, Set[str]]] = [ + # The upper Swamp entrance + ("Overworld", "Overworld Redux, Swamp Redux 2_wall", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}), + # Furnace entrance, next to the sign that leads to West Garden + ("Overworld", "Overworld Redux, Furnace_gyro_west", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}), + # Upper West Garden entry, by the belltower + ("Overworld", "Overworld Redux, Archipelagos Redux_upper", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}), + # Ruined Passage + ("Overworld", "Overworld Redux, Ruins Passage_east", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}), + # Well rail, west side. Can ls in town, get extra height by going over the portal pad + ("Overworld", "Overworld Redux, Sewer_west_aqueduct", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Quarry"}), + # Well rail, east side. Need some height from the temple stairs + ("Overworld", "Overworld Redux, Furnace_gyro_upper_north", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Quarry"}), + # Quarry entry + ("Overworld", "Overworld Redux, Darkwoods Tunnel_", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well"}), + + # East Forest entry + ("Overworld", "Overworld Redux, Forest Belltower_", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), + + # Fortress entry + ("Overworld", "Overworld Redux, Fortress Courtyard_", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), + + # Patrol Cave entry + ("Overworld", "Overworld Redux, PatrolCave_", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + "Overworld Shortcut Ladders", "Ladder to Quarry", "Ladders near Dark Tomb"}), + + # Special Shop entry + ("Overworld", "Overworld Redux, ShopSpecial_", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + "Overworld Shortcut Ladders", "Ladders near Patrol Cave", "Ladder to Quarry", + "Ladders near Dark Tomb"}), + + # Temple Rafters + ("Overworld", "Overworld Redux, Temple_rafters", + {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + "Overworld Shortcut Ladders", "Ladders near Patrol Cave", "Ladder to Quarry", + "Ladders near Dark Tomb"}), + + # Mountain Stairs + ("Overworld above Quarry Entrance", "Overworld Redux, Mountain_", + {"Ladders near Dark Tomb"}), + + # West Garden entry by the Furnace + ("Overworld Beach", "Overworld Redux, Archipelagos Redux_lower", + {"West Overworld Ladders", "Ladder to Ruined Atoll"}), + # West Garden laurels entry + ("Overworld Beach", "Overworld Redux, Archipelagos Redux_lowest", + {"West Overworld Ladders", "Ladder to Ruined Atoll"}), + # Swamp lower entrance + ("Overworld Beach", "Overworld Redux, Swamp Redux 2_conduit", + {"West Overworld Ladders", "Ladder to Ruined Atoll"}), + # Rotating Lights entrance + ("Overworld Beach", "Overworld Redux, Overworld Cave_", + {"West Overworld Ladders", "Ladder to Ruined Atoll"}), + + # West Garden main entry from swamp ladder + ("Overworld Swamp Lower Entry", "Overworld Redux, Archipelagos Redux_lower", + {"Ladder to Swamp"}), + # Maze Cave entry from swamp ladder + ("Overworld Swamp Lower Entry", "Overworld Redux, Maze Room_", + {"Ladder to Swamp"}), + # Hourglass Cave entry from swamp ladder + ("Overworld Swamp Lower Entry", "Overworld Redux, Town Basement_beach", + {"Ladder to Swamp"}), + # Lower Atoll entry from swamp ladder + ("Overworld Swamp Lower Entry", "Overworld Redux, Atoll Redux_lower", + {"Ladder to Swamp"}), + # Lowest West Garden entry from swamp ladder + ("Overworld Swamp Lower Entry", "Overworld Redux, Archipelagos Redux_lowest", + {"Ladder to Swamp"}), + + # from the ladders by the belltower + # Ruined Passage + ("Overworld to West Garden Upper", "Overworld Redux, Ruins Passage_east", + {"Ladders to West Belltower"}), + # Well rail, west side. Can ls in town, get extra height by going over the portal pad + ("Overworld to West Garden Upper", "Overworld Redux, Sewer_west_aqueduct", + {"Ladders to West Belltower"}), + # Well rail, east side. Need some height from the temple stairs + ("Overworld to West Garden Upper", "Overworld Redux, Furnace_gyro_upper_north", + {"Ladders to West Belltower"}), + # Quarry entry + ("Overworld to West Garden Upper", "Overworld Redux, Darkwoods Tunnel_", + {"Ladders to West Belltower"}), + # East Forest entry + ("Overworld to West Garden Upper", "Overworld Redux, Forest Belltower_", + {"Ladders to West Belltower"}), + # Fortress entry + ("Overworld to West Garden Upper", "Overworld Redux, Fortress Courtyard_", + {"Ladders to West Belltower"}), + # Patrol Cave entry + ("Overworld to West Garden Upper", "Overworld Redux, PatrolCave_", + {"Ladders to West Belltower"}), + # Special Shop entry + ("Overworld to West Garden Upper", "Overworld Redux, ShopSpecial_", + {"Ladders to West Belltower"}), + # Temple Rafters + ("Overworld to West Garden Upper", "Overworld Redux, Temple_rafters", + {"Ladders to West Belltower"}), + + # Furnace ladder to the fuse entrance + ("Furnace Ladder Area", "Furnace, Overworld Redux_gyro_upper_north", set()), + # Furnace ladder to Dark Tomb + ("Furnace Ladder Area", "Furnace, Crypt Redux_", set()), + # Furnace ladder to the West Garden connector + ("Furnace Ladder Area", "Furnace, Overworld Redux_gyro_west", set()), + + # West Garden exit after Garden Knight + ("West Garden", "Archipelagos Redux, Overworld Redux_upper", set()), + # West Garden laurels exit + ("West Garden", "Archipelagos Redux, Overworld Redux_lowest", set()), + + # Frog mouth entrance + ("Ruined Atoll", "Atoll Redux, Frog Stairs_mouth", set()), + + # Entrance by the dancing fox holy cross spot + ("East Forest", "East Forest Redux, East Forest Redux Laddercave_upper", set()), + + # From the west side of guard house 1 to the east side + ("Guard House 1 West", "East Forest Redux Laddercave, East Forest Redux_gate", set()), + ("Guard House 1 West", "East Forest Redux Laddercave, Forest Boss Room_", set()), + + # Upper exit from the Forest Grave Path, use ls at the ladder by the gate switch + ("Forest Grave Path Main", "Sword Access, East Forest Redux_upper", set()), + + # Fortress exterior shop, ls at the ladder by the telescope + ("Fortress Exterior from Overworld", "Fortress Courtyard, Shop_", set()), + # Fortress main entry and grave path lower entry, ls at the ladder by the telescope + ("Fortress Exterior from Overworld", "Fortress Courtyard, Fortress Main_Big Door", set()), + ("Fortress Exterior from Overworld", "Fortress Courtyard, Fortress Reliquary_Lower", set()), + # Upper exits from the courtyard. Use the ramp in the courtyard, then the blocks north of the first fuse + ("Fortress Exterior from Overworld", "Fortress Courtyard, Fortress Reliquary_Upper", set()), + ("Fortress Exterior from Overworld", "Fortress Courtyard, Fortress East_", set()), + + # same as above, except from the east side of the area + ("Fortress Exterior from East Forest", "Fortress Courtyard, Overworld Redux_", set()), + ("Fortress Exterior from East Forest", "Fortress Courtyard, Shop_", set()), + ("Fortress Exterior from East Forest", "Fortress Courtyard, Fortress Main_Big Door", set()), + ("Fortress Exterior from East Forest", "Fortress Courtyard, Fortress Reliquary_Lower", set()), + ("Fortress Exterior from East Forest", "Fortress Courtyard, Fortress Reliquary_Upper", set()), + ("Fortress Exterior from East Forest", "Fortress Courtyard, Fortress East_", set()), + + # same as above, except from the Beneath the Vault entrance ladder + ("Fortress Exterior near cave", "Fortress Courtyard, Overworld Redux_", set()), + ("Fortress Exterior near cave", "Fortress Courtyard, Fortress Main_Big Door", set()), + ("Fortress Exterior near cave", "Fortress Courtyard, Fortress Reliquary_Lower", set()), + ("Fortress Exterior near cave", "Fortress Courtyard, Fortress Reliquary_Upper", set()), + ("Fortress Exterior near cave", "Fortress Courtyard, Fortress East_", set()), + + # ls at the ladder, need to gain a little height to get up the stairs + ("Lower Mountain", "Mountain, Mountaintop_", set()), + + # Where the rope is behind Monastery. Connecting here since, if you have this region, you don't need a sword + ("Quarry Monastery Entry", "Quarry Redux, Monastery_back", set()), + + # Swamp to Gauntlet + ("Swamp Mid", "Swamp Redux 2, Cathedral Arena_", + {"Swamp Ladders"}), + # Swamp to Overworld upper + ("Swamp Mid", "Swamp Redux 2, Overworld Redux_wall", + {"Swamp Ladders"}), + # Ladder by the hero grave + ("Back of Swamp", "Swamp Redux 2, Overworld Redux_conduit", set()), + ("Back of Swamp", "Swamp Redux 2, Shop_", set()), + # Need to put the cathedral HC code mid-flight + ("Back of Swamp", "Swamp Redux 2, Cathedral Redux_secret", set()), + ] + + for region_name, scene_dest, ladders in ladder_storages: + portal_name, paired_region = get_portal_info(scene_dest) + # this is the only exception, requiring holy cross as well + if portal_name == "Swamp to Cathedral Secret Legend Room Entrance": + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and has_ability(state, player, holy_cross, options, ability_unlocks) + and has_ladder("Swamp Ladders", state, player, options)) + # if no ladder items are required, just do the basic stick only lambda + elif not ladders: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player)) + # if one ladder is required, use has_ladder + elif len(ladders) == 1: + ladder = ladders.pop() + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and has_ladder(ladder, state, player, options)) + # if multiple ladders can be used, use has_any_ladder + else: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and has_any_ladder(ladders, state, player, options)) def set_er_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> None: From ce2237596fb2f0624adf068638bd14355de78162 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 2 Mar 2024 17:41:42 -0500 Subject: [PATCH 14/82] Fix for hints --- worlds/tunic/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index e271bf1d9bad..86212e12aead 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -254,10 +254,10 @@ def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]): while connection != ("Menu", None): name, connection = connection # was getting some cases like Library Grave -> Library Grave -> other place + if "(LS)" in name: + name, _ = name.split(" (LS) ") if name in portal_names and name != previous_name: previous_name = name - if "(LS)" in name: - name, _ = name.split(" (LS) ") path_to_loc.append(name) hint_text = "" for transition in reversed(path_to_loc): From 412f180a5ee6d3bf36316745f304233fe6ca63ba Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Mon, 4 Mar 2024 10:09:48 -0500 Subject: [PATCH 15/82] Simplify has_ladder (thanks medic) --- worlds/tunic/er_rules.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 53d25e91e7c2..b689b3c23f37 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -29,17 +29,11 @@ def has_ladder(ladder: str, state: CollectionState, player: int, options: TunicOptions): - if not options.ladder_rando: - return True - else: - return state.has(ladder, player) + return not options.ladder_rando or state.has(ladder, player) def has_any_ladder(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): - if not options.ladder_rando: - return True - else: - return state.has_any(ladders, player) + return not options.ladder_rando or state.has_any(ladders, player) def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], regions: Dict[str, Region], From a8fdf12eb22c16a8c0ba954c63c5f963f2ac1173 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Mon, 4 Mar 2024 19:48:28 -0500 Subject: [PATCH 16/82] Change name of west overworld ladders --- worlds/tunic/er_rules.py | 36 ++++++++++++++++++------------------ worlds/tunic/items.py | 2 +- worlds/tunic/ladder_rules.py | 2 +- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index b689b3c23f37..8e8938486bb6 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -51,10 +51,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["Overworld Beach"], - rule=lambda state: has_ladder("West Overworld Ladders", state, player, options) or state.has(laurels, player)) + rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) or state.has(laurels, player)) regions["Overworld Beach"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("West Overworld Ladders", state, player, options) or state.has(laurels, player)) + rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) or state.has(laurels, player)) regions["Overworld Beach"].connect( connecting_region=regions["Overworld West Garden Laurels Entry"], @@ -914,50 +914,50 @@ def get_portal_info(portal_sd: str) -> (str, str): ladder_storages: List[Tuple[str, str, Set[str]]] = [ # The upper Swamp entrance ("Overworld", "Overworld Redux, Swamp Redux 2_wall", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), # Furnace entrance, next to the sign that leads to West Garden ("Overworld", "Overworld Redux, Furnace_gyro_west", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), # Upper West Garden entry, by the belltower ("Overworld", "Overworld Redux, Archipelagos Redux_upper", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), # Ruined Passage ("Overworld", "Overworld Redux, Ruins Passage_east", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), # Well rail, west side. Can ls in town, get extra height by going over the portal pad ("Overworld", "Overworld Redux, Sewer_west_aqueduct", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Quarry"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Quarry"}), # Well rail, east side. Need some height from the temple stairs ("Overworld", "Overworld Redux, Furnace_gyro_upper_north", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Quarry"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Quarry"}), # Quarry entry ("Overworld", "Overworld Redux, Darkwoods Tunnel_", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well"}), # East Forest entry ("Overworld", "Overworld Redux, Forest Belltower_", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), # Fortress entry ("Overworld", "Overworld Redux, Fortress Courtyard_", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), # Patrol Cave entry ("Overworld", "Overworld Redux, PatrolCave_", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Overworld Shortcut Ladders", "Ladder to Quarry", "Ladders near Dark Tomb"}), # Special Shop entry ("Overworld", "Overworld Redux, ShopSpecial_", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Overworld Shortcut Ladders", "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), # Temple Rafters ("Overworld", "Overworld Redux, Temple_rafters", - {"Ladders near Weathervane", "Ladder to Swamp", "West Overworld Ladders", "Ladder to Well", + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Overworld Shortcut Ladders", "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), @@ -967,16 +967,16 @@ def get_portal_info(portal_sd: str) -> (str, str): # West Garden entry by the Furnace ("Overworld Beach", "Overworld Redux, Archipelagos Redux_lower", - {"West Overworld Ladders", "Ladder to Ruined Atoll"}), + {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), # West Garden laurels entry ("Overworld Beach", "Overworld Redux, Archipelagos Redux_lowest", - {"West Overworld Ladders", "Ladder to Ruined Atoll"}), + {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), # Swamp lower entrance ("Overworld Beach", "Overworld Redux, Swamp Redux 2_conduit", - {"West Overworld Ladders", "Ladder to Ruined Atoll"}), + {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), # Rotating Lights entrance ("Overworld Beach", "Overworld Redux, Overworld Cave_", - {"West Overworld Ladders", "Ladder to Ruined Atoll"}), + {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), # West Garden main entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Archipelagos Redux_lower", diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 491fee6e1e4a..5530694c36d2 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -162,7 +162,7 @@ class TunicItemData(NamedTuple): "South Atoll Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), "Ladders to Frog's Domain": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), - "West Overworld Ladders": TunicItemData(ItemClassification.progression, 0, 148, "ladders") + "Overworld Town Ladders": TunicItemData(ItemClassification.progression, 0, 148, "ladders") } fool_tiers: List[List[str]] = [ diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index c3ad6176c7eb..79fa51c27f10 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -69,7 +69,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] multiworld.get_entrance("Overworld -> Upper Overworld", player).access_rule = \ lambda state: can_reach_upper_overworld(state, player, options, ability_unlocks) multiworld.get_entrance("Overworld -> Overworld Beach", player).access_rule = \ - lambda state: state.has_any({"West Overworld Ladders", laurels}, player) + lambda state: state.has_any({"Overworld Town Ladders", laurels}, player) multiworld.get_entrance("Overworld Beach -> West Garden", player).access_rule = \ lambda state: state.has(laurels, player) multiworld.get_entrance("West Garden -> Overworld Beach", player).access_rule = \ From 709819f820651ee638c227cb5334b6de1363bb0e Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Mon, 4 Mar 2024 20:10:47 -0500 Subject: [PATCH 17/82] Add beneath the vault ladder --- worlds/tunic/er_data.py | 32 +++++++++++++++++--------------- worlds/tunic/er_rules.py | 14 ++++++++++++++ worlds/tunic/items.py | 3 ++- worlds/tunic/ladder_rules.py | 1 + 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index fd26f24533dd..5a0215fd363c 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -321,7 +321,7 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th destination="Fortress Main_Big Door"), Portal(name="Fortress Courtyard to East Fortress", region="Fortress Courtyard Upper", destination="Fortress East_"), - Portal(name="Fortress Courtyard to Beneath the Earth", region="Fortress Exterior near cave", + Portal(name="Fortress Courtyard to Beneath the Vault", region="Beneath the Vault Entry", destination="Fortress Basement_"), Portal(name="Fortress Courtyard to Forest Belltower", region="Fortress Exterior from East Forest", destination="Forest Belltower_"), @@ -330,9 +330,9 @@ def scene_destination(self) -> str: # full, nonchanging name to interpret by th Portal(name="Fortress Courtyard Shop", region="Fortress Exterior near cave", destination="Shop_"), - Portal(name="Beneath the Earth to Fortress Interior", region="Beneath the Vault Back", + Portal(name="Beneath the Vault to Fortress Interior", region="Beneath the Vault Back", destination="Fortress Main_"), - Portal(name="Beneath the Earth to Fortress Courtyard", region="Beneath the Vault Front", + Portal(name="Beneath the Vault to Fortress Courtyard", region="Beneath the Vault Ladder Exit", destination="Fortress Courtyard_"), Portal(name="Fortress Interior Main Exit", region="Eastern Vault Fortress", @@ -634,8 +634,10 @@ class DeadEnd(IntEnum): "Fortress Exterior from East Forest": RegionInfo("Fortress Courtyard"), "Fortress Exterior from Overworld": RegionInfo("Fortress Courtyard"), "Fortress Exterior near cave": RegionInfo("Fortress Courtyard"), # where the shop and beneath the earth entry are + "Beneath the Vault Entry": RegionInfo("Fortress Courtyard"), "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 Back": RegionInfo("Fortress Basement"), # the vanilla exit point "Eastern Vault Fortress": RegionInfo("Fortress Main"), @@ -780,11 +782,11 @@ class DeadEnd(IntEnum): ["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"): + "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 Front", "Beneath the Vault Back"): - ["Beneath the Vault Front", "Beneath the Vault Back"], + "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",): @@ -889,11 +891,11 @@ class DeadEnd(IntEnum): ("Library Lab", "Library Lab Lower", "Library Portal"): ["Library Lab", "Library Lab Lower", "Library Portal"], ("Fortress Exterior from East Forest", "Fortress Exterior from Overworld", - "Fortress Exterior near cave", "Fortress Courtyard", "Fortress Courtyard Upper"): + "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 Front", "Beneath the Vault Back"): - ["Beneath the Vault Front", "Beneath the Vault Back"], + "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"): @@ -1006,11 +1008,11 @@ class DeadEnd(IntEnum): ["Library Lab", "Library Lab Lower", "Library Portal"], # 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"): + "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 Front", "Beneath the Vault Back"): - ["Beneath the Vault Front", "Beneath the Vault Back"], + "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"], diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 8e8938486bb6..98f884e04221 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -601,6 +601,13 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Fortress Exterior near cave"], rule=lambda state: state.has(laurels, player) or has_ability(state, player, prayer, options, ability_unlocks)) + regions["Fortress Exterior near cave"].connect( + connecting_region=regions["Beneath the Vault Entry"], + rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options)) + regions["Beneath the Vault Entry"].connect( + connecting_region=regions["Fortress Exterior near cave"], + rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options)) + regions["Fortress Courtyard"].connect( connecting_region=regions["Fortress Exterior from Overworld"], rule=lambda state: state.has(laurels, player)) @@ -620,6 +627,13 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Fortress Courtyard Upper"].connect( 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 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)) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 5530694c36d2..430edd657cde 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -162,7 +162,8 @@ class TunicItemData(NamedTuple): "South Atoll Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), "Ladders to Frog's Domain": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), - "Overworld Town Ladders": TunicItemData(ItemClassification.progression, 0, 148, "ladders") + "Overworld Town Ladders": TunicItemData(ItemClassification.progression, 0, 148, "ladders"), + "Ladder to Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 149, "ladders") } fool_tiers: List[List[str]] = [ diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 79fa51c27f10..88283165ef9f 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -118,6 +118,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] or can_ladder_storage(state, player, options) multiworld.get_entrance("East Overworld -> Beneath the Vault", player).access_rule = \ lambda state: has_lantern(state, player, options) \ + and state.has("Ladder to Beneath the Vault", player) \ and (can_ladder_storage(state, player, options) or has_ability(state, player, prayer, options, ability_unlocks) or state.has(laurels, player)) From a1ef58e41c616e177e17c98989db35933f3d9fe6 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Mon, 4 Mar 2024 23:36:02 -0500 Subject: [PATCH 18/82] Rename west bell ladders --- worlds/tunic/er_rules.py | 24 ++++++++++++------------ worlds/tunic/items.py | 2 +- worlds/tunic/ladder_rules.py | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 98f884e04221..1c4c319a4c2c 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -85,14 +85,14 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld Belltower"].connect( connecting_region=regions["Overworld to West Garden Upper"], - rule=lambda state: has_ladder("Ladders to West Belltower", state, player, options)) + rule=lambda state: has_ladder("Ladders to West Bell", state, player, options)) regions["Overworld to West Garden Upper"].connect( connecting_region=regions["Overworld Belltower"], - rule=lambda state: has_ladder("Ladders to West Belltower", state, player, options)) + rule=lambda state: has_ladder("Ladders to West Bell", state, player, options)) regions["Overworld Belltower"].connect( connecting_region=regions["Overworld Belltower at Bell"], - rule=lambda state: has_ladder("Ladders to West Belltower", state, player, options)) + rule=lambda state: has_ladder("Ladders to West Bell", state, player, options)) # long dong, do not make a reverse connection here or to belltower regions["Overworld above Patrol Cave"].connect( @@ -1011,31 +1011,31 @@ def get_portal_info(portal_sd: str) -> (str, str): # from the ladders by the belltower # Ruined Passage ("Overworld to West Garden Upper", "Overworld Redux, Ruins Passage_east", - {"Ladders to West Belltower"}), + {"Ladders to West Bell"}), # Well rail, west side. Can ls in town, get extra height by going over the portal pad ("Overworld to West Garden Upper", "Overworld Redux, Sewer_west_aqueduct", - {"Ladders to West Belltower"}), + {"Ladders to West Bell"}), # Well rail, east side. Need some height from the temple stairs ("Overworld to West Garden Upper", "Overworld Redux, Furnace_gyro_upper_north", - {"Ladders to West Belltower"}), + {"Ladders to West Bell"}), # Quarry entry ("Overworld to West Garden Upper", "Overworld Redux, Darkwoods Tunnel_", - {"Ladders to West Belltower"}), + {"Ladders to West Bell"}), # East Forest entry ("Overworld to West Garden Upper", "Overworld Redux, Forest Belltower_", - {"Ladders to West Belltower"}), + {"Ladders to West Bell"}), # Fortress entry ("Overworld to West Garden Upper", "Overworld Redux, Fortress Courtyard_", - {"Ladders to West Belltower"}), + {"Ladders to West Bell"}), # Patrol Cave entry ("Overworld to West Garden Upper", "Overworld Redux, PatrolCave_", - {"Ladders to West Belltower"}), + {"Ladders to West Bell"}), # Special Shop entry ("Overworld to West Garden Upper", "Overworld Redux, ShopSpecial_", - {"Ladders to West Belltower"}), + {"Ladders to West Bell"}), # Temple Rafters ("Overworld to West Garden Upper", "Overworld Redux, Temple_rafters", - {"Ladders to West Belltower"}), + {"Ladders to West Bell"}), # Furnace ladder to the fuse entrance ("Furnace Ladder Area", "Furnace, Overworld Redux_gyro_upper_north", set()), diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 430edd657cde..2b24e3649137 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -151,7 +151,7 @@ class TunicItemData(NamedTuple): "Ladders near Patrol Cave": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), "Ladder to Well": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), "Well Back Ladder": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), - "Ladders to West Belltower": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), + "Ladders to West Bell": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), "Dark Tomb Ladder": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), "Ladders near Dark Tomb": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 88283165ef9f..d5b0cf3e42d3 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -57,7 +57,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] multiworld.get_entrance("Overworld -> Sealed Temple", player).access_rule = \ lambda state: ((state.has("Ladder Drop to East Forest", player) and can_reach_east_overworld(state, player, options, ability_unlocks)) and - (state.has("Ladders to West Belltower", player) and + (state.has("Ladders to West Bell", player) and ((state.has(laurels, player) and (has_sword(state, player) or state.has(fire_wand, player))) or (state.has_all({lantern, "Dark Tomb Ladder"}, player) and has_sword(state, player)))) or (can_reach_upper_overworld(state, player, options, ability_unlocks) @@ -100,7 +100,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: state.has("Dark Tomb Ladder", player) # dark tomb to west garden has no rule intentionally multiworld.get_entrance("Overworld -> West Garden", player).access_rule = \ - lambda state: (state.has(laurels, player) and state.has("Ladders to West Belltower", player)) \ + lambda state: (state.has(laurels, player) and state.has("Ladders to West Bell", player)) \ or can_ladder_storage(state, player, options) multiworld.get_entrance("Overworld -> Beneath the Well", player).access_rule = \ lambda state: state.has("Ladder to Well", player) @@ -240,7 +240,7 @@ def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, in set_rule(multiworld.get_location("Overworld - [West] Chest After Bell", player), lambda state: state.has(laurels, player) or (has_lantern(state, player, options) and has_sword(state, player) - and state.has_all({"Ladders to West Belltower", "Dark Tomb Ladder"}, player)) + and state.has_all({"Ladders to West Bell", "Dark Tomb Ladder"}, player)) or can_ladder_storage(state, player, options)) set_rule(multiworld.get_location("Overworld - [Northwest] Chest Beneath Quarry Gate", player), lambda state: state.has_any({grapple, laurels}, player) or options.logic_rules) From 96a84e52534f0e53ea551376ff86fd07f2b2493f Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 5 Mar 2024 14:21:28 -0500 Subject: [PATCH 19/82] Revise remove filler to remove traps if there's no filler left --- worlds/tunic/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index 86212e12aead..804a6edfae82 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -129,7 +129,10 @@ def create_items(self) -> None: def remove_filler(amount: int): # Remove filler to make room for other items for _ in range(0, amount): - fill = self.random.choice(available_filler) + if not available_filler: + fill = "Fool Trap" + else: + fill = self.random.choice(available_filler) items_to_create[fill] -= 1 if items_to_create[fill] == 0: available_filler.remove(fill) From a180470987eb7511068cb4cf8575b841a3cd8d9b Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 5 Mar 2024 19:27:07 -0500 Subject: [PATCH 20/82] Rename ladder rando to shuffle ladders --- worlds/tunic/__init__.py | 12 ++++++------ worlds/tunic/er_rules.py | 4 ++-- worlds/tunic/options.py | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index 804a6edfae82..e03b62a3d043 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -74,7 +74,7 @@ def generate_early(self) -> None: self.options.maskless.value = passthrough["maskless"] self.options.hexagon_quest.value = passthrough["hexagon_quest"] self.options.entrance_rando.value = passthrough["entrance_rando"] - self.options.ladder_rando.value = passthrough["ladder_rando"] + self.options.shuffle_ladders.value = passthrough["shuffle_ladders"] def create_item(self, name: str) -> TunicItem: item_data = item_table[name] @@ -137,7 +137,7 @@ def remove_filler(amount: int): if items_to_create[fill] == 0: available_filler.remove(fill) - if self.options.ladder_rando: + if self.options.shuffle_ladders: ladder_count = 0 for item_name, item_data in item_table.items(): if item_data.item_group == "ladders": @@ -199,7 +199,7 @@ def create_regions(self) -> None: self.tunic_portal_pairs[portal1.scene_destination()] = portal2.scene_destination() else: - if self.options.ladder_rando: + if self.options.shuffle_ladders: region_list = tunic_ladder_regions else: region_list = tunic_regions @@ -213,7 +213,7 @@ def create_regions(self) -> None: region.add_exits(exits) for location_name, location_id in self.location_name_to_id.items(): - if self.options.ladder_rando: + if self.options.shuffle_ladders: region = self.multiworld.get_region(location_table[location_name].region, self.player) else: region = self.multiworld.get_region(location_table[location_name].region, self.player) @@ -229,7 +229,7 @@ def create_regions(self) -> None: def set_rules(self) -> None: if self.options.entrance_rando: set_er_location_rules(self, self.ability_unlocks) - elif self.options.ladder_rando: + elif self.options.shuffle_ladders: set_ladder_region_rules(self, self.ability_unlocks) set_ladder_location_rules(self, self.ability_unlocks) else: @@ -282,7 +282,7 @@ def fill_slot_data(self) -> Dict[str, Any]: "lanternless": self.options.lanternless.value, "maskless": self.options.maskless.value, "entrance_rando": self.options.entrance_rando.value, - "ladder_rando": self.options.ladder_rando.value, + "shuffle_ladders": self.options.shuffle_ladders.value, "Hexagon Quest Prayer": self.ability_unlocks["Pages 24-25 (Prayer)"], "Hexagon Quest Holy Cross": self.ability_unlocks["Pages 42-43 (Holy Cross)"], "Hexagon Quest Icebolt": self.ability_unlocks["Pages 52-53 (Icebolt)"], diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 1c4c319a4c2c..26da87308be8 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -29,11 +29,11 @@ def has_ladder(ladder: str, state: CollectionState, player: int, options: TunicOptions): - return not options.ladder_rando or state.has(ladder, player) + return not options.shuffle_ladders or state.has(ladder, player) def has_any_ladder(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): - return not options.ladder_rando or state.has_any(ladders, player) + return not options.shuffle_ladders or state.has_any(ladders, player) def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], regions: Dict[str, Region], diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index e0ef887d90ba..075422609ed6 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -131,10 +131,10 @@ class LaurelsLocation(Choice): default = 0 -class LadderRando(Toggle): +class ShuffleLadders(Toggle): """Removes several of the ladders from the game, requiring you to find their items to get them back. Greatly increases the number of spheres, making it great for asyncs.""" - internal_name = "ladder_rando" + internal_name = "shuffle_ladders" display_name = "Ladder Rando" @@ -154,5 +154,5 @@ class TunicOptions(PerGameCommonOptions): lanternless: Lanternless maskless: Maskless laurels_location: LaurelsLocation - ladder_rando: LadderRando + shuffle_ladders: ShuffleLadders start_inventory_from_pool: StartInventoryPool From 4c0c4a46db955676e3250b0e7c8cd27f911cd228 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 5 Mar 2024 19:35:12 -0500 Subject: [PATCH 21/82] Shuffle options around a bit --- worlds/tunic/options.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index 075422609ed6..c7a2e375fff5 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -135,7 +135,7 @@ class ShuffleLadders(Toggle): """Removes several of the ladders from the game, requiring you to find their items to get them back. Greatly increases the number of spheres, making it great for asyncs.""" internal_name = "shuffle_ladders" - display_name = "Ladder Rando" + display_name = "Shuffle Ladders" @dataclass @@ -144,9 +144,10 @@ class TunicOptions(PerGameCommonOptions): start_with_sword: StartWithSword keys_behind_bosses: KeysBehindBosses ability_shuffling: AbilityShuffling - logic_rules: LogicRules + shuffle_ladders: ShuffleLadders entrance_rando: EntranceRando fixed_shop: FixedShop + logic_rules: LogicRules fool_traps: FoolTraps hexagon_quest: HexagonQuest hexagon_goal: HexagonGoal @@ -154,5 +155,4 @@ class TunicOptions(PerGameCommonOptions): lanternless: Lanternless maskless: Maskless laurels_location: LaurelsLocation - shuffle_ladders: ShuffleLadders start_inventory_from_pool: StartInventoryPool From 0b322b8f15a38facac7d3acd4f1e9c240b801295 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 5 Mar 2024 20:19:37 -0500 Subject: [PATCH 22/82] Make the ladder logic actually get loaded in properly --- worlds/tunic/__init__.py | 2 +- worlds/tunic/locations.py | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index e03b62a3d043..c2370baa80ef 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -214,7 +214,7 @@ def create_regions(self) -> None: for location_name, location_id in self.location_name_to_id.items(): if self.options.shuffle_ladders: - region = self.multiworld.get_region(location_table[location_name].region, self.player) + region = self.multiworld.get_region(location_table[location_name].ladders_region(), self.player) else: region = self.multiworld.get_region(location_table[location_name].region, self.player) location = TunicLocation(self.player, location_name, location_id, region) diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index fdd014ba7310..c62bfd3275b7 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -8,6 +8,9 @@ class TunicLocationData(NamedTuple): ladder_region: Optional[str] = None location_group: str = "region" + def ladders_region(self) -> str: + return self.ladder_region or self.region + location_base_id = 509342400 @@ -103,7 +106,7 @@ class TunicLocationData(NamedTuple): "Frog's Domain - Side Room Grapple Secret": TunicLocationData("Frog's Domain", "Frog's Domain"), "Frog's Domain - Magic Orb Pickup": TunicLocationData("Frog's Domain", "Frog's Domain"), "Librarian - Hexagon Green": TunicLocationData("Library", "Library Arena"), - "Library Hall - Holy Cross Chest": TunicLocationData("Library", "Library Hall", "holy cross"), + "Library Hall - Holy Cross Chest": TunicLocationData("Library", "Library Hall", location_group="holy cross"), "Library Lab - Chest By Shrine 2": TunicLocationData("Library", "Library Lab"), "Library Lab - Chest By Shrine 1": TunicLocationData("Library", "Library Lab"), "Library Lab - Chest By Shrine 3": TunicLocationData("Library", "Library Lab"), @@ -112,7 +115,7 @@ class TunicLocationData(NamedTuple): "Library Lab - Page 1": TunicLocationData("Library", "Library Lab"), "Library Lab - Page 2": TunicLocationData("Library", "Library Lab"), "Hero's Grave - Mushroom Relic": TunicLocationData("Library", "Hero Relic - Library"), - "Lower Mountain - Page Before Door": TunicLocationData("Overworld", "Lower Mountain"), + "Lower Mountain - Page Before Door": TunicLocationData("Overworld", "Lower Mountain", ladder_region="Upper Overworld"), "Changing Room - Normal Chest": TunicLocationData("Overworld", "Changing Room"), "Fortress Courtyard - Chest Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave", ladder_region="East Overworld"), "Fortress Courtyard - Near Fuse": TunicLocationData("Overworld", "Fortress Exterior from Overworld", ladder_region="East Overworld"), @@ -166,10 +169,10 @@ class TunicLocationData(NamedTuple): "Ruined Shop - Chest 2": TunicLocationData("Overworld", "Ruined Shop"), "Ruined Shop - Chest 3": TunicLocationData("Overworld", "Ruined Shop"), "Ruined Passage - Page Pickup": TunicLocationData("Overworld", "Ruined Passage"), - "Shop - Potion 1": TunicLocationData("Overworld", "Shop", "shop"), - "Shop - Potion 2": TunicLocationData("Overworld", "Shop", "shop"), - "Shop - Coin 1": TunicLocationData("Overworld", "Shop", "shop"), - "Shop - Coin 2": TunicLocationData("Overworld", "Shop", "shop"), + "Shop - Potion 1": TunicLocationData("Overworld", "Shop", location_group="shop"), + "Shop - Potion 2": TunicLocationData("Overworld", "Shop", location_group="shop"), + "Shop - Coin 1": TunicLocationData("Overworld", "Shop", location_group="shop"), + "Shop - Coin 2": TunicLocationData("Overworld", "Shop", location_group="shop"), "Special Shop - Secret Page Pickup": TunicLocationData("Overworld", "Special Shop", ladder_region="East Overworld"), "Stick House - Stick Chest": TunicLocationData("Overworld", "Stick House"), "Sealed Temple - Page Pickup": TunicLocationData("Overworld", "Sealed Temple", ladder_region="Sealed Temple"), @@ -190,7 +193,7 @@ class TunicLocationData(NamedTuple): "Overworld - [West] Windmill Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), "Overworld - [Southwest] Haiku Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Beach", ladder_region="Overworld Beach", location_group="holy cross"), "Overworld - [West] Windchimes Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), - "Overworld - [South] Starting Platform Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", "holy cross"), + "Overworld - [South] Starting Platform Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), "Overworld - [Northwest] Golden Obelisk Page": TunicLocationData("Overworld Holy Cross", "Upper Overworld", ladder_region="Upper Overworld", location_group="holy cross"), "Old House - Holy Cross Door Page": TunicLocationData("Overworld Holy Cross", "Old House Back", location_group="holy cross"), "Cube Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Cube Cave", location_group="holy cross"), @@ -199,12 +202,12 @@ class TunicLocationData(NamedTuple): "Southeast Cross Door - Chest 1": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), "Maze Cave - Maze Room Holy Cross": TunicLocationData("Overworld Holy Cross", "Maze Cave", ladder_region="Overworld Beach", location_group="holy cross"), "Caustic Light Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Caustic Light Cave", ladder_region="Swamp", location_group="holy cross"), - "Old House - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Old House Front", "holy cross"), - "Patrol Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Patrol Cave", "holy cross"), + "Old House - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Old House Front", location_group="holy cross"), + "Patrol Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Patrol Cave", location_group="holy cross"), "Ruined Passage - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Ruined Passage", ladder_region="Overworld", location_group="holy cross"), "Hourglass Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Hourglass Cave Tower", ladder_region="Overworld Beach", location_group="holy cross"), "Sealed Temple - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Sealed Temple", ladder_region="Sealed Temple", location_group="holy cross"), - "Fountain Cross Door - Page Pickup": TunicLocationData("Overworld Holy Cross", "Fountain Cross Room", "holy cross"), + "Fountain Cross Door - Page Pickup": TunicLocationData("Overworld Holy Cross", "Fountain Cross Room", location_group="holy cross"), "Secret Gathering Place - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Secret Gathering Place", location_group="holy cross"), "Top of the Mountain - Page At The Peak": TunicLocationData("Overworld Holy Cross", "Top of the Mountain", ladder_region="Upper Overworld", location_group="holy cross"), "Monastery - Monastery Chest": TunicLocationData("Quarry", "Monastery Back"), @@ -296,7 +299,7 @@ class TunicLocationData(NamedTuple): "West Garden - [West Lowlands] Tree Holy Cross Chest": TunicLocationData("West Garden", "West Garden", location_group="holy cross"), "West Garden - [Southeast Lowlands] Outside Cave": TunicLocationData("West Garden", "West Garden"), "West Garden - [Central Lowlands] Chest Beneath Faeries": TunicLocationData("West Garden", "West Garden"), - "West Garden - [North] Behind Holy Cross Door": TunicLocationData("West Garden", "West Garden", "holy cross"), + "West Garden - [North] Behind Holy Cross Door": TunicLocationData("West Garden", "West Garden", location_group="holy cross"), "West Garden - [Central Highlands] Top of Ladder Before Boss": TunicLocationData("West Garden", "West Garden"), "West Garden - [Central Lowlands] Passage Beneath Bridge": TunicLocationData("West Garden", "West Garden"), "West Garden - [North] Across From Page Pickup": TunicLocationData("West Garden", "West Garden"), From 4ed177b01f14ce783dcf17d477463ca2254ea585 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 5 Mar 2024 20:37:18 -0500 Subject: [PATCH 23/82] Make location groups less dumb, add more, remove some --- worlds/tunic/locations.py | 40 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index c62bfd3275b7..d9c137376b8d 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -6,7 +6,7 @@ class TunicLocationData(NamedTuple): region: str er_region: str # entrance rando region ladder_region: Optional[str] = None - location_group: str = "region" + location_group: Optional[str] = None def ladders_region(self) -> str: return self.ladder_region or self.region @@ -74,11 +74,11 @@ def ladders_region(self) -> str: "Forest Grave Path - Obscured Chest": TunicLocationData("East Forest", "Forest Grave Path Main"), "Forest Grave Path - Upper Walkway": TunicLocationData("East Forest", "Forest Grave Path Upper"), "Forest Grave Path - Sword Pickup": TunicLocationData("East Forest", "Forest Grave Path by Grave"), - "Hero's Grave - Tooth Relic": TunicLocationData("East Forest", "Hero Relic - East Forest"), + "Hero's Grave - Tooth Relic": TunicLocationData("East Forest", "Hero Relic - East Forest", location_group="hero relic"), "Fortress Courtyard - From East Belltower": TunicLocationData("East Forest", "Fortress Exterior from East Forest"), "Fortress Leaf Piles - Secret Chest": TunicLocationData("Eastern Vault Fortress", "Fortress Leaf Piles"), "Fortress Arena - Hexagon Red": TunicLocationData("Eastern Vault Fortress", "Fortress Arena"), - "Fortress Arena - Siege Engine/Vault Key Pickup": TunicLocationData("Eastern Vault Fortress", "Fortress Arena"), + "Fortress Arena - Siege Engine/Vault Key Pickup": TunicLocationData("Eastern Vault Fortress", "Fortress Arena", location_group="bosses"), "Fortress East Shortcut - Chest Near Slimes": TunicLocationData("Eastern Vault Fortress", "Fortress East Shortcut Lower"), "Eastern Vault Fortress - [West Wing] Candles Holy Cross": TunicLocationData("Eastern Vault Fortress", "Eastern Vault Fortress", location_group="holy cross"), "Eastern Vault Fortress - [West Wing] Dark Room Chest 1": TunicLocationData("Eastern Vault Fortress", "Eastern Vault Fortress"), @@ -88,7 +88,7 @@ def ladders_region(self) -> str: "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"), - "Hero's Grave - Flowers Relic": TunicLocationData("Eastern Vault Fortress", "Hero Relic - Fortress"), + "Hero's Grave - Flowers Relic": TunicLocationData("Eastern Vault Fortress", "Hero Relic - Fortress", location_group="hero relic"), "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"), @@ -105,7 +105,7 @@ def ladders_region(self) -> str: "Frog's Domain - Side Room Chest": TunicLocationData("Frog's Domain", "Frog's Domain"), "Frog's Domain - Side Room Grapple Secret": TunicLocationData("Frog's Domain", "Frog's Domain"), "Frog's Domain - Magic Orb Pickup": TunicLocationData("Frog's Domain", "Frog's Domain"), - "Librarian - Hexagon Green": TunicLocationData("Library", "Library Arena"), + "Librarian - Hexagon Green": TunicLocationData("Library", "Library Arena", location_group="bosses"), "Library Hall - Holy Cross Chest": TunicLocationData("Library", "Library Hall", location_group="holy cross"), "Library Lab - Chest By Shrine 2": TunicLocationData("Library", "Library Lab"), "Library Lab - Chest By Shrine 1": TunicLocationData("Library", "Library Lab"), @@ -114,7 +114,7 @@ def ladders_region(self) -> str: "Library Lab - Page 3": TunicLocationData("Library", "Library Lab"), "Library Lab - Page 1": TunicLocationData("Library", "Library Lab"), "Library Lab - Page 2": TunicLocationData("Library", "Library Lab"), - "Hero's Grave - Mushroom Relic": TunicLocationData("Library", "Hero Relic - Library"), + "Hero's Grave - Mushroom Relic": TunicLocationData("Library", "Hero Relic - Library", location_group="hero relic"), "Lower Mountain - Page Before Door": TunicLocationData("Overworld", "Lower Mountain", ladder_region="Upper Overworld"), "Changing Room - Normal Chest": TunicLocationData("Overworld", "Changing Room"), "Fortress Courtyard - Chest Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave", ladder_region="East Overworld"), @@ -229,7 +229,7 @@ def ladders_region(self) -> str: "Quarry - [Central] Above Ladder Dash Chest": TunicLocationData("Quarry", "Quarry Monastery Entry"), "Quarry - [West] Upper Area Bombable Wall": TunicLocationData("Quarry Back", "Quarry Back"), "Quarry - [East] Bombable Wall": TunicLocationData("Quarry", "Quarry"), - "Hero's Grave - Ash Relic": TunicLocationData("Quarry", "Hero Relic - Quarry"), + "Hero's Grave - Ash Relic": TunicLocationData("Quarry", "Hero Relic - Quarry", location_group="hero relics"), "Quarry - [West] Shooting Range Secret Path": TunicLocationData("Lower Quarry", "Lower Quarry"), "Quarry - [West] Near Shooting Range": TunicLocationData("Lower Quarry", "Lower Quarry"), "Quarry - [West] Below Shooting Range": TunicLocationData("Lower Quarry", "Lower Quarry"), @@ -250,7 +250,7 @@ def ladders_region(self) -> str: "Rooted Ziggurat Lower - Guarded By Double Turrets": TunicLocationData("Rooted Ziggurat", "Rooted Ziggurat Lower Front"), "Rooted Ziggurat Lower - After 2nd Double Turret Chest": TunicLocationData("Rooted Ziggurat", "Rooted Ziggurat Lower Front"), "Rooted Ziggurat Lower - Guarded By Double Turrets 2": TunicLocationData("Rooted Ziggurat", "Rooted Ziggurat Lower Front"), - "Rooted Ziggurat Lower - Hexagon Blue": TunicLocationData("Rooted Ziggurat", "Rooted Ziggurat Lower Back"), + "Rooted Ziggurat Lower - Hexagon Blue": TunicLocationData("Rooted Ziggurat", "Rooted Ziggurat Lower Back", location_group="bosses"), "Ruined Atoll - [West] Near Kevin Block": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [South] Upper Floor On Power Line": TunicLocationData("Ruined Atoll", "Ruined Atoll Ladder Tops"), "Ruined Atoll - [South] Chest Near Big Crabs": TunicLocationData("Ruined Atoll", "Ruined Atoll"), @@ -292,7 +292,7 @@ def ladders_region(self) -> str: "Swamp - [South Graveyard] Upper Walkway Dash Chest": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), "Swamp - [South Graveyard] Above Big Skeleton": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [Central] Beneath Memorial": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), - "Hero's Grave - Feathers Relic": TunicLocationData("Swamp", "Hero Relic - Swamp"), + "Hero's Grave - Feathers Relic": TunicLocationData("Swamp", "Hero Relic - Swamp", location_group="hero relic"), "West Furnace - Chest": TunicLocationData("West Garden", "Furnace Walking Path"), "Overworld - [West] Near West Garden Entrance": TunicLocationData("West Garden", "Overworld to West Garden from Furnace"), "West Garden - [Central Highlands] Holy Cross (Blue Lines)": TunicLocationData("West Garden", "West Garden", location_group="holy cross"), @@ -311,12 +311,12 @@ def ladders_region(self) -> str: "West Garden - [West Highlands] Upper Left Walkway": TunicLocationData("West Garden", "West Garden"), "West Garden - [Central Lowlands] Chest Beneath Save Point": TunicLocationData("West Garden", "West Garden"), "West Garden - [Central Highlands] Behind Guard Captain": TunicLocationData("West Garden", "West Garden"), - "West Garden - [Central Highlands] After Garden Knight": TunicLocationData("Overworld", "West Garden after Boss", location_group="west garden"), + "West Garden - [Central Highlands] After Garden Knight": TunicLocationData("Overworld", "West Garden after Boss", location_group="bosses"), "West Garden - [South Highlands] Secret Chest Beneath Fuse": TunicLocationData("West Garden", "West Garden"), "West Garden - [East Lowlands] Page Behind Ice Dagger House": TunicLocationData("West Garden", "West Garden Portal Item"), "West Garden - [North] Page Pickup": TunicLocationData("West Garden", "West Garden"), "West Garden House - [Southeast Lowlands] Ice Dagger Pickup": TunicLocationData("West Garden", "Magic Dagger House"), - "Hero's Grave - Effigy Relic": TunicLocationData("West Garden", "Hero Relic - West Garden"), + "Hero's Grave - Effigy Relic": TunicLocationData("West Garden", "Hero Relic - West Garden", location_group="hero relic"), } hexagon_locations: Dict[str, str] = { @@ -327,15 +327,9 @@ def ladders_region(self) -> str: location_name_to_id: Dict[str, int] = {name: location_base_id + index for index, name in enumerate(location_table)} - -def get_loc_group(location_name: str) -> str: - loc_group = location_table[location_name].location_group - if loc_group == "region": - # set loc_group as the region name. Typically, location groups are lowercase - loc_group = location_table[location_name].region.lower() - return loc_group - - -location_name_groups: Dict[str, Set[str]] = { - group: set(item_names) for group, item_names in groupby(sorted(location_table, key=get_loc_group), get_loc_group) -} +location_name_groups: Dict[str, Set[str]] = {} +for loc_name, loc_data in location_table.items(): + if loc_data.location_group: + if loc_data.location_group not in location_name_groups.keys(): + location_name_groups[loc_data.location_group] = set() + location_name_groups[loc_data.location_group].add(loc_name) From 9ca4f737699791467e18a7598ccd6b00857abb8e Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 5 Mar 2024 20:39:02 -0500 Subject: [PATCH 24/82] Update docs to match new groups --- worlds/tunic/docs/en_TUNIC.md | 2 +- worlds/tunic/locations.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/worlds/tunic/docs/en_TUNIC.md b/worlds/tunic/docs/en_TUNIC.md index e957f9eafaf5..8c8d1c92317c 100644 --- a/worlds/tunic/docs/en_TUNIC.md +++ b/worlds/tunic/docs/en_TUNIC.md @@ -61,4 +61,4 @@ For Entrance Rando specifically: Bombs, consumables (non-bomb ones), weapons, melee weapons (stick and sword), keys, hexagons, offerings, hero relics, cards, golden treasures, money, pages, and abilities (the three ability pages). There are also a few groups being used for singular items: laurels, orb, dagger, magic rod, holy cross, prayer, ice rod, and progressive sword. ## What location groups are there? -Holy cross (for all holy cross checks), fairies (for the two fairy checks), well (for the coin well checks), and shop. Additionally, for checks that do not fall into the above categories, the name of the region is the name of the location group. +Holy cross (for all holy cross checks), fairies (for the two fairy checks), well (for the coin well checks), shop, bosses (for the bosses with checks associated with them), and hero relic (for the 6 hero grave checks). diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index d9c137376b8d..fe95176e4598 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -1,5 +1,4 @@ from typing import Dict, NamedTuple, Set, Optional -from itertools import groupby class TunicLocationData(NamedTuple): From 235ab77fad623ce892711ef244010026a16219d4 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 5 Mar 2024 21:43:47 -0500 Subject: [PATCH 25/82] Several logic fixes --- worlds/tunic/ladder_rules.py | 9 ++++++--- worlds/tunic/locations.py | 8 ++++---- worlds/tunic/regions.py | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index d5b0cf3e42d3..5a6e206c570d 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -103,7 +103,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: (state.has(laurels, player) and state.has("Ladders to West Bell", player)) \ or can_ladder_storage(state, player, options) multiworld.get_entrance("Overworld -> Beneath the Well", player).access_rule = \ - lambda state: state.has("Ladder to Well", player) + lambda state: state.has("Ladder to Well", player) and (has_stick(state, player) or state.has(fire_wand, player)) multiworld.get_entrance("Beneath the Well -> Beneath the Well Back", player).access_rule = \ lambda state: state.has("Well Back Ladder", player) # dash to the fuse and have the rear ladder, or dash through the well boss gate in nmg @@ -111,7 +111,8 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: state.has(laurels, player) and (state.has("Well Back Ladder", player) or options.logic_rules) multiworld.get_entrance("Beneath the Well Back -> Beneath the Well", player).access_rule = \ - lambda state: state.has("Well Back Ladder", player) + lambda state: state.has("Well Back Ladder", player) \ + and (has_stick(state, player) or state.has(fire_wand, player)) multiworld.get_entrance("East Overworld -> Eastern Vault Fortress", player).access_rule = \ lambda state: state.has(laurels, player) \ or has_ice_grapple_logic(True, state, player, options, ability_unlocks) \ @@ -123,8 +124,10 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] or has_ability(state, player, prayer, options, ability_unlocks) or state.has(laurels, player)) multiworld.get_entrance("Overworld -> Ruined Atoll", player).access_rule = \ - lambda state: state.has_any({"Ladder to Ruined Atoll", laurels, grapple}, player) \ + lambda state: state.has_any({laurels, grapple}, player) \ or has_ability(state, player, prayer, options, ability_unlocks) + multiworld.get_entrance("Overworld Beach -> Ruined Atoll", player).access_rule = \ + lambda state: state.has("Ladder to Ruined Atoll", player) multiworld.get_entrance("Ruined Atoll -> Frog's Domain", player).access_rule = \ lambda state: state.has("Ladders to Frog's Domain", player) multiworld.get_entrance("Ruined Atoll -> Library", player).access_rule = \ diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index fe95176e4598..0b5763d4b179 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -19,14 +19,14 @@ def ladders_region(self) -> str: "Beneath the Well - [Third Room] Beneath Platform Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Third Room] Tentacle Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Entryway] Obscured Behind Waterfall": TunicLocationData("Beneath the Well", "Beneath the Well Main"), - "Beneath the Well - [Save Room] Upper Floor Chest 1": TunicLocationData("Beneath the Well", "Beneath the Well Back"), - "Beneath the Well - [Save Room] Upper Floor Chest 2": TunicLocationData("Beneath the Well", "Beneath the Well Back"), + "Beneath the Well - [Save Room] Upper Floor Chest 1": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), + "Beneath the Well - [Save Room] Upper Floor Chest 2": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), "Beneath the Well - [Second Room] Underwater Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Back Corridor] Right Secret": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Back Corridor] Left Secret": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Second Room] Obscured Behind Waterfall": TunicLocationData("Beneath the Well", "Beneath the Well Main"), - "Beneath the Well - [Side Room] Chest By Pots": TunicLocationData("Beneath the Well", "Beneath the Well Main"), - "Beneath the Well - [Side Room] Chest By Phrends": TunicLocationData("Beneath the Well", "Beneath the Well Back"), + "Beneath the Well - [Side Room] Chest By Pots": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), + "Beneath the Well - [Side Room] Chest By Phrends": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), "Beneath the Well - [Second Room] Page": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Dark Tomb Checkpoint - [Passage To Dark Tomb] Page Pickup": TunicLocationData("Overworld", "Dark Tomb Checkpoint"), "Cathedral - [1F] Guarded By Lasers": TunicLocationData("Cathedral", "Cathedral"), diff --git a/worlds/tunic/regions.py b/worlds/tunic/regions.py index dd9878865e8f..6f19f5957031 100644 --- a/worlds/tunic/regions.py +++ b/worlds/tunic/regions.py @@ -35,7 +35,7 @@ "Lower Forest": set(), "East Overworld": {"East Forest", "Eastern Vault Fortress", "Beneath the Vault"}, "Upper Overworld": {"Quarry Back", "Sealed Temple"}, - "Overworld Beach": {"West Garden"}, + "Overworld Beach": {"West Garden", "Ruined Atoll"}, "Dark Tomb Front": {"Dark Tomb"}, "Dark Tomb": {"West Garden"}, "Beneath the Well": {"Beneath the Well Back"}, From f3feb6b7f8bcdc5e7445b34c7142d8f64633588b Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 5 Mar 2024 22:02:00 -0500 Subject: [PATCH 26/82] Re-fix that quarry bug --- worlds/tunic/regions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/regions.py b/worlds/tunic/regions.py index 6f19f5957031..2225dcdc3144 100644 --- a/worlds/tunic/regions.py +++ b/worlds/tunic/regions.py @@ -47,7 +47,7 @@ "Eastern Vault Fortress": {"Beneath the Vault"}, "Beneath the Vault": {"Eastern Vault Fortress"}, "Quarry Back": {"Quarry"}, - "Quarry": {"Lower Quarry", "Rooted Ziggurat"}, + "Quarry": {"Lower Quarry"}, "Lower Quarry": {"Rooted Ziggurat"}, "Rooted Ziggurat": set(), "Swamp": {"Swamp Middle"}, From dd788bc3d9dfa4d371fafaa246fbe45bf0529eba Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 5 Mar 2024 22:03:28 -0500 Subject: [PATCH 27/82] Update option description --- worlds/tunic/options.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index c7a2e375fff5..1b621a0a916a 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -132,8 +132,9 @@ class LaurelsLocation(Choice): class ShuffleLadders(Toggle): - """Removes several of the ladders from the game, requiring you to find their items to get them back. - Greatly increases the number of spheres, making it great for asyncs.""" + """Turns several ladders in the game into items that must be found before they can be climbed on. + Adds more layers of progression to the game by blocking access to many areas early on. + "Ladders were a mistake." -Andrew Shouldice""" internal_name = "shuffle_ladders" display_name = "Shuffle Ladders" From 56d544e93ac37e5692a1740a73870661838e5c37 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Wed, 6 Mar 2024 15:32:48 -0500 Subject: [PATCH 28/82] Fix overworld -> atoll again --- worlds/tunic/ladder_rules.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 5a6e206c570d..51d8848d0c14 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -124,10 +124,9 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] or has_ability(state, player, prayer, options, ability_unlocks) or state.has(laurels, player)) multiworld.get_entrance("Overworld -> Ruined Atoll", player).access_rule = \ - lambda state: state.has_any({laurels, grapple}, player) \ - or has_ability(state, player, prayer, options, ability_unlocks) + lambda state: state.has(laurels, player) or has_ability(state, player, prayer, options, ability_unlocks) multiworld.get_entrance("Overworld Beach -> Ruined Atoll", player).access_rule = \ - lambda state: state.has("Ladder to Ruined Atoll", player) + lambda state: state.has_any({"Ladder to Ruined Atoll", grapple}, player) multiworld.get_entrance("Ruined Atoll -> Frog's Domain", player).access_rule = \ lambda state: state.has("Ladders to Frog's Domain", player) multiworld.get_entrance("Ruined Atoll -> Library", player).access_rule = \ From 13fc2c3d32624921577981679f1a44a65fe7dbe5 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Wed, 6 Mar 2024 19:08:45 -0500 Subject: [PATCH 29/82] Add missing HC rules --- worlds/tunic/ladder_rules.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 51d8848d0c14..fdfb037f50be 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -160,6 +160,16 @@ def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, in # Ability Shuffle Exclusive Rules set_rule(multiworld.get_location("Far Shore - Page Pickup", player), lambda state: has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Maze Cave - Maze Room Holy Cross", player), + lambda state: has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Southwest] Haiku Holy Cross", player), + lambda state: has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Northeast] Flowers Holy Cross", player), + lambda state: has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [Southwest] Flowers Holy Cross", player), + lambda state: has_ability(state, player, prayer, options, ability_unlocks)) + set_rule(multiworld.get_location("Overworld - [East] Weathervane Holy Cross", player), + lambda state: has_ability(state, player, prayer, options, ability_unlocks)) set_rule(multiworld.get_location("Fortress Courtyard - Chest Near Cave", player), lambda state: can_ladder_storage(state, player, options) or has_ability(state, player, prayer, options, ability_unlocks) @@ -265,7 +275,8 @@ def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, in set_rule(multiworld.get_location("Overworld - [East] Chest In Trees", player), lambda state: state.has_any({laurels, "Ladders near Weathervane"}, player)) set_rule(multiworld.get_location("Hourglass Cave - Holy Cross Chest", player), - lambda state: state.has("Hourglass Cave Ladders", player)) + lambda state: state.has("Hourglass Cave Ladders", player) + and has_ability(state, player, prayer, options, ability_unlocks)) set_rule(multiworld.get_location("Overworld - [Northwest] Chest Near Golden Obelisk", player), lambda state: state.has("Ladders near Dark Tomb", player) or (can_reach_upper_overworld(state, player, options, ability_unlocks) From e725d65c83c0eadaf713c9da9811b3f95f951b83 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Wed, 6 Mar 2024 19:34:03 -0500 Subject: [PATCH 30/82] Fix more broken rules --- worlds/tunic/items.py | 3 ++- worlds/tunic/ladder_rules.py | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 2b24e3649137..b42089ab96df 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -230,7 +230,8 @@ def get_item_group(item_name: str) -> str: "melee weapons": {"Stick", "Sword", "Sword Upgrade"}, "progressive sword": {"Sword Upgrade"}, "abilities": {"Pages 24-25 (Prayer)", "Pages 42-43 (Holy Cross)", "Pages 52-53 (Icebolt)"}, - "questagons": {"Red Questagon", "Green Questagon", "Blue Questagon", "Gold Questagon"} + "questagons": {"Red Questagon", "Green Questagon", "Blue Questagon", "Gold Questagon"}, + "ladder to atoll": {"Ladder to Ruined Atoll"}, # fuzzy matching made it hint ladder to well, now it won't } item_name_groups.update(extra_groups) diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index fdfb037f50be..991a4644931c 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -197,7 +197,8 @@ def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, in set_rule(multiworld.get_location("Quarry - [Back Entrance] Bushes Holy Cross", player), lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) set_rule(multiworld.get_location("Cathedral - Secret Legend Trophy Chest", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) + and state.has("Swamp Ladders", player)) set_rule(multiworld.get_location("Overworld - [Northwest] Golden Obelisk Page", player), lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) set_rule(multiworld.get_location("Overworld - [Northeast] Flowers Holy Cross", player), @@ -276,7 +277,7 @@ def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, in lambda state: state.has_any({laurels, "Ladders near Weathervane"}, player)) set_rule(multiworld.get_location("Hourglass Cave - Holy Cross Chest", player), lambda state: state.has("Hourglass Cave Ladders", player) - and has_ability(state, player, prayer, options, ability_unlocks)) + and has_ability(state, player, holy_cross, options, ability_unlocks)) set_rule(multiworld.get_location("Overworld - [Northwest] Chest Near Golden Obelisk", player), lambda state: state.has("Ladders near Dark Tomb", player) or (can_reach_upper_overworld(state, player, options, ability_unlocks) From b6c4380ff724534747010f254056f583dcd668b8 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Wed, 6 Mar 2024 19:57:08 -0500 Subject: [PATCH 31/82] More fixesssss --- worlds/tunic/locations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index 0b5763d4b179..7650123c70cb 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -14,7 +14,7 @@ def ladders_region(self) -> str: location_base_id = 509342400 location_table: Dict[str, TunicLocationData] = { - "Beneath the Well - [Powered Secret Room] Chest": TunicLocationData("Beneath the Well", "Beneath the Well Back"), + "Beneath the Well - [Powered Secret Room] Chest": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), "Beneath the Well - [Entryway] Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Third Room] Beneath Platform Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Third Room] Tentacle Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), From 5e4fbd75098a5c2c62729e866f2666d0e576f70f Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 7 Mar 2024 15:04:12 -0500 Subject: [PATCH 32/82] Reorganize temple access --- worlds/tunic/ladder_rules.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 991a4644931c..434688ffb0a7 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -54,16 +54,18 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] multiworld.get_entrance("Overworld -> Overworld Holy Cross", player).access_rule = \ lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) + # simplified: can hit a bell & can reach east bell & can reach/hit west bell or can break in via front or can break in via back multiworld.get_entrance("Overworld -> Sealed Temple", player).access_rule = \ - lambda state: ((state.has("Ladder Drop to East Forest", player) and - can_reach_east_overworld(state, player, options, ability_unlocks)) and - (state.has("Ladders to West Bell", player) and - ((state.has(laurels, player) and (has_sword(state, player) or state.has(fire_wand, player))) or - (state.has_all({lantern, "Dark Tomb Ladder"}, player) and has_sword(state, player)))) - or (can_reach_upper_overworld(state, player, options, ability_unlocks) - and state.has_all({laurels, "Ladder near Temple Rafters"}, player)) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks) - or can_ladder_storage(state, player, options) and state.has(laurels, player)) + lambda state: (((has_stick(state, player) or state.has(fire_wand, player)) + and ((can_reach_east_overworld(state, player, options, ability_unlocks) and state.has("Ladder Drop to East Forest")) + or (has_ability(state, player, prayer, options, ability_unlocks) and state.has(laurels, player))) + and ((state.has("Ladders to West Bell", player) + and (state.has(laurels, player) + or (state.has_all({lantern, "Dark Tomb Ladder"}, player) and has_sword(state, player)))) + or (state.has(fire_wand, player) and state.has_any({"Overworld Shortcut Ladders", grapple}, player) and options.logic_rules))) + or has_ice_grapple_logic(False, state, player, options, ability_unlocks) + or (can_reach_upper_overworld(state, player, options, ability_unlocks) and state.has_all({"Ladder near Temple Rafters", laurels}, player)) + or (can_ladder_storage(state, player, options) and state.has(laurels, player))) multiworld.get_entrance("Overworld -> East Overworld", player).access_rule = \ lambda state: can_reach_east_overworld(state, player, options, ability_unlocks) multiworld.get_entrance("Overworld -> Upper Overworld", player).access_rule = \ @@ -99,9 +101,9 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] multiworld.get_entrance("Dark Tomb Front -> Dark Tomb", player).access_rule = \ lambda state: state.has("Dark Tomb Ladder", player) # dark tomb to west garden has no rule intentionally + # Overworld -> West Garden access via furnace multiworld.get_entrance("Overworld -> West Garden", player).access_rule = \ - lambda state: (state.has(laurels, player) and state.has("Ladders to West Bell", player)) \ - or can_ladder_storage(state, player, options) + lambda state: state.has(laurels, player) or can_ladder_storage(state, player, options) multiworld.get_entrance("Overworld -> Beneath the Well", player).access_rule = \ lambda state: state.has("Ladder to Well", player) and (has_stick(state, player) or state.has(fire_wand, player)) multiworld.get_entrance("Beneath the Well -> Beneath the Well Back", player).access_rule = \ @@ -125,6 +127,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] or state.has(laurels, player)) multiworld.get_entrance("Overworld -> Ruined Atoll", player).access_rule = \ lambda state: state.has(laurels, player) or has_ability(state, player, prayer, options, ability_unlocks) + # either use the ladder, or enter through the lower and use orb multiworld.get_entrance("Overworld Beach -> Ruined Atoll", player).access_rule = \ lambda state: state.has_any({"Ladder to Ruined Atoll", grapple}, player) multiworld.get_entrance("Ruined Atoll -> Frog's Domain", player).access_rule = \ From e8a734548cc681bfb78b3455704bcb0c0501ba82 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 7 Mar 2024 15:14:14 -0500 Subject: [PATCH 33/82] Couple more fixes, add a todo --- worlds/tunic/ladder_rules.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index 434688ffb0a7..e32eba811cb0 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -70,6 +70,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] lambda state: can_reach_east_overworld(state, player, options, ability_unlocks) multiworld.get_entrance("Overworld -> Upper Overworld", player).access_rule = \ lambda state: can_reach_upper_overworld(state, player, options, ability_unlocks) + # use the ladder down, use laurels, or multiworld.get_entrance("Overworld -> Overworld Beach", player).access_rule = \ lambda state: state.has_any({"Overworld Town Ladders", laurels}, player) multiworld.get_entrance("Overworld Beach -> West Garden", player).access_rule = \ @@ -94,7 +95,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] or (can_ladder_storage(state, player, options) and state.has(fire_wand, player))) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) multiworld.get_entrance("Overworld -> Back of Swamp", player).access_rule = \ - lambda state: state.has(laurels, player) or can_ladder_storage(state, player, options) + lambda state: state.has(laurels, player) # before the ladder, just the one chest in the room where you open up the grave to the ladder multiworld.get_entrance("Overworld -> Dark Tomb Front", player).access_rule = \ lambda state: has_lantern(state, player, options) @@ -125,6 +126,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] and (can_ladder_storage(state, player, options) or has_ability(state, player, prayer, options, ability_unlocks) or state.has(laurels, player)) + # todo: LS to atoll upper, maybe also do atoll lower + orb from swamp multiworld.get_entrance("Overworld -> Ruined Atoll", player).access_rule = \ lambda state: state.has(laurels, player) or has_ability(state, player, prayer, options, ability_unlocks) # either use the ladder, or enter through the lower and use orb From 0d3cfca802d93cb2685e866c0f7e9cd04161e2b8 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 7 Mar 2024 15:25:40 -0500 Subject: [PATCH 34/82] LS from atoll upper entry if you have the ladder --- worlds/tunic/er_rules.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 26da87308be8..fb2e2d775ed2 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -929,6 +929,8 @@ def get_portal_info(portal_sd: str) -> (str, str): # The upper Swamp entrance ("Overworld", "Overworld Redux, Swamp Redux 2_wall", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), + ("Overworld", "Overworld Redux, Atoll Redux_upper", + {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), # Furnace entrance, next to the sign that leads to West Garden ("Overworld", "Overworld Redux, Furnace_gyro_west", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), @@ -991,6 +993,28 @@ def get_portal_info(portal_sd: str) -> (str, str): # Rotating Lights entrance ("Overworld Beach", "Overworld Redux, Overworld Cave_", {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), + # todo: verify the ones below from the atoll ladder, see if there's any missing + # Swamp upper entrance + ("Overworld Beach", "Overworld Redux, Swamp Redux 2_wall", + {"Ladder to Ruined Atoll"}), + # Furnace entrance, next to the sign that leads to West Garden + ("Overworld Beach", "Overworld Redux, Furnace_gyro_west", + {"Ladder to Ruined Atoll"}), + # Upper West Garden entry, by the belltower + ("Overworld Beach", "Overworld Redux, Archipelagos Redux_upper", + {"Ladder to Ruined Atoll"}), + # Ruined Passage + ("Overworld Beach", "Overworld Redux, Ruins Passage_east", + {"Ladder to Ruined Atoll"}), + # Well rail, west side. Can ls in town, get extra height by going over the portal pad + ("Overworld Beach", "Overworld Redux, Sewer_west_aqueduct", + {"Ladder to Ruined Atoll"}), + # Well rail, east side. Need some height from the temple stairs + ("Overworld Beach", "Overworld Redux, Furnace_gyro_upper_north", + {"Ladder to Ruined Atoll"}), + # Quarry entry + ("Overworld Beach", "Overworld Redux, Darkwoods Tunnel_", + {"Ladder to Ruined Atoll"}), # West Garden main entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Archipelagos Redux_lower", From bed7d8761e09eaae3e80f1d6fa776098e40d929e Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 7 Mar 2024 15:27:14 -0500 Subject: [PATCH 35/82] Add note --- worlds/tunic/ladder_rules.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py index e32eba811cb0..f30e1a652ffa 100644 --- a/worlds/tunic/ladder_rules.py +++ b/worlds/tunic/ladder_rules.py @@ -126,7 +126,7 @@ def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int] and (can_ladder_storage(state, player, options) or has_ability(state, player, prayer, options, ability_unlocks) or state.has(laurels, player)) - # todo: LS to atoll upper, maybe also do atoll lower + orb from swamp + # todo: LS to atoll upper, maybe also do atoll lower + orb from swamp, and vice versa? multiworld.get_entrance("Overworld -> Ruined Atoll", player).access_rule = \ lambda state: state.has(laurels, player) or has_ability(state, player, prayer, options, ability_unlocks) # either use the ladder, or enter through the lower and use orb From 56e43b26653a317e0bc6431b09a94f15b73c1d51 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 7 Mar 2024 17:10:06 -0500 Subject: [PATCH 36/82] Add note to er scripts for later --- worlds/tunic/er_scripts.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 8bd8bea2697a..0bbe7cd1bd93 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -86,6 +86,9 @@ def place_event_items(world: "TunicWorld", regions: Dict[str, Region]) -> None: def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: # separate the portals into dead ends and non-dead ends portal_pairs: Dict[Portal, Portal] = {} + + # todo: if not er, return vanilla connections + dead_ends: List[Portal] = [] two_plus: List[Portal] = [] plando_connections: List[PlandoConnection] = [] From 65960920cdaee991b6a401f5b4a59e9a4cf5ec7d Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 7 Mar 2024 21:05:38 -0500 Subject: [PATCH 37/82] Big refactor, ladder rando just uses the ER now with vanilla connections --- worlds/tunic/__init__.py | 25 +- worlds/tunic/er_data.py | 438 ++++++++++++++++++----------------- worlds/tunic/er_rules.py | 3 +- worlds/tunic/er_scripts.py | 57 ++++- worlds/tunic/ladder_rules.py | 411 -------------------------------- worlds/tunic/locations.py | 122 +++++----- worlds/tunic/regions.py | 34 --- 7 files changed, 337 insertions(+), 753 deletions(-) delete mode 100644 worlds/tunic/ladder_rules.py diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index c2370baa80ef..856d70242596 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -5,8 +5,7 @@ from .locations import location_table, location_name_groups, location_name_to_id, hexagon_locations from .rules import set_location_rules, set_region_rules, randomize_ability_unlocks, gold_hexagon from .er_rules import set_er_location_rules -from .ladder_rules import set_ladder_region_rules, set_ladder_location_rules -from .regions import tunic_regions, tunic_ladder_regions +from .regions import tunic_regions from .er_scripts import create_er_regions from .er_data import portal_mapping from .options import TunicOptions @@ -193,16 +192,14 @@ def create_regions(self) -> None: self.ability_unlocks["Pages 42-43 (Holy Cross)"] = passthrough["Hexagon Quest Holy Cross"] self.ability_unlocks["Pages 52-53 (Icebolt)"] = passthrough["Hexagon Quest Icebolt"] - if self.options.entrance_rando: + if self.options.entrance_rando or self.options.shuffle_ladders: portal_pairs = create_er_regions(self) - for portal1, portal2 in portal_pairs.items(): - self.tunic_portal_pairs[portal1.scene_destination()] = portal2.scene_destination() + if self.options.entrance_rando: + for portal1, portal2 in portal_pairs.items(): + self.tunic_portal_pairs[portal1.scene_destination()] = portal2.scene_destination() else: - if self.options.shuffle_ladders: - region_list = tunic_ladder_regions - else: - region_list = tunic_regions + region_list = tunic_regions for region_name in region_list: region = Region(region_name, self.player, self.multiworld) @@ -213,10 +210,7 @@ def create_regions(self) -> None: region.add_exits(exits) for location_name, location_id in self.location_name_to_id.items(): - if self.options.shuffle_ladders: - region = self.multiworld.get_region(location_table[location_name].ladders_region(), self.player) - else: - region = self.multiworld.get_region(location_table[location_name].region, self.player) + region = self.multiworld.get_region(location_table[location_name].region, self.player) location = TunicLocation(self.player, location_name, location_id, region) region.locations.append(location) @@ -227,11 +221,8 @@ def create_regions(self) -> None: victory_region.locations.append(victory_location) def set_rules(self) -> None: - if self.options.entrance_rando: + if self.options.entrance_rando or self.options.shuffle_ladders: set_er_location_rules(self, self.ability_unlocks) - elif self.options.shuffle_ladders: - set_ladder_region_rules(self, self.ability_unlocks) - set_ladder_location_rules(self, self.ability_unlocks) else: set_region_rules(self, self.ability_unlocks) set_location_rules(self, self.ability_unlocks) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 5a0215fd363c..de620e08b9aa 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -5,505 +5,509 @@ class Portal(NamedTuple): name: str # human-readable name region: str # AP region - destination: str # vanilla destination scene and tag + destination: str # vanilla destination scene + tag: str # vanilla tag def scene(self) -> str: # the actual scene name in Tunic return tunic_er_regions[self.region].game_scene def scene_destination(self) -> str: # full, nonchanging name to interpret by the mod - return self.scene() + ", " + self.destination + return self.scene() + ", " + self.destination + self.tag + + def destination_scene(self) -> str: # the vanilla connection + return self.destination + ", " + self.scene() + self.tag portal_mapping: List[Portal] = [ Portal(name="Stick House Entrance", region="Overworld", - destination="Sword Cave_"), + destination="Sword Cave", tag="_"), Portal(name="Windmill Entrance", region="Overworld", - destination="Windmill_"), + destination="Windmill", tag="_"), Portal(name="Well Ladder Entrance", region="Overworld Well Ladder", - destination="Sewer_entrance"), + destination="Sewer", tag="_entrance"), Portal(name="Entrance to Well from Well Rail", region="Overworld Well to Furnace Rail", - destination="Sewer_west_aqueduct"), + destination="Sewer", tag="_west_aqueduct"), Portal(name="Old House Door Entrance", region="Overworld Old House Door", - destination="Overworld Interiors_house"), + destination="Overworld Interiors", tag="_house"), Portal(name="Old House Waterfall Entrance", region="Overworld", - destination="Overworld Interiors_under_checkpoint"), + destination="Overworld Interiors", tag="_under_checkpoint"), Portal(name="Entrance to Furnace from Well Rail", region="Overworld Well to Furnace Rail", - destination="Furnace_gyro_upper_north"), + destination="Furnace", tag="_gyro_upper_north"), Portal(name="Entrance to Furnace under Windmill", region="Overworld", - destination="Furnace_gyro_upper_east"), + destination="Furnace", tag="_gyro_upper_east"), Portal(name="Entrance to Furnace near West Garden", region="Overworld to West Garden from Furnace", - destination="Furnace_gyro_west"), + destination="Furnace", tag="_gyro_west"), Portal(name="Entrance to Furnace from Beach", region="Overworld", - destination="Furnace_gyro_lower"), + destination="Furnace", tag="_gyro_lower"), Portal(name="Caustic Light Cave Entrance", region="Overworld Swamp Lower Entry", - destination="Overworld Cave_"), + destination="Overworld Cave", tag="_"), Portal(name="Swamp Upper Entrance", region="Overworld Swamp Upper Entry", - destination="Swamp Redux 2_wall"), + destination="Swamp Redux 2", tag="_wall"), Portal(name="Swamp Lower Entrance", region="Overworld Swamp Lower Entry", - destination="Swamp Redux 2_conduit"), + destination="Swamp Redux 2", tag="_conduit"), Portal(name="Ruined Passage Not-Door Entrance", region="After Ruined Passage", - destination="Ruins Passage_east"), + destination="Ruins Passage", tag="_east"), Portal(name="Ruined Passage Door Entrance", region="Overworld Ruined Passage Door", - destination="Ruins Passage_west"), + destination="Ruins Passage", tag="_west"), Portal(name="Atoll Upper Entrance", region="Overworld to Atoll Upper", - destination="Atoll Redux_upper"), + destination="Atoll Redux", tag="_upper"), Portal(name="Atoll Lower Entrance", region="Overworld Beach", - destination="Atoll Redux_lower"), + destination="Atoll Redux", tag="_lower"), Portal(name="Special Shop Entrance", region="Overworld Special Shop Entry", - destination="ShopSpecial_"), + destination="ShopSpecial", tag="_"), Portal(name="Maze Cave Entrance", region="Overworld Beach", - destination="Maze Room_"), + destination="Maze Room", tag="_"), Portal(name="West Garden Entrance near Belltower", region="Overworld to West Garden Upper", - destination="Archipelagos Redux_upper"), + destination="Archipelagos Redux", tag="_upper"), Portal(name="West Garden Entrance from Furnace", region="Overworld to West Garden from Furnace", - destination="Archipelagos Redux_lower"), + destination="Archipelagos Redux", tag="_lower"), Portal(name="West Garden Laurels Entrance", region="Overworld West Garden Laurels Entry", - destination="Archipelagos Redux_lowest"), + destination="Archipelagos Redux", tag="_lowest"), Portal(name="Temple Door Entrance", region="Overworld Temple Door", - destination="Temple_main"), + destination="Temple", tag="_main"), Portal(name="Temple Rafters Entrance", region="Upper Overworld", - destination="Temple_rafters"), + destination="Temple", tag="_rafters"), Portal(name="Ruined Shop Entrance", region="Overworld", - destination="Ruined Shop_"), + destination="Ruined Shop", tag="_"), Portal(name="Patrol Cave Entrance", region="Overworld at Patrol Cave", - destination="PatrolCave_"), + destination="PatrolCave", tag="_"), Portal(name="Hourglass Cave Entrance", region="Overworld Beach", - destination="Town Basement_beach"), + destination="Town Basement", tag="_beach"), Portal(name="Changing Room Entrance", region="Overworld", - destination="Changing Room_"), + destination="Changing Room", tag="_"), Portal(name="Cube Cave Entrance", region="Overworld", - destination="CubeRoom_"), + destination="CubeRoom", tag="_"), Portal(name="Stairs from Overworld to Mountain", region="Upper Overworld", - destination="Mountain_"), + destination="Mountain", tag="_"), Portal(name="Overworld to Fortress", region="East Overworld", - destination="Fortress Courtyard_"), + destination="Fortress Courtyard", tag="_"), Portal(name="Fountain HC Door Entrance", region="Overworld Fountain Cross Door", - destination="Town_FiligreeRoom_"), + destination="Town_FiligreeRoom", tag="_"), Portal(name="Southeast HC Door Entrance", region="Overworld Southeast Cross Door", - destination="EastFiligreeCache_"), + destination="EastFiligreeCache", tag="_"), Portal(name="Overworld to Quarry Connector", region="Overworld Quarry Entry", - destination="Darkwoods Tunnel_"), + destination="Darkwoods Tunnel", tag="_"), Portal(name="Dark Tomb Main Entrance", region="Overworld", - destination="Crypt Redux_"), + destination="Crypt Redux", tag="_"), Portal(name="Overworld to Forest Belltower", region="East Overworld", - destination="Forest Belltower_"), + destination="Forest Belltower", tag="_"), Portal(name="Town to Far Shore", region="Overworld Town Portal", - destination="Transit_teleporter_town"), + destination="Transit", tag="_teleporter_town"), Portal(name="Spawn to Far Shore", region="Overworld Spawn Portal", - destination="Transit_teleporter_starting island"), + destination="Transit", tag="_teleporter_starting island"), Portal(name="Secret Gathering Place Entrance", region="Overworld", - destination="Waterfall_"), + destination="Waterfall", tag="_"), Portal(name="Secret Gathering Place Exit", region="Secret Gathering Place", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Windmill Exit", region="Windmill", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Windmill Shop", region="Windmill", - destination="Shop_"), + destination="Shop", tag="_"), Portal(name="Old House Door Exit", region="Old House Front", - destination="Overworld Redux_house"), + destination="Overworld Redux", tag="_house"), Portal(name="Old House to Glyph Tower", region="Old House Front", - destination="g_elements_"), + destination="g_elements", tag="_"), Portal(name="Old House Waterfall Exit", region="Old House Back", - destination="Overworld Redux_under_checkpoint"), + destination="Overworld Redux", tag="_under_checkpoint"), Portal(name="Glyph Tower Exit", region="Relic Tower", - destination="Overworld Interiors_"), + destination="Overworld Interiors", tag="_"), Portal(name="Changing Room Exit", region="Changing Room", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Fountain HC Room Exit", region="Fountain Cross Room", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Cube Cave Exit", region="Cube Cave", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Guard Patrol Cave Exit", region="Patrol Cave", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Ruined Shop Exit", region="Ruined Shop", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Furnace Exit towards Well", region="Furnace Fuse", - destination="Overworld Redux_gyro_upper_north"), + destination="Overworld Redux", tag="_gyro_upper_north"), Portal(name="Furnace Exit to Dark Tomb", region="Furnace Walking Path", - destination="Crypt Redux_"), + destination="Crypt Redux", tag="_"), Portal(name="Furnace Exit towards West Garden", region="Furnace Walking Path", - destination="Overworld Redux_gyro_west"), + destination="Overworld Redux", tag="_gyro_west"), Portal(name="Furnace Exit to Beach", region="Furnace Ladder Area", - destination="Overworld Redux_gyro_lower"), + destination="Overworld Redux", tag="_gyro_lower"), Portal(name="Furnace Exit under Windmill", region="Furnace Ladder Area", - destination="Overworld Redux_gyro_upper_east"), + destination="Overworld Redux", tag="_gyro_upper_east"), Portal(name="Stick House Exit", region="Stick House", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Ruined Passage Not-Door Exit", region="Ruined Passage", - destination="Overworld Redux_east"), + destination="Overworld Redux", tag="_east"), Portal(name="Ruined Passage Door Exit", region="Ruined Passage", - destination="Overworld Redux_west"), + destination="Overworld Redux", tag="_west"), Portal(name="Southeast HC Room Exit", region="Southeast Cross Room", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Caustic Light Cave Exit", region="Caustic Light Cave", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Maze Cave Exit", region="Maze Cave", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Hourglass Cave Exit", region="Hourglass Cave", - destination="Overworld Redux_beach"), + destination="Overworld Redux", tag="_beach"), Portal(name="Special Shop Exit", region="Special Shop", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Temple Rafters Exit", region="Sealed Temple Rafters", - destination="Overworld Redux_rafters"), + destination="Overworld Redux", tag="_rafters"), Portal(name="Temple Door Exit", region="Sealed Temple", - destination="Overworld Redux_main"), + destination="Overworld Redux", tag="_main"), Portal(name="Well Ladder Exit", region="Beneath the Well Ladder Exit", - destination="Overworld Redux_entrance"), + destination="Overworld Redux", tag="_entrance"), Portal(name="Well to Well Boss", region="Beneath the Well Back", - destination="Sewer_Boss_"), + destination="Sewer_Boss", tag="_"), Portal(name="Well Exit towards Furnace", region="Beneath the Well Back", - destination="Overworld Redux_west_aqueduct"), + destination="Overworld Redux", tag="_west_aqueduct"), Portal(name="Well Boss to Well", region="Well Boss", - destination="Sewer_"), + destination="Sewer", tag="_"), Portal(name="Checkpoint to Dark Tomb", region="Dark Tomb Checkpoint", - destination="Crypt Redux_"), + destination="Crypt Redux", tag="_"), Portal(name="Dark Tomb to Overworld", region="Dark Tomb Entry Point", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Dark Tomb to Furnace", region="Dark Tomb Dark Exit", - destination="Furnace_"), + destination="Furnace", tag="_"), Portal(name="Dark Tomb to Checkpoint", region="Dark Tomb Entry Point", - destination="Sewer_Boss_"), + destination="Sewer_Boss", tag="_"), Portal(name="West Garden Exit near Hero's Grave", region="West Garden", - destination="Overworld Redux_lower"), + destination="Overworld Redux", tag="_lower"), Portal(name="West Garden to Magic Dagger House", region="West Garden", - destination="archipelagos_house_"), + destination="archipelagos_house", tag="_"), Portal(name="West Garden Exit after Boss", region="West Garden after Boss", - destination="Overworld Redux_upper"), + destination="Overworld Redux", tag="_upper"), Portal(name="West Garden Shop", region="West Garden", - destination="Shop_"), + destination="Shop", tag="_"), Portal(name="West Garden Laurels Exit", region="West Garden Laurels Exit Region", - destination="Overworld Redux_lowest"), + destination="Overworld Redux", tag="_lowest"), Portal(name="West Garden Hero's Grave", region="West Garden Hero's Grave Region", - destination="RelicVoid_teleporter_relic plinth"), + destination="RelicVoid", tag="_teleporter_relic plinth"), Portal(name="West Garden to Far Shore", region="West Garden Portal", - destination="Transit_teleporter_archipelagos_teleporter"), + destination="Transit", tag="_teleporter_archipelagos_teleporter"), Portal(name="Magic Dagger House Exit", region="Magic Dagger House", - destination="Archipelagos Redux_"), + destination="Archipelagos Redux", tag="_"), Portal(name="Atoll Upper Exit", region="Ruined Atoll", - destination="Overworld Redux_upper"), + destination="Overworld Redux", tag="_upper"), Portal(name="Atoll Lower Exit", region="Ruined Atoll Lower Entry Area", - destination="Overworld Redux_lower"), + destination="Overworld Redux", tag="_lower"), Portal(name="Atoll Shop", region="Ruined Atoll", - destination="Shop_"), + destination="Shop", tag="_"), Portal(name="Atoll to Far Shore", region="Ruined Atoll Portal", - destination="Transit_teleporter_atoll"), + destination="Transit", tag="_teleporter_atoll"), Portal(name="Atoll Statue Teleporter", region="Ruined Atoll Statue", - destination="Library Exterior_"), + destination="Library Exterior", tag="_"), Portal(name="Frog Stairs Eye Entrance", region="Ruined Atoll Frog Eye", - destination="Frog Stairs_eye"), + destination="Frog Stairs", tag="_eye"), Portal(name="Frog Stairs Mouth Entrance", region="Ruined Atoll Frog Mouth", - destination="Frog Stairs_mouth"), + destination="Frog Stairs", tag="_mouth"), Portal(name="Frog Stairs Eye Exit", region="Frog Stairs Eye Exit", - destination="Atoll Redux_eye"), + destination="Atoll Redux", tag="_eye"), Portal(name="Frog Stairs Mouth Exit", region="Frog Stairs Upper", - destination="Atoll Redux_mouth"), + destination="Atoll Redux", tag="_mouth"), Portal(name="Frog Stairs to Frog's Domain's Entrance", region="Frog Stairs to Frog's Domain", - destination="frog cave main_Entrance"), + destination="frog cave main", tag="_Entrance"), Portal(name="Frog Stairs to Frog's Domain's Exit", region="Frog Stairs Lower", - destination="frog cave main_Exit"), + destination="frog cave main", tag="_Exit"), Portal(name="Frog's Domain Ladder Exit", region="Frog's Domain", - destination="Frog Stairs_Entrance"), + destination="Frog Stairs", tag="_Entrance"), Portal(name="Frog's Domain Orb Exit", region="Frog's Domain Back", - destination="Frog Stairs_Exit"), + destination="Frog Stairs", tag="_Exit"), Portal(name="Library Exterior Tree", region="Library Exterior Tree Region", - destination="Atoll Redux_"), + destination="Atoll Redux", tag="_"), Portal(name="Library Exterior Ladder", region="Library Exterior Ladder Region", - destination="Library Hall_"), + destination="Library Hall", tag="_"), Portal(name="Library Hall Bookshelf Exit", region="Library Hall", - destination="Library Exterior_"), + destination="Library Exterior", tag="_"), Portal(name="Library Hero's Grave", region="Library Hero's Grave Region", - destination="RelicVoid_teleporter_relic plinth"), + destination="RelicVoid", tag="_teleporter_relic plinth"), Portal(name="Library Hall to Rotunda", region="Library Hall", - destination="Library Rotunda_"), + destination="Library Rotunda", tag="_"), Portal(name="Library Rotunda Lower Exit", region="Library Rotunda", - destination="Library Hall_"), + destination="Library Hall", tag="_"), Portal(name="Library Rotunda Upper Exit", region="Library Rotunda", - destination="Library Lab_"), + destination="Library Lab", tag="_"), Portal(name="Library Lab to Rotunda", region="Library Lab Lower", - destination="Library Rotunda_"), + destination="Library Rotunda", tag="_"), Portal(name="Library to Far Shore", region="Library Portal", - destination="Transit_teleporter_library teleporter"), + destination="Transit", tag="_teleporter_library teleporter"), Portal(name="Library Lab to Librarian Arena", region="Library Lab", - destination="Library Arena_"), + destination="Library Arena", tag="_"), Portal(name="Librarian Arena Exit", region="Library Arena", - destination="Library Lab_"), + destination="Library Lab", tag="_"), Portal(name="Forest to Belltower", region="East Forest", - destination="Forest Belltower_"), + destination="Forest Belltower", tag="_"), Portal(name="Forest Guard House 1 Lower Entrance", region="East Forest", - destination="East Forest Redux Laddercave_lower"), + destination="East Forest Redux Laddercave", tag="_lower"), Portal(name="Forest Guard House 1 Gate Entrance", region="East Forest", - destination="East Forest Redux Laddercave_gate"), + destination="East Forest Redux Laddercave", tag="_gate"), Portal(name="Forest Dance Fox Outside Doorway", region="East Forest Dance Fox Spot", - destination="East Forest Redux Laddercave_upper"), + destination="East Forest Redux Laddercave", tag="_upper"), Portal(name="Forest to Far Shore", region="East Forest Portal", - destination="Transit_teleporter_forest teleporter"), + destination="Transit", tag="_teleporter_forest teleporter"), Portal(name="Forest Guard House 2 Lower Entrance", region="Lower Forest", - destination="East Forest Redux Interior_lower"), + destination="East Forest Redux Interior", tag="_lower"), Portal(name="Forest Guard House 2 Upper Entrance", region="East Forest", - destination="East Forest Redux Interior_upper"), + destination="East Forest Redux Interior", tag="_upper"), Portal(name="Forest Grave Path Lower Entrance", region="East Forest", - destination="Sword Access_lower"), + destination="Sword Access", tag="_lower"), Portal(name="Forest Grave Path Upper Entrance", region="East Forest", - destination="Sword Access_upper"), + destination="Sword Access", tag="_upper"), Portal(name="Guard House 1 Dance Fox Exit", region="Guard House 1 West", - destination="East Forest Redux_upper"), + destination="East Forest Redux", tag="_upper"), Portal(name="Guard House 1 Lower Exit", region="Guard House 1 West", - destination="East Forest Redux_lower"), + destination="East Forest Redux", tag="_lower"), Portal(name="Guard House 1 Upper Forest Exit", region="Guard House 1 East", - destination="East Forest Redux_gate"), + destination="East Forest Redux", tag="_gate"), Portal(name="Guard House 1 to Guard Captain Room", region="Guard House 1 East", - destination="Forest Boss Room_"), + destination="Forest Boss Room", tag="_"), Portal(name="Forest Grave Path Upper Exit", region="Forest Grave Path Upper", - destination="East Forest Redux_upper"), + destination="East Forest Redux", tag="_upper"), Portal(name="Forest Grave Path Lower Exit", region="Forest Grave Path Main", - destination="East Forest Redux_lower"), + destination="East Forest Redux", tag="_lower"), Portal(name="East Forest Hero's Grave", region="Forest Hero's Grave", - destination="RelicVoid_teleporter_relic plinth"), + destination="RelicVoid", tag="_teleporter_relic plinth"), Portal(name="Guard House 2 Lower Exit", region="Guard House 2 Lower", - destination="East Forest Redux_lower"), + destination="East Forest Redux", tag="_lower"), Portal(name="Guard House 2 Upper Exit", region="Guard House 2 Upper", - destination="East Forest Redux_upper"), + destination="East Forest Redux", tag="_upper"), Portal(name="Guard Captain Room Non-Gate Exit", region="Forest Boss Room", - destination="East Forest Redux Laddercave_"), + destination="East Forest Redux Laddercave", tag="_"), Portal(name="Guard Captain Room Gate Exit", region="Forest Boss Room", - destination="Forest Belltower_"), + destination="Forest Belltower", tag="_"), Portal(name="Forest Belltower to Fortress", region="Forest Belltower Main", - destination="Fortress Courtyard_"), + destination="Fortress Courtyard", tag="_"), Portal(name="Forest Belltower to Forest", region="Forest Belltower Lower", - destination="East Forest Redux_"), + destination="East Forest Redux", tag="_"), Portal(name="Forest Belltower to Overworld", region="Forest Belltower Main", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Forest Belltower to Guard Captain Room", region="Forest Belltower Upper", - destination="Forest Boss Room_"), + destination="Forest Boss Room", tag="_"), Portal(name="Fortress Courtyard to Fortress Grave Path Lower", region="Fortress Courtyard", - destination="Fortress Reliquary_Lower"), + destination="Fortress Reliquary", tag="_Lower"), Portal(name="Fortress Courtyard to Fortress Grave Path Upper", region="Fortress Courtyard Upper", - destination="Fortress Reliquary_Upper"), + destination="Fortress Reliquary", tag="_Upper"), Portal(name="Fortress Courtyard to Fortress Interior", region="Fortress Courtyard", - destination="Fortress Main_Big Door"), + destination="Fortress Main", tag="_Big Door"), Portal(name="Fortress Courtyard to East Fortress", region="Fortress Courtyard Upper", - destination="Fortress East_"), + destination="Fortress East", tag="_"), Portal(name="Fortress Courtyard to Beneath the Vault", region="Beneath the Vault Entry", - destination="Fortress Basement_"), + destination="Fortress Basement", tag="_"), Portal(name="Fortress Courtyard to Forest Belltower", region="Fortress Exterior from East Forest", - destination="Forest Belltower_"), + destination="Forest Belltower", tag="_"), Portal(name="Fortress Courtyard to Overworld", region="Fortress Exterior from Overworld", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Fortress Courtyard Shop", region="Fortress Exterior near cave", - destination="Shop_"), + destination="Shop", tag="_"), Portal(name="Beneath the Vault to Fortress Interior", region="Beneath the Vault Back", - destination="Fortress Main_"), + destination="Fortress Main", tag="_"), Portal(name="Beneath the Vault to Fortress Courtyard", region="Beneath the Vault Ladder Exit", - destination="Fortress Courtyard_"), + destination="Fortress Courtyard", tag="_"), Portal(name="Fortress Interior Main Exit", region="Eastern Vault Fortress", - destination="Fortress Courtyard_Big Door"), + destination="Fortress Courtyard", tag="_Big Door"), Portal(name="Fortress Interior to Beneath the Earth", region="Eastern Vault Fortress", - destination="Fortress Basement_"), + destination="Fortress Basement", tag="_"), Portal(name="Fortress Interior to Siege Engine Arena", region="Eastern Vault Fortress Gold Door", - destination="Fortress Arena_"), + destination="Fortress Arena", tag="_"), Portal(name="Fortress Interior Shop", region="Eastern Vault Fortress", - destination="Shop_"), + destination="Shop", tag="_"), Portal(name="Fortress Interior to East Fortress Upper", region="Eastern Vault Fortress", - destination="Fortress East_upper"), + destination="Fortress East", tag="_upper"), Portal(name="Fortress Interior to East Fortress Lower", region="Eastern Vault Fortress", - destination="Fortress East_lower"), + destination="Fortress East", tag="_lower"), Portal(name="East Fortress to Interior Lower", region="Fortress East Shortcut Lower", - destination="Fortress Main_lower"), + destination="Fortress Main", tag="_lower"), Portal(name="East Fortress to Courtyard", region="Fortress East Shortcut Upper", - destination="Fortress Courtyard_"), + destination="Fortress Courtyard", tag="_"), Portal(name="East Fortress to Interior Upper", region="Fortress East Shortcut Upper", - destination="Fortress Main_upper"), + destination="Fortress Main", tag="_upper"), Portal(name="Fortress Grave Path Lower Exit", region="Fortress Grave Path", - destination="Fortress Courtyard_Lower"), + destination="Fortress Courtyard", tag="_Lower"), Portal(name="Fortress Hero's Grave", region="Fortress Hero's Grave Region", - destination="RelicVoid_teleporter_relic plinth"), + destination="RelicVoid", tag="_teleporter_relic plinth"), Portal(name="Fortress Grave Path Upper Exit", region="Fortress Grave Path Upper", - destination="Fortress Courtyard_Upper"), + destination="Fortress Courtyard", tag="_Upper"), Portal(name="Fortress Grave Path Dusty Entrance", region="Fortress Grave Path Dusty Entrance Region", - destination="Dusty_"), + destination="Dusty", tag="_"), Portal(name="Dusty Exit", region="Fortress Leaf Piles", - destination="Fortress Reliquary_"), + destination="Fortress Reliquary", tag="_"), Portal(name="Siege Engine Arena to Fortress", region="Fortress Arena", - destination="Fortress Main_"), + destination="Fortress Main", tag="_"), Portal(name="Fortress to Far Shore", region="Fortress Arena Portal", - destination="Transit_teleporter_spidertank"), + destination="Transit", tag="_teleporter_spidertank"), Portal(name="Stairs to Top of the Mountain", region="Lower Mountain Stairs", - destination="Mountaintop_"), + destination="Mountaintop", tag="_"), Portal(name="Mountain to Quarry", region="Lower Mountain", - destination="Quarry Redux_"), + destination="Quarry Redux", tag="_"), Portal(name="Mountain to Overworld", region="Lower Mountain", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Top of the Mountain Exit", region="Top of the Mountain", - destination="Mountain_"), + destination="Mountain", tag="_"), Portal(name="Quarry Connector to Overworld", region="Quarry Connector", - destination="Overworld Redux_"), + destination="Overworld Redux", tag="_"), Portal(name="Quarry Connector to Quarry", region="Quarry Connector", - destination="Quarry Redux_"), + destination="Quarry Redux", tag="_"), Portal(name="Quarry to Overworld Exit", region="Quarry Entry", - destination="Darkwoods Tunnel_"), + destination="Darkwoods Tunnel", tag="_"), Portal(name="Quarry Shop", region="Quarry Entry", - destination="Shop_"), + destination="Shop", tag="_"), Portal(name="Quarry to Monastery Front", region="Quarry Monastery Entry", - destination="Monastery_front"), + destination="Monastery", tag="_front"), Portal(name="Quarry to Monastery Back", region="Monastery Rope", - destination="Monastery_back"), + destination="Monastery", tag="_back"), Portal(name="Quarry to Mountain", region="Quarry Back", - destination="Mountain_"), + destination="Mountain", tag="_"), Portal(name="Quarry to Ziggurat", region="Lower Quarry Zig Door", - destination="ziggurat2020_0_"), + destination="ziggurat2020_0", tag="_"), Portal(name="Quarry to Far Shore", region="Quarry Portal", - destination="Transit_teleporter_quarry teleporter"), + destination="Transit", tag="_teleporter_quarry teleporter"), Portal(name="Monastery Rear Exit", region="Monastery Back", - destination="Quarry Redux_back"), + destination="Quarry Redux", tag="_back"), Portal(name="Monastery Front Exit", region="Monastery Front", - destination="Quarry Redux_front"), + destination="Quarry Redux", tag="_front"), Portal(name="Monastery Hero's Grave", region="Monastery Hero's Grave Region", - destination="RelicVoid_teleporter_relic plinth"), + destination="RelicVoid", tag="_teleporter_relic plinth"), Portal(name="Ziggurat Entry Hallway to Ziggurat Upper", region="Rooted Ziggurat Entry", - destination="ziggurat2020_1_"), + destination="ziggurat2020_1", tag="_"), Portal(name="Ziggurat Entry Hallway to Quarry", region="Rooted Ziggurat Entry", - destination="Quarry Redux_"), + destination="Quarry Redux", tag="_"), Portal(name="Ziggurat Upper to Ziggurat Entry Hallway", region="Rooted Ziggurat Upper Entry", - destination="ziggurat2020_0_"), + destination="ziggurat2020_0", tag="_"), Portal(name="Ziggurat Upper to Ziggurat Tower", region="Rooted Ziggurat Upper Back", - destination="ziggurat2020_2_"), + destination="ziggurat2020_2", tag="_"), Portal(name="Ziggurat Tower to Ziggurat Upper", region="Rooted Ziggurat Middle Top", - destination="ziggurat2020_1_"), + destination="ziggurat2020_1", tag="_"), Portal(name="Ziggurat Tower to Ziggurat Lower", region="Rooted Ziggurat Middle Bottom", - destination="ziggurat2020_3_"), + destination="ziggurat2020_3", tag="_"), Portal(name="Ziggurat Lower to Ziggurat Tower", region="Rooted Ziggurat Lower Front", - destination="ziggurat2020_2_"), + destination="ziggurat2020_2", tag="_"), Portal(name="Ziggurat Portal Room Entrance", region="Rooted Ziggurat Portal Room Entrance", - destination="ziggurat2020_FTRoom_"), + destination="ziggurat2020_FTRoom", tag="_"), Portal(name="Ziggurat Portal Room Exit", region="Rooted Ziggurat Portal Room Exit", - destination="ziggurat2020_3_"), + destination="ziggurat2020_3", tag="_"), Portal(name="Ziggurat to Far Shore", region="Rooted Ziggurat Portal", - destination="Transit_teleporter_ziggurat teleporter"), + destination="Transit", tag="_teleporter_ziggurat teleporter"), Portal(name="Swamp Lower Exit", region="Swamp Front", - destination="Overworld Redux_conduit"), + destination="Overworld Redux", tag="_conduit"), Portal(name="Swamp to Cathedral Main Entrance", region="Swamp to Cathedral Main Entrance Region", - destination="Cathedral Redux_main"), + destination="Cathedral Redux", tag="_main"), Portal(name="Swamp to Cathedral Secret Legend Room Entrance", region="Swamp to Cathedral Treasure Room", - destination="Cathedral Redux_secret"), + destination="Cathedral Redux", tag="_secret"), Portal(name="Swamp to Gauntlet", region="Back of Swamp", - destination="Cathedral Arena_"), + destination="Cathedral Arena", tag="_"), Portal(name="Swamp Shop", region="Swamp Front", - destination="Shop_"), + destination="Shop", tag="_"), Portal(name="Swamp Upper Exit", region="Back of Swamp Laurels Area", - destination="Overworld Redux_wall"), + destination="Overworld Redux", tag="_wall"), Portal(name="Swamp Hero's Grave", region="Swamp Hero's Grave Region", - destination="RelicVoid_teleporter_relic plinth"), + destination="RelicVoid", tag="_teleporter_relic plinth"), Portal(name="Cathedral Main Exit", region="Cathedral", - destination="Swamp Redux 2_main"), + destination="Swamp Redux 2", tag="_main"), Portal(name="Cathedral Elevator", region="Cathedral", - destination="Cathedral Arena_"), + destination="Cathedral Arena", tag="_"), Portal(name="Cathedral Secret Legend Room Exit", region="Cathedral Secret Legend Room", - destination="Swamp Redux 2_secret"), + destination="Swamp Redux 2", tag="_secret"), Portal(name="Gauntlet to Swamp", region="Cathedral Gauntlet Exit", - destination="Swamp Redux 2_"), + destination="Swamp Redux 2", tag="_"), Portal(name="Gauntlet Elevator", region="Cathedral Gauntlet Checkpoint", - destination="Cathedral Redux_"), + destination="Cathedral Redux", tag="_"), Portal(name="Gauntlet Shop", region="Cathedral Gauntlet Checkpoint", - destination="Shop_"), + destination="Shop", tag="_"), Portal(name="Hero's Grave to Fortress", region="Hero Relic - Fortress", - destination="Fortress Reliquary_teleporter_relic plinth"), + destination="Fortress Reliquary", tag="_teleporter_relic plinth"), Portal(name="Hero's Grave to Monastery", region="Hero Relic - Quarry", - destination="Monastery_teleporter_relic plinth"), + destination="Monastery", tag="_teleporter_relic plinth"), Portal(name="Hero's Grave to West Garden", region="Hero Relic - West Garden", - destination="Archipelagos Redux_teleporter_relic plinth"), + destination="Archipelagos Redux", tag="_teleporter_relic plinth"), Portal(name="Hero's Grave to East Forest", region="Hero Relic - East Forest", - destination="Sword Access_teleporter_relic plinth"), + destination="Sword Access", tag="_teleporter_relic plinth"), Portal(name="Hero's Grave to Library", region="Hero Relic - Library", - destination="Library Hall_teleporter_relic plinth"), + destination="Library Hall", tag="_teleporter_relic plinth"), Portal(name="Hero's Grave to Swamp", region="Hero Relic - Swamp", - destination="Swamp Redux 2_teleporter_relic plinth"), + destination="Swamp Redux 2", tag="_teleporter_relic plinth"), Portal(name="Far Shore to West Garden", region="Far Shore to West Garden Region", - destination="Archipelagos Redux_teleporter_archipelagos_teleporter"), + destination="Archipelagos Redux", tag="_teleporter_archipelagos_teleporter"), Portal(name="Far Shore to Library", region="Far Shore to Library Region", - destination="Library Lab_teleporter_library teleporter"), + destination="Library Lab", tag="_teleporter_library teleporter"), Portal(name="Far Shore to Quarry", region="Far Shore to Quarry Region", - destination="Quarry Redux_teleporter_quarry teleporter"), + destination="Quarry Redux", tag="_teleporter_quarry teleporter"), Portal(name="Far Shore to East Forest", region="Far Shore to East Forest Region", - destination="East Forest Redux_teleporter_forest teleporter"), + destination="East Forest Redux", tag="_teleporter_forest teleporter"), Portal(name="Far Shore to Fortress", region="Far Shore to Fortress Region", - destination="Fortress Arena_teleporter_spidertank"), + destination="Fortress Arena", tag="_teleporter_spidertank"), Portal(name="Far Shore to Atoll", region="Far Shore", - destination="Atoll Redux_teleporter_atoll"), + destination="Atoll Redux", tag="_teleporter_atoll"), Portal(name="Far Shore to Ziggurat", region="Far Shore", - destination="ziggurat2020_FTRoom_teleporter_ziggurat teleporter"), + destination="ziggurat2020_FTRoom", tag="_teleporter_ziggurat teleporter"), Portal(name="Far Shore to Heir", region="Far Shore", - destination="Spirit Arena_teleporter_spirit arena"), + destination="Spirit Arena", tag="_teleporter_spirit arena"), Portal(name="Far Shore to Town", region="Far Shore", - destination="Overworld Redux_teleporter_town"), + destination="Overworld Redux", tag="_teleporter_town"), Portal(name="Far Shore to Spawn", region="Far Shore to Spawn Region", - destination="Overworld Redux_teleporter_starting island"), + destination="Overworld Redux", tag="_teleporter_starting island"), Portal(name="Heir Arena Exit", region="Spirit Arena", - destination="Transit_teleporter_spirit arena"), + destination="Transit", tag="_teleporter_spirit arena"), Portal(name="Purgatory Bottom Exit", region="Purgatory", - destination="Purgatory_bottom"), + destination="Purgatory", tag="_bottom"), Portal(name="Purgatory Top Exit", region="Purgatory", - destination="Purgatory_top"), + destination="Purgatory", tag="_top"), ] @@ -710,6 +714,8 @@ class DeadEnd(IntEnum): "Shop Entrance 4": RegionInfo("Shop", dead_end=DeadEnd.all_cats), "Shop Entrance 5": RegionInfo("Shop", dead_end=DeadEnd.all_cats), "Shop Entrance 6": RegionInfo("Shop", dead_end=DeadEnd.all_cats), + "Shop Entrance 7": RegionInfo("Shop", dead_end=DeadEnd.all_cats), + "Shop Entrance 8": RegionInfo("Shop", dead_end=DeadEnd.all_cats), "Shop": RegionInfo("Shop", dead_end=DeadEnd.all_cats), "Spirit Arena": RegionInfo("Spirit Arena", dead_end=DeadEnd.all_cats), "Spirit Arena Victory": RegionInfo("Spirit Arena", dead_end=DeadEnd.all_cats) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index fb2e2d775ed2..ec8fd0cf3071 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -343,7 +343,8 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Forest Belltower Main"]) regions["Forest Belltower Main"].connect( - connecting_region=regions["Forest Belltower Lower"]) + connecting_region=regions["Forest Belltower Lower"], + rule=lambda state: has_ladder("Ladder Drop to East Forest", state, player, options)) # nmg: ice grapple up to dance fox spot, and vice versa regions["East Forest"].connect( diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 0bbe7cd1bd93..f130779b680f 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -20,11 +20,14 @@ class TunicERLocation(Location): def create_er_regions(world: "TunicWorld") -> Dict[Portal, Portal]: regions: Dict[str, Region] = {} - portal_pairs: Dict[Portal, Portal] = pair_portals(world) + if world.options.entrance_rando: + portal_pairs: Dict[Portal, Portal] = pair_portals(world) - # output the entrances to the spoiler log here for convenience - for portal1, portal2 in portal_pairs.items(): - world.multiworld.spoiler.set_entrance(portal1.name, portal2.name, "both", world.player) + # output the entrances to the spoiler log here for convenience + for portal1, portal2 in portal_pairs.items(): + world.multiworld.spoiler.set_entrance(portal1.name, portal2.name, "both", world.player) + else: + portal_pairs: Dict[Portal, Portal] = vanilla_portals() for region_name, region_data in tunic_er_regions.items(): regions[region_name] = Region(region_name, world.player, world.multiworld) @@ -82,13 +85,45 @@ def place_event_items(world: "TunicWorld", regions: Dict[str, Region]) -> None: region.locations.append(location) +def vanilla_portals() -> Dict[Portal, Portal]: + portal_pairs: Dict[Portal, Portal] = {} + portal_map = portal_mapping.copy() + shop_num = 1 + + while portal_map: + portal1 = portal_map[0] + portal2 = None + # portal2 scene destination tag is portal1's destination scene tag + portal2_sdt = portal1.destination_scene() + + if portal2_sdt.startswith("Shop,"): + portal2 = Portal(name=f"Shop", region=f"Shop Entrance {shop_num}", + destination="Previous Region", tag="_") + shop_num += 1 + + if portal2_sdt == "Purgatory, Purgatory_bottom": + portal2_sdt = "Purgatory, Purgatory_top" + + for portal in portal_map: + if portal.scene_destination() == portal2_sdt: + portal2 = portal + break + + portal_pairs[portal1] = portal2 + portal_map.remove(portal1) + if not portal2_sdt.startswith("Shop,"): + if portal2 not in portal_map: + print(portal1.scene_destination()) + print(portal1.destination_scene()) + portal_map.remove(portal2) + + return portal_pairs + + # pairing off portals, starting with dead ends def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: # separate the portals into dead ends and non-dead ends portal_pairs: Dict[Portal, Portal] = {} - - # todo: if not er, return vanilla connections - dead_ends: List[Portal] = [] two_plus: List[Portal] = [] plando_connections: List[PlandoConnection] = [] @@ -183,7 +218,7 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: if portal.scene_destination() == "Overworld Redux, Windmill_": portal1 = portal break - portal2 = Portal(name="Shop Portal", region=f"Shop Entrance 2", destination="Previous Region_") + portal2 = Portal(name="Shop Portal", region="Shop Entrance 2", destination="Previous Region", tag="_") portal_pairs[portal1] = portal2 two_plus.remove(portal1) @@ -257,7 +292,7 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: break if portal1 is None: raise Exception("Too many shops in the pool, or something else went wrong") - portal2 = Portal(name=f"Shop Portal {i + 1}", region=f"Shop Entrance {i + 1}", destination="Previous Region_") + portal2 = Portal(name=f"Shop Portal {i + 1}", region=f"Shop Entrance {i + 1}", destination="Previous Region", tag="_") portal_pairs[portal1] = portal2 # connect dead ends to random non-dead ends @@ -287,7 +322,7 @@ def create_randomized_entrances(portal_pairs: Dict[Portal, Portal], regions: Dic region2 = regions[portal2.region] region1.connect(connecting_region=region2, name=portal1.name) # prevent the logic from thinking you can get to any shop-connected region from the shop - if portal2.name != "Shop": + if portal2.name not in ["Shop", "Shop Portal"]: region2.connect(connecting_region=region1, name=portal2.name) @@ -453,7 +488,7 @@ def create_plando_connections(plando_connections: List[PlandoConnection], portal2 = portal break if p_exit == "Shop Portal": - portal2 = Portal(name="Shop Portal", region=f"Shop Entrance {shop_num}", destination="Previous Region_") + portal2 = Portal(name="Shop Portal", region=f"Shop Entrance {shop_num}", destination="Previous Region", tag="_") shop_num += 1 else: dead_ends.remove(portal2) diff --git a/worlds/tunic/ladder_rules.py b/worlds/tunic/ladder_rules.py deleted file mode 100644 index f30e1a652ffa..000000000000 --- a/worlds/tunic/ladder_rules.py +++ /dev/null @@ -1,411 +0,0 @@ -from typing import Dict, TYPE_CHECKING -from BaseClasses import CollectionState -from worlds.generic.Rules import set_rule, forbid_item -from .rules import has_ability, has_sword, has_stick, has_ice_grapple_logic, has_lantern, has_mask, can_ladder_storage -from .options import TunicOptions -if TYPE_CHECKING: - from . import TunicWorld - -laurels = "Hero's Laurels" -grapple = "Magic Orb" -ice_dagger = "Magic Dagger" -fire_wand = "Magic Wand" -lantern = "Lantern" -fairies = "Fairy" -coins = "Golden Coin" -prayer = "Pages 24-25 (Prayer)" -holy_cross = "Pages 42-43 (Holy Cross)" -icebolt = "Pages 52-53 (Icebolt)" -key = "Key" -house_key = "Old House Key" -vault_key = "Fortress Vault Key" -mask = "Scavenger Mask" -red_hexagon = "Red Questagon" -green_hexagon = "Green Questagon" -blue_hexagon = "Blue Questagon" -gold_hexagon = "Gold Questagon" - - -def can_reach_east_overworld(state: CollectionState, player: int, options: TunicOptions, ability_unlocks: Dict[str, int]) -> bool: - return ( - state.has_any({"Ladders near Weathervane", "Overworld Shortcut Ladders"}, player) - or has_ice_grapple_logic(True, state, player, options, ability_unlocks) - or (can_reach_upper_overworld(state, player, options, ability_unlocks) - and state.has("Ladders near Patrol Cave", player)) - or can_ladder_storage(state, player, options) - or (state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) - ) - - -def can_reach_upper_overworld(state: CollectionState, player: int, options: TunicOptions, ability_unlocks: Dict[str, int]) -> bool: - return ( - (state.has("Ladders near Dark Tomb", player) and state.has_any({laurels, grapple}, player)) - or ((state.has_any({"Ladders near Weathervane", "Overworld Shortcut Ladders", grapple}, player) - or can_ladder_storage(state, player, options)) - and (state.has("Ladders near Patrol Cave", player) - or has_ice_grapple_logic(True, state, player, options, ability_unlocks))) - ) - - -def set_ladder_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> None: - multiworld = world.multiworld - player = world.player - options = world.options - - multiworld.get_entrance("Overworld -> Overworld Holy Cross", player).access_rule = \ - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) - # simplified: can hit a bell & can reach east bell & can reach/hit west bell or can break in via front or can break in via back - multiworld.get_entrance("Overworld -> Sealed Temple", player).access_rule = \ - lambda state: (((has_stick(state, player) or state.has(fire_wand, player)) - and ((can_reach_east_overworld(state, player, options, ability_unlocks) and state.has("Ladder Drop to East Forest")) - or (has_ability(state, player, prayer, options, ability_unlocks) and state.has(laurels, player))) - and ((state.has("Ladders to West Bell", player) - and (state.has(laurels, player) - or (state.has_all({lantern, "Dark Tomb Ladder"}, player) and has_sword(state, player)))) - or (state.has(fire_wand, player) and state.has_any({"Overworld Shortcut Ladders", grapple}, player) and options.logic_rules))) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks) - or (can_reach_upper_overworld(state, player, options, ability_unlocks) and state.has_all({"Ladder near Temple Rafters", laurels}, player)) - or (can_ladder_storage(state, player, options) and state.has(laurels, player))) - multiworld.get_entrance("Overworld -> East Overworld", player).access_rule = \ - lambda state: can_reach_east_overworld(state, player, options, ability_unlocks) - multiworld.get_entrance("Overworld -> Upper Overworld", player).access_rule = \ - lambda state: can_reach_upper_overworld(state, player, options, ability_unlocks) - # use the ladder down, use laurels, or - multiworld.get_entrance("Overworld -> Overworld Beach", player).access_rule = \ - lambda state: state.has_any({"Overworld Town Ladders", laurels}, player) - multiworld.get_entrance("Overworld Beach -> West Garden", player).access_rule = \ - lambda state: state.has(laurels, player) - multiworld.get_entrance("West Garden -> Overworld Beach", player).access_rule = \ - lambda state: state.has(laurels, player) - multiworld.get_entrance("Overworld -> East Forest", player).access_rule = \ - lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks) - multiworld.get_entrance("East Overworld -> East Forest", player).access_rule = \ - lambda state: state.has("Ladder Drop to East Forest", player) - multiworld.get_entrance("East Forest -> Lower Forest", player).access_rule = \ - lambda state: state.has("Ladders to Lower Forest", player) \ - or (state.has_all({grapple, fire_wand, ice_dagger}, player) # do ice slime, then go to the lower hook - and has_ability(state, player, icebolt, options, ability_unlocks)) - multiworld.get_entrance("Overworld -> Swamp", player).access_rule = \ - lambda state: state.has("Ladder to Swamp", player) - multiworld.get_entrance("Swamp -> Swamp Middle", player).access_rule = \ - lambda state: state.has("Swamp Ladders", player) or state.has(laurels, player) - multiworld.get_entrance("Swamp Middle -> Cathedral", player).access_rule = \ - lambda state: (has_ability(state, player, prayer, options, ability_unlocks) - and (state.has(laurels, player) - or (can_ladder_storage(state, player, options) and state.has(fire_wand, player))) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) - multiworld.get_entrance("Overworld -> Back of Swamp", player).access_rule = \ - lambda state: state.has(laurels, player) - # before the ladder, just the one chest in the room where you open up the grave to the ladder - multiworld.get_entrance("Overworld -> Dark Tomb Front", player).access_rule = \ - lambda state: has_lantern(state, player, options) - multiworld.get_entrance("Dark Tomb Front -> Dark Tomb", player).access_rule = \ - lambda state: state.has("Dark Tomb Ladder", player) - # dark tomb to west garden has no rule intentionally - # Overworld -> West Garden access via furnace - multiworld.get_entrance("Overworld -> West Garden", player).access_rule = \ - lambda state: state.has(laurels, player) or can_ladder_storage(state, player, options) - multiworld.get_entrance("Overworld -> Beneath the Well", player).access_rule = \ - lambda state: state.has("Ladder to Well", player) and (has_stick(state, player) or state.has(fire_wand, player)) - multiworld.get_entrance("Beneath the Well -> Beneath the Well Back", player).access_rule = \ - lambda state: state.has("Well Back Ladder", player) - # dash to the fuse and have the rear ladder, or dash through the well boss gate in nmg - multiworld.get_entrance("Overworld -> Beneath the Well Back", player).access_rule = \ - lambda state: state.has(laurels, player) and (state.has("Well Back Ladder", player) - or options.logic_rules) - multiworld.get_entrance("Beneath the Well Back -> Beneath the Well", player).access_rule = \ - lambda state: state.has("Well Back Ladder", player) \ - and (has_stick(state, player) or state.has(fire_wand, player)) - multiworld.get_entrance("East Overworld -> Eastern Vault Fortress", player).access_rule = \ - lambda state: state.has(laurels, player) \ - or has_ice_grapple_logic(True, state, player, options, ability_unlocks) \ - or can_ladder_storage(state, player, options) - multiworld.get_entrance("East Overworld -> Beneath the Vault", player).access_rule = \ - lambda state: has_lantern(state, player, options) \ - and state.has("Ladder to Beneath the Vault", player) \ - and (can_ladder_storage(state, player, options) - or has_ability(state, player, prayer, options, ability_unlocks) - or state.has(laurels, player)) - # todo: LS to atoll upper, maybe also do atoll lower + orb from swamp, and vice versa? - multiworld.get_entrance("Overworld -> Ruined Atoll", player).access_rule = \ - lambda state: state.has(laurels, player) or has_ability(state, player, prayer, options, ability_unlocks) - # either use the ladder, or enter through the lower and use orb - multiworld.get_entrance("Overworld Beach -> Ruined Atoll", player).access_rule = \ - lambda state: state.has_any({"Ladder to Ruined Atoll", grapple}, player) - multiworld.get_entrance("Ruined Atoll -> Frog's Domain", player).access_rule = \ - lambda state: state.has("Ladders to Frog's Domain", player) - multiworld.get_entrance("Ruined Atoll -> Library", player).access_rule = \ - lambda state: state.has_any({grapple, laurels}, player) and \ - has_ability(state, player, prayer, options, ability_unlocks) and \ - state.has("South Atoll Ladders", player) - # have combat items, and the ladder to quarry, and the quarry ladder, or ls to skip those last two - multiworld.get_entrance("Overworld -> Quarry", player).access_rule = \ - lambda state: (has_sword(state, player) or state.has(fire_wand, player)) \ - and ((state.has_any({grapple, laurels}, player) and state.has("Ladder to Quarry", player)) - or can_ladder_storage(state, player, options)) - multiworld.get_entrance("Quarry Back -> Quarry", player).access_rule = \ - lambda state: has_sword(state, player) or state.has(fire_wand, player) - multiworld.get_entrance("Quarry -> Lower Quarry", player).access_rule = \ - lambda state: has_mask(state, player, options) - multiworld.get_entrance("Lower Quarry -> Rooted Ziggurat", player).access_rule = \ - lambda state: state.has(grapple, player) and has_ability(state, player, prayer, options, ability_unlocks) - multiworld.get_entrance("Overworld -> Spirit Arena", player).access_rule = \ - lambda state: (state.has(gold_hexagon, player, options.hexagon_goal.value) if options.hexagon_quest.value - else state.has_all({red_hexagon, green_hexagon, blue_hexagon}, player)) and \ - has_ability(state, player, prayer, options, ability_unlocks) and has_sword(state, player) - - -def set_ladder_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> None: - multiworld = world.multiworld - player = world.player - options = world.options - - forbid_item(multiworld.get_location("Secret Gathering Place - 20 Fairy Reward", player), fairies, player) - - # Ability Shuffle Exclusive Rules - set_rule(multiworld.get_location("Far Shore - Page Pickup", player), - lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Maze Cave - Maze Room Holy Cross", player), - lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Overworld - [Southwest] Haiku Holy Cross", player), - lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Overworld - [Northeast] Flowers Holy Cross", player), - lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Overworld - [Southwest] Flowers Holy Cross", player), - lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Overworld - [East] Weathervane Holy Cross", player), - lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Fortress Courtyard - Chest Near Cave", player), - lambda state: can_ladder_storage(state, player, options) - or has_ability(state, player, prayer, options, ability_unlocks) - or state.has(laurels, player)) - set_rule(multiworld.get_location("Fortress Courtyard - Page Near Cave", player), - lambda state: can_ladder_storage(state, player, options) - or has_ability(state, player, prayer, options, ability_unlocks) - or state.has(laurels, player)) - set_rule(multiworld.get_location("East Forest - Dancing Fox Spirit Holy Cross", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Forest Grave Path - Holy Cross Code by Grave", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("East Forest - Golden Obelisk Holy Cross", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Beneath the Well - [Powered Secret Room] Chest", player), - lambda state: has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("West Garden - [North] Behind Holy Cross Door", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Library Hall - Holy Cross Chest", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Eastern Vault Fortress - [West Wing] Candles Holy Cross", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("West Garden - [Central Highlands] Holy Cross (Blue Lines)", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Quarry - [Back Entrance] Bushes Holy Cross", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Cathedral - Secret Legend Trophy Chest", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) - and state.has("Swamp Ladders", player)) - set_rule(multiworld.get_location("Overworld - [Northwest] Golden Obelisk Page", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Overworld - [Northeast] Flowers Holy Cross", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Patrol Cave - Holy Cross Chest", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) - and (can_reach_east_overworld(state, player, options, ability_unlocks) - or ((can_reach_upper_overworld(state, player, options, ability_unlocks) or state.has(grapple, player)) - and state.has("Ladders near Patrol Cave", player)))) - set_rule(multiworld.get_location("Sealed Temple - Holy Cross Chest", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Ruined Passage - Holy Cross Chest", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) - and (state.has("Ladders near Weathervane", player) - or state.has(key, player, 2) - or (state.has(laurels, player) and options.logic_rules) - or has_ice_grapple_logic(True, state, player, options, ability_unlocks) - or can_ladder_storage(state, player, options))) - set_rule(multiworld.get_location("Caustic Light Cave - Holy Cross Chest", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Top of the Mountain - Page At The Peak", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) - - # Overworld - set_rule(multiworld.get_location("Overworld - [Southwest] Fountain Page", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Overworld - [Southwest] Grapple Chest Over Walkway", player), - lambda state: state.has_any({grapple, laurels}, player)) - set_rule(multiworld.get_location("Overworld - [Southwest] West Beach Guarded By Turret 2", player), - lambda state: state.has_any({grapple, laurels}, player)) - set_rule(multiworld.get_location("Far Shore - Secret Chest", player), - lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Overworld - [Southeast] Page on Pillar by Swamp", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Old House - Normal Chest", player), - lambda state: state.has(house_key, player) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks) - or (state.has(laurels, player) and options.logic_rules)) - set_rule(multiworld.get_location("Old House - Holy Cross Chest", player), - lambda state: has_ability(state, player, holy_cross, options, ability_unlocks) and - (state.has(house_key, player) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks) - or (state.has(laurels, player) and options.logic_rules))) - set_rule(multiworld.get_location("Old House - Shield Pickup", player), - lambda state: state.has(house_key, player) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks) - or (state.has(laurels, player) and options.logic_rules)) - set_rule(multiworld.get_location("Overworld - [Northwest] Page on Pillar by Dark Tomb", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Overworld - [Southwest] From West Garden", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Overworld - [West] Chest After Bell", player), - lambda state: state.has(laurels, player) - or (has_lantern(state, player, options) and has_sword(state, player) - and state.has_all({"Ladders to West Bell", "Dark Tomb Ladder"}, player)) - or can_ladder_storage(state, player, options)) - set_rule(multiworld.get_location("Overworld - [Northwest] Chest Beneath Quarry Gate", player), - lambda state: state.has_any({grapple, laurels}, player) or options.logic_rules) - set_rule(multiworld.get_location("Overworld - [East] Grapple Chest", player), - lambda state: state.has(grapple, player)) - set_rule(multiworld.get_location("Special Shop - Secret Page Pickup", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Ruined Passage - Page Pickup", player), - lambda state: state.has("Ladders near Weathervane", player) - or state.has(key, player, 2) - or (state.has(laurels, player) and options.logic_rules) - or has_ice_grapple_logic(True, state, player, options, ability_unlocks) - or can_ladder_storage(state, player, options)) - set_rule(multiworld.get_location("Overworld - [East] Between Ladders Near Ruined Passage", player), - lambda state: state.has("Ladders near Weathervane", player) - or state.has(key, player, 2) - or (state.has(laurels, player) and options.logic_rules) - or has_ice_grapple_logic(True, state, player, options, ability_unlocks) - or can_ladder_storage(state, player, options)) - set_rule(multiworld.get_location("Overworld - [East] Chest In Trees", player), - lambda state: state.has_any({laurels, "Ladders near Weathervane"}, player)) - set_rule(multiworld.get_location("Hourglass Cave - Holy Cross Chest", player), - lambda state: state.has("Hourglass Cave Ladders", player) - and has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("Overworld - [Northwest] Chest Near Golden Obelisk", player), - lambda state: state.has("Ladders near Dark Tomb", player) - or (can_reach_upper_overworld(state, player, options, ability_unlocks) - and state.has_any({laurels, grapple}, player))) - set_rule(multiworld.get_location("Patrol Cave - Normal Chest", player), - lambda state: can_reach_east_overworld(state, player, options, ability_unlocks) - or ((can_reach_upper_overworld(state, player, options, ability_unlocks) or state.has(grapple, player)) - and state.has("Ladders near Patrol Cave", player))) - - set_rule(multiworld.get_location("Secret Gathering Place - 10 Fairy Reward", player), - lambda state: state.has(fairies, player, 10)) - set_rule(multiworld.get_location("Secret Gathering Place - 20 Fairy Reward", player), - lambda state: state.has(fairies, player, 20)) - set_rule(multiworld.get_location("Coins in the Well - 3 Coins", player), - lambda state: state.has(coins, player, 3)) - set_rule(multiworld.get_location("Coins in the Well - 6 Coins", player), - lambda state: state.has(coins, player, 6)) - set_rule(multiworld.get_location("Coins in the Well - 10 Coins", player), - lambda state: state.has(coins, player, 10)) - set_rule(multiworld.get_location("Coins in the Well - 15 Coins", player), - lambda state: state.has(coins, player, 15)) - - # East Forest - set_rule(multiworld.get_location("East Forest - Lower Grapple Chest", player), - lambda state: state.has(grapple, player)) - set_rule(multiworld.get_location("East Forest - Lower Dash Chest", player), - lambda state: state.has_all({grapple, laurels}, player)) - set_rule(multiworld.get_location("East Forest - Ice Rod Grapple Chest", player), - lambda state: state.has_all({grapple, ice_dagger, fire_wand}, player) - and has_ability(state, player, icebolt, options, ability_unlocks)) - - # West Garden - set_rule(multiworld.get_location("West Garden - [North] Across From Page Pickup", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("West Garden - [West] In Flooded Walkway", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("West Garden - [West Lowlands] Tree Holy Cross Chest", player), - lambda state: state.has(laurels, player) - and has_ability(state, player, holy_cross, options, ability_unlocks)) - set_rule(multiworld.get_location("West Garden - [East Lowlands] Page Behind Ice Dagger House", player), - lambda state: (state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) - or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) - set_rule(multiworld.get_location("West Garden - [Central Lowlands] Below Left Walkway", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("West Garden - [Central Highlands] After Garden Knight", player), - lambda state: has_sword(state, player) or state.has(laurels, player) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks) - or can_ladder_storage(state, player, options)) - - # Ruined Atoll - set_rule(multiworld.get_location("Ruined Atoll - [West] Near Kevin Block", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Ruined Atoll - [East] Locked Room Lower Chest", player), - lambda state: state.has_any({laurels, key}, player)) - set_rule(multiworld.get_location("Ruined Atoll - [East] Locked Room Upper Chest", player), - lambda state: state.has_any({laurels, key}, player)) - set_rule(multiworld.get_location("Librarian - Hexagon Green", player), - lambda state: has_sword(state, player) or options.logic_rules) - set_rule(multiworld.get_location("Ruined Atoll - [Southeast] Chest Near Fuse", player), - lambda state: state.has("South Atoll Ladders", player)) - set_rule(multiworld.get_location("Ruined Atoll - [South] Upper Floor On Bricks", player), - lambda state: state.has("South Atoll Ladders", player)) - set_rule(multiworld.get_location("Ruined Atoll - [South] Upper Floor On Power Line", player), - lambda state: state.has("South Atoll Ladders", player)) - - # Frog's Domain - set_rule(multiworld.get_location("Frog's Domain - Side Room Grapple Secret", player), - lambda state: state.has_any({grapple, laurels}, player)) - set_rule(multiworld.get_location("Frog's Domain - Grapple Above Hot Tub", player), - lambda state: state.has_any({grapple, laurels}, player)) - set_rule(multiworld.get_location("Frog's Domain - Escape Chest", player), - lambda state: state.has_any({grapple, laurels}, player)) - - # Eastern Vault Fortress - set_rule(multiworld.get_location("Fortress Leaf Piles - Secret Chest", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Fortress Arena - Siege Engine/Vault Key Pickup", player), - lambda state: has_sword(state, player) and - (has_ability(state, player, prayer, options, ability_unlocks) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks))) - set_rule(multiworld.get_location("Fortress Arena - Hexagon Red", player), - lambda state: state.has(vault_key, player) and - (has_ability(state, player, prayer, options, ability_unlocks) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks))) - - # Beneath the Vault - set_rule(multiworld.get_location("Beneath the Fortress - Bridge", player), - lambda state: has_stick(state, player) or state.has_any({laurels, fire_wand}, player)) - set_rule(multiworld.get_location("Beneath the Fortress - Obscured Behind Waterfall", player), - lambda state: has_stick(state, player) and has_lantern(state, player, options)) - - # Quarry - set_rule(multiworld.get_location("Quarry - [Central] Above Ladder Dash Chest", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Quarry - [West] Upper Area Bombable Wall", player), - lambda state: has_mask(state, player, options)) - set_rule(multiworld.get_location("Rooted Ziggurat Lower - Hexagon Blue", player), - lambda state: has_sword(state, player)) - - # Swamp - set_rule(multiworld.get_location("Cathedral Gauntlet - Gauntlet Reward", player), - lambda state: state.has(laurels, player) and state.has(fire_wand, player) and has_sword(state, player)) - set_rule(multiworld.get_location("Swamp - [Entrance] Above Entryway", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Swamp - [South Graveyard] Upper Walkway Dash Chest", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Swamp - [Outside Cathedral] Obscured Behind Memorial", player), - lambda state: state.has(laurels, player)) - set_rule(multiworld.get_location("Swamp - [South Graveyard] 4 Orange Skulls", player), - lambda state: has_sword(state, player)) - set_rule(multiworld.get_location("Swamp - [South Graveyard] Guarded By Tentacles", player), - lambda state: has_sword(state, player)) - - # Hero's Grave - set_rule(multiworld.get_location("Hero's Grave - Tooth Relic", player), - lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Hero's Grave - Mushroom Relic", player), - lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Hero's Grave - Ash Relic", player), - lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Hero's Grave - Flowers Relic", player), - lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Hero's Grave - Effigy Relic", player), - lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) - set_rule(multiworld.get_location("Hero's Grave - Feathers Relic", player), - lambda state: state.has(laurels, player) and has_ability(state, player, prayer, options, ability_unlocks)) diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index 7650123c70cb..23550de82744 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -4,29 +4,25 @@ class TunicLocationData(NamedTuple): region: str er_region: str # entrance rando region - ladder_region: Optional[str] = None location_group: Optional[str] = None - def ladders_region(self) -> str: - return self.ladder_region or self.region - location_base_id = 509342400 location_table: Dict[str, TunicLocationData] = { - "Beneath the Well - [Powered Secret Room] Chest": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), + "Beneath the Well - [Powered Secret Room] Chest": TunicLocationData("Beneath the Well", "Beneath the Well Back"), "Beneath the Well - [Entryway] Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Third Room] Beneath Platform Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Third Room] Tentacle Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Entryway] Obscured Behind Waterfall": TunicLocationData("Beneath the Well", "Beneath the Well Main"), - "Beneath the Well - [Save Room] Upper Floor Chest 1": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), - "Beneath the Well - [Save Room] Upper Floor Chest 2": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), + "Beneath the Well - [Save Room] Upper Floor Chest 1": TunicLocationData("Beneath the Well", "Beneath the Well Back"), + "Beneath the Well - [Save Room] Upper Floor Chest 2": TunicLocationData("Beneath the Well", "Beneath the Well Back"), "Beneath the Well - [Second Room] Underwater Chest": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Back Corridor] Right Secret": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Back Corridor] Left Secret": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Beneath the Well - [Second Room] Obscured Behind Waterfall": TunicLocationData("Beneath the Well", "Beneath the Well Main"), - "Beneath the Well - [Side Room] Chest By Pots": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), - "Beneath the Well - [Side Room] Chest By Phrends": TunicLocationData("Beneath the Well", "Beneath the Well Back", ladder_region="Beneath the Well Back"), + "Beneath the Well - [Side Room] Chest By Pots": TunicLocationData("Beneath the Well", "Beneath the Well Back"), + "Beneath the Well - [Side Room] Chest By Phrends": TunicLocationData("Beneath the Well", "Beneath the Well Back"), "Beneath the Well - [Second Room] Page": TunicLocationData("Beneath the Well", "Beneath the Well Main"), "Dark Tomb Checkpoint - [Passage To Dark Tomb] Page Pickup": TunicLocationData("Overworld", "Dark Tomb Checkpoint"), "Cathedral - [1F] Guarded By Lasers": TunicLocationData("Cathedral", "Cathedral"), @@ -42,25 +38,25 @@ def ladders_region(self) -> str: "Dark Tomb - 2nd Laser Room": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - 1st Laser Room": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - Spike Maze Upper Walkway": TunicLocationData("Dark Tomb", "Dark Tomb Main"), - "Dark Tomb - Skulls Chest": TunicLocationData("Dark Tomb", "Dark Tomb Upper", ladder_region="Dark Tomb Front"), + "Dark Tomb - Skulls Chest": TunicLocationData("Dark Tomb", "Dark Tomb Upper"), "Dark Tomb - Spike Maze Near Stairs": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Dark Tomb - 1st Laser Room Obscured": TunicLocationData("Dark Tomb", "Dark Tomb Main"), "Guardhouse 2 - Upper Floor": TunicLocationData("East Forest", "Guard House 2 Upper"), - "Guardhouse 2 - Bottom Floor Secret": TunicLocationData("East Forest", "Guard House 2 Lower", ladder_region="Lower Forest"), + "Guardhouse 2 - Bottom Floor Secret": TunicLocationData("East Forest", "Guard House 2 Lower"), "Guardhouse 1 - Upper Floor Obscured": TunicLocationData("East Forest", "Guard House 1 East"), "Guardhouse 1 - Upper Floor": TunicLocationData("East Forest", "Guard House 1 East"), "East Forest - Dancing Fox Spirit Holy Cross": TunicLocationData("East Forest", "East Forest Dance Fox Spot", location_group="holy cross"), - "East Forest - Golden Obelisk Holy Cross": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest", location_group="holy cross"), + "East Forest - Golden Obelisk Holy Cross": TunicLocationData("East Forest", "Lower Forest", location_group="holy cross"), "East Forest - Ice Rod Grapple Chest": TunicLocationData("East Forest", "East Forest"), "East Forest - Above Save Point": TunicLocationData("East Forest", "East Forest"), "East Forest - Above Save Point Obscured": TunicLocationData("East Forest", "East Forest"), "East Forest - From Guardhouse 1 Chest": TunicLocationData("East Forest", "East Forest Dance Fox Spot"), "East Forest - Near Save Point": TunicLocationData("East Forest", "East Forest"), - "East Forest - Beneath Spider Chest": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest"), + "East Forest - Beneath Spider Chest": TunicLocationData("East Forest", "Lower Forest"), "East Forest - Near Telescope": TunicLocationData("East Forest", "East Forest"), - "East Forest - Spider Chest": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest"), - "East Forest - Lower Dash Chest": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest"), - "East Forest - Lower Grapple Chest": TunicLocationData("East Forest", "Lower Forest", ladder_region="Lower Forest"), + "East Forest - Spider Chest": TunicLocationData("East Forest", "Lower Forest"), + "East Forest - Lower Dash Chest": TunicLocationData("East Forest", "Lower Forest"), + "East Forest - Lower Grapple Chest": TunicLocationData("East Forest", "Lower Forest"), "East Forest - Bombable Wall": TunicLocationData("East Forest", "East Forest"), "East Forest - Page On Teleporter": TunicLocationData("East Forest", "East Forest"), "Forest Belltower - Near Save Point": TunicLocationData("East Forest", "Forest Belltower Lower"), @@ -114,53 +110,53 @@ def ladders_region(self) -> str: "Library Lab - Page 1": TunicLocationData("Library", "Library Lab"), "Library Lab - Page 2": TunicLocationData("Library", "Library Lab"), "Hero's Grave - Mushroom Relic": TunicLocationData("Library", "Hero Relic - Library", location_group="hero relic"), - "Lower Mountain - Page Before Door": TunicLocationData("Overworld", "Lower Mountain", ladder_region="Upper Overworld"), + "Lower Mountain - Page Before Door": TunicLocationData("Overworld", "Lower Mountain"), "Changing Room - Normal Chest": TunicLocationData("Overworld", "Changing Room"), - "Fortress Courtyard - Chest Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave", ladder_region="East Overworld"), - "Fortress Courtyard - Near Fuse": TunicLocationData("Overworld", "Fortress Exterior from Overworld", ladder_region="East Overworld"), - "Fortress Courtyard - Below Walkway": TunicLocationData("Overworld", "Fortress Exterior from Overworld", ladder_region="East Overworld"), - "Fortress Courtyard - Page Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave", ladder_region="East Overworld"), - "West Furnace - Lantern Pickup": TunicLocationData("Overworld", "Furnace Fuse", ladder_region="Beneath the Well Back"), - "Maze Cave - Maze Room Chest": TunicLocationData("Overworld", "Maze Cave", ladder_region="Overworld Beach"), + "Fortress Courtyard - Chest Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave"), + "Fortress Courtyard - Near Fuse": TunicLocationData("Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Below Walkway": TunicLocationData("Overworld", "Fortress Exterior from Overworld"), + "Fortress Courtyard - Page Near Cave": TunicLocationData("Overworld", "Fortress Exterior near cave"), + "West Furnace - Lantern Pickup": TunicLocationData("Overworld", "Furnace Fuse"), + "Maze Cave - Maze Room Chest": TunicLocationData("Overworld", "Maze Cave"), "Old House - Normal Chest": TunicLocationData("Overworld", "Old House Front"), "Old House - Shield Pickup": TunicLocationData("Overworld", "Old House Front"), "Overworld - [West] Obscured Behind Windmill": TunicLocationData("Overworld", "Overworld"), - "Overworld - [South] Beach Chest": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), + "Overworld - [South] Beach Chest": TunicLocationData("Overworld", "Overworld Beach"), "Overworld - [West] Obscured Near Well": TunicLocationData("Overworld", "Overworld"), "Overworld - [Central] Bombable Wall": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Chest Near Turret": TunicLocationData("Overworld", "Overworld"), - "Overworld - [East] Chest Near Pots": TunicLocationData("Overworld", "East Overworld", ladder_region="East Overworld"), + "Overworld - [East] Chest Near Pots": TunicLocationData("Overworld", "East Overworld"), "Overworld - [Northwest] Chest Near Golden Obelisk": TunicLocationData("Overworld", "Overworld above Quarry Entrance"), "Overworld - [Southwest] South Chest Near Guard": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Southwest] West Beach Guarded By Turret": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), + "Overworld - [Southwest] West Beach Guarded By Turret": TunicLocationData("Overworld", "Overworld Beach"), "Overworld - [Southwest] Chest Guarded By Turret": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Shadowy Corner Chest": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Obscured In Tunnel To Beach": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Grapple Chest Over Walkway": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Chest Beneath Quarry Gate": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Southeast] Chest Near Swamp": TunicLocationData("Overworld", "Overworld Swamp Lower Entry", ladder_region="Swamp"), - "Overworld - [Southwest] From West Garden": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), + "Overworld - [Southeast] Chest Near Swamp": TunicLocationData("Overworld", "Overworld Swamp Lower Entry"), + "Overworld - [Southwest] From West Garden": TunicLocationData("Overworld", "Overworld Beach"), "Overworld - [East] Grapple Chest": TunicLocationData("Overworld", "Overworld above Patrol Cave"), - "Overworld - [Southwest] West Beach Guarded By Turret 2": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), - "Overworld - [Southwest] Beach Chest Near Flowers": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), + "Overworld - [Southwest] West Beach Guarded By Turret 2": TunicLocationData("Overworld", "Overworld Beach"), + "Overworld - [Southwest] Beach Chest Near Flowers": TunicLocationData("Overworld", "Overworld Beach"), "Overworld - [Southwest] Bombable Wall Near Fountain": TunicLocationData("Overworld", "Overworld"), "Overworld - [West] Chest After Bell": TunicLocationData("Overworld", "Overworld Belltower"), "Overworld - [Southwest] Tunnel Guarded By Turret": TunicLocationData("Overworld", "Overworld"), "Overworld - [East] Between Ladders Near Ruined Passage": TunicLocationData("Overworld", "After Ruined Passage"), - "Overworld - [Northeast] Chest Above Patrol Cave": TunicLocationData("Overworld", "Upper Overworld", ladder_region="Upper Overworld"), - "Overworld - [Southwest] Beach Chest Beneath Guard": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), + "Overworld - [Northeast] Chest Above Patrol Cave": TunicLocationData("Overworld", "Upper Overworld"), + "Overworld - [Southwest] Beach Chest Beneath Guard": TunicLocationData("Overworld", "Overworld Beach"), "Overworld - [Central] Chest Across From Well": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Chest Near Quarry Gate": TunicLocationData("Overworld", "Overworld"), "Overworld - [East] Chest In Trees": TunicLocationData("Overworld", "Above Ruined Passage"), "Overworld - [West] Chest Behind Moss Wall": TunicLocationData("Overworld", "Overworld"), - "Overworld - [South] Beach Page": TunicLocationData("Overworld", "Overworld Beach", ladder_region="Overworld Beach"), + "Overworld - [South] Beach Page": TunicLocationData("Overworld", "Overworld Beach"), "Overworld - [Southeast] Page on Pillar by Swamp": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Key Pickup": TunicLocationData("Overworld", "Overworld"), "Overworld - [West] Key Pickup": TunicLocationData("Overworld", "Overworld"), - "Overworld - [East] Page Near Secret Shop": TunicLocationData("Overworld", "East Overworld", ladder_region="East Overworld"), + "Overworld - [East] Page Near Secret Shop": TunicLocationData("Overworld", "East Overworld"), "Overworld - [Southwest] Fountain Page": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Page on Pillar by Dark Tomb": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Northwest] Fire Wand Pickup": TunicLocationData("Overworld", "Upper Overworld", ladder_region="Upper Overworld"), + "Overworld - [Northwest] Fire Wand Pickup": TunicLocationData("Overworld", "Upper Overworld"), "Overworld - [West] Page On Teleporter": TunicLocationData("Overworld", "Overworld"), "Overworld - [Northwest] Page By Well": TunicLocationData("Overworld", "Overworld"), "Patrol Cave - Normal Chest": TunicLocationData("Overworld", "Patrol Cave"), @@ -172,10 +168,10 @@ def ladders_region(self) -> str: "Shop - Potion 2": TunicLocationData("Overworld", "Shop", location_group="shop"), "Shop - Coin 1": TunicLocationData("Overworld", "Shop", location_group="shop"), "Shop - Coin 2": TunicLocationData("Overworld", "Shop", location_group="shop"), - "Special Shop - Secret Page Pickup": TunicLocationData("Overworld", "Special Shop", ladder_region="East Overworld"), + "Special Shop - Secret Page Pickup": TunicLocationData("Overworld", "Special Shop"), "Stick House - Stick Chest": TunicLocationData("Overworld", "Stick House"), - "Sealed Temple - Page Pickup": TunicLocationData("Overworld", "Sealed Temple", ladder_region="Sealed Temple"), - "Hourglass Cave - Hourglass Chest": TunicLocationData("Overworld", "Hourglass Cave", ladder_region="Overworld Beach"), + "Sealed Temple - Page Pickup": TunicLocationData("Overworld", "Sealed Temple"), + "Hourglass Cave - Hourglass Chest": TunicLocationData("Overworld", "Hourglass Cave"), "Far Shore - Secret Chest": TunicLocationData("Overworld", "Far Shore"), "Far Shore - Page Pickup": TunicLocationData("Overworld", "Far Shore to Spawn Region"), "Coins in the Well - 10 Coins": TunicLocationData("Overworld", "Overworld", location_group="well"), @@ -185,30 +181,30 @@ def ladders_region(self) -> str: "Secret Gathering Place - 20 Fairy Reward": TunicLocationData("Overworld", "Secret Gathering Place", location_group="fairies"), "Secret Gathering Place - 10 Fairy Reward": TunicLocationData("Overworld", "Secret Gathering Place", location_group="fairies"), "Overworld - [West] Moss Wall Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), - "Overworld - [Southwest] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Beach", ladder_region="Overworld Beach", location_group="holy cross"), + "Overworld - [Southwest] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Beach", location_group="holy cross"), "Overworld - [Southwest] Fountain Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), - "Overworld - [Northeast] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "East Overworld", ladder_region="East Overworld", location_group="holy cross"), - "Overworld - [East] Weathervane Holy Cross": TunicLocationData("Overworld Holy Cross", "East Overworld", ladder_region="East Overworld", location_group="holy cross"), + "Overworld - [Northeast] Flowers Holy Cross": TunicLocationData("Overworld Holy Cross", "East Overworld", location_group="holy cross"), + "Overworld - [East] Weathervane Holy Cross": TunicLocationData("Overworld Holy Cross", "East Overworld", location_group="holy cross"), "Overworld - [West] Windmill Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), - "Overworld - [Southwest] Haiku Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Beach", ladder_region="Overworld Beach", location_group="holy cross"), + "Overworld - [Southwest] Haiku Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Beach", location_group="holy cross"), "Overworld - [West] Windchimes Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), "Overworld - [South] Starting Platform Holy Cross": TunicLocationData("Overworld Holy Cross", "Overworld Holy Cross", location_group="holy cross"), - "Overworld - [Northwest] Golden Obelisk Page": TunicLocationData("Overworld Holy Cross", "Upper Overworld", ladder_region="Upper Overworld", location_group="holy cross"), + "Overworld - [Northwest] Golden Obelisk Page": TunicLocationData("Overworld Holy Cross", "Upper Overworld", location_group="holy cross"), "Old House - Holy Cross Door Page": TunicLocationData("Overworld Holy Cross", "Old House Back", location_group="holy cross"), "Cube Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Cube Cave", location_group="holy cross"), "Southeast Cross Door - Chest 3": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), "Southeast Cross Door - Chest 2": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), "Southeast Cross Door - Chest 1": TunicLocationData("Overworld Holy Cross", "Southeast Cross Room", location_group="holy cross"), - "Maze Cave - Maze Room Holy Cross": TunicLocationData("Overworld Holy Cross", "Maze Cave", ladder_region="Overworld Beach", location_group="holy cross"), - "Caustic Light Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Caustic Light Cave", ladder_region="Swamp", location_group="holy cross"), + "Maze Cave - Maze Room Holy Cross": TunicLocationData("Overworld Holy Cross", "Maze Cave", location_group="holy cross"), + "Caustic Light Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Caustic Light Cave", location_group="holy cross"), "Old House - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Old House Front", location_group="holy cross"), "Patrol Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Patrol Cave", location_group="holy cross"), - "Ruined Passage - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Ruined Passage", ladder_region="Overworld", location_group="holy cross"), - "Hourglass Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Hourglass Cave Tower", ladder_region="Overworld Beach", location_group="holy cross"), - "Sealed Temple - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Sealed Temple", ladder_region="Sealed Temple", location_group="holy cross"), + "Ruined Passage - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Ruined Passage", location_group="holy cross"), + "Hourglass Cave - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Hourglass Cave Tower", location_group="holy cross"), + "Sealed Temple - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Sealed Temple", location_group="holy cross"), "Fountain Cross Door - Page Pickup": TunicLocationData("Overworld Holy Cross", "Fountain Cross Room", location_group="holy cross"), "Secret Gathering Place - Holy Cross Chest": TunicLocationData("Overworld Holy Cross", "Secret Gathering Place", location_group="holy cross"), - "Top of the Mountain - Page At The Peak": TunicLocationData("Overworld Holy Cross", "Top of the Mountain", ladder_region="Upper Overworld", location_group="holy cross"), + "Top of the Mountain - Page At The Peak": TunicLocationData("Overworld Holy Cross", "Top of the Mountain", location_group="holy cross"), "Monastery - Monastery Chest": TunicLocationData("Quarry", "Monastery Back"), "Quarry - [Back Entrance] Bushes Holy Cross": TunicLocationData("Quarry Back", "Quarry Back", location_group="holy cross"), "Quarry - [Back Entrance] Chest": TunicLocationData("Quarry Back", "Quarry Back"), @@ -267,30 +263,30 @@ def ladders_region(self) -> str: "Ruined Atoll - [Northeast] Chest On Brick Walkway": TunicLocationData("Ruined Atoll", "Ruined Atoll"), "Ruined Atoll - [Southeast] Chest Near Fuse": TunicLocationData("Ruined Atoll", "Ruined Atoll Ladder Tops"), "Ruined Atoll - [Northeast] Key Pickup": TunicLocationData("Ruined Atoll", "Ruined Atoll"), - "Cathedral Gauntlet - Gauntlet Reward": TunicLocationData("Swamp", "Cathedral Gauntlet", ladder_region="Back of Swamp"), - "Cathedral - Secret Legend Trophy Chest": TunicLocationData("Swamp", "Cathedral Secret Legend Room", ladder_region="Swamp Middle"), - "Swamp - [Upper Graveyard] Obscured Behind Hill": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Cathedral Gauntlet - Gauntlet Reward": TunicLocationData("Swamp", "Cathedral Gauntlet"), + "Cathedral - Secret Legend Trophy Chest": TunicLocationData("Swamp", "Cathedral Secret Legend Room"), + "Swamp - [Upper Graveyard] Obscured Behind Hill": TunicLocationData("Swamp", "Swamp Mid"), "Swamp - [South Graveyard] 4 Orange Skulls": TunicLocationData("Swamp", "Swamp Front"), - "Swamp - [Central] Near Ramps Up": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), - "Swamp - [Upper Graveyard] Near Shield Fleemers": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), - "Swamp - [South Graveyard] Obscured Behind Ridge": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [Central] Near Ramps Up": TunicLocationData("Swamp", "Swamp Mid"), + "Swamp - [Upper Graveyard] Near Shield Fleemers": TunicLocationData("Swamp", "Swamp Mid"), + "Swamp - [South Graveyard] Obscured Behind Ridge": TunicLocationData("Swamp", "Swamp Mid"), "Swamp - [South Graveyard] Obscured Beneath Telescope": TunicLocationData("Swamp", "Swamp Front"), - "Swamp - [Entrance] Above Entryway": TunicLocationData("Swamp", "Back of Swamp Laurels Area", ladder_region="Back of Swamp"), - "Swamp - [Central] South Secret Passage": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [Entrance] Above Entryway": TunicLocationData("Swamp", "Back of Swamp Laurels Area"), + "Swamp - [Central] South Secret Passage": TunicLocationData("Swamp", "Swamp Mid"), "Swamp - [South Graveyard] Upper Walkway On Pedestal": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [South Graveyard] Guarded By Tentacles": TunicLocationData("Swamp", "Swamp Front"), - "Swamp - [Upper Graveyard] Near Telescope": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), - "Swamp - [Outside Cathedral] Near Moonlight Bridge Door": TunicLocationData("Swamp", "Swamp Ledge under Cathedral Door", ladder_region="Swamp Middle"), + "Swamp - [Upper Graveyard] Near Telescope": TunicLocationData("Swamp", "Swamp Mid"), + "Swamp - [Outside Cathedral] Near Moonlight Bridge Door": TunicLocationData("Swamp", "Swamp Ledge under Cathedral Door"), "Swamp - [Entrance] Obscured Inside Watchtower": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [Entrance] South Near Fence": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [South Graveyard] Guarded By Big Skeleton": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [South Graveyard] Chest Near Graves": TunicLocationData("Swamp", "Swamp Front"), "Swamp - [Entrance] North Small Island": TunicLocationData("Swamp", "Swamp Front"), - "Swamp - [Outside Cathedral] Obscured Behind Memorial": TunicLocationData("Swamp", "Back of Swamp", ladder_region="Back of Swamp"), - "Swamp - [Central] Obscured Behind Northern Mountain": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), - "Swamp - [South Graveyard] Upper Walkway Dash Chest": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [Outside Cathedral] Obscured Behind Memorial": TunicLocationData("Swamp", "Back of Swamp"), + "Swamp - [Central] Obscured Behind Northern Mountain": TunicLocationData("Swamp", "Swamp Mid"), + "Swamp - [South Graveyard] Upper Walkway Dash Chest": TunicLocationData("Swamp", "Swamp Mid"), "Swamp - [South Graveyard] Above Big Skeleton": TunicLocationData("Swamp", "Swamp Front"), - "Swamp - [Central] Beneath Memorial": TunicLocationData("Swamp", "Swamp Mid", ladder_region="Swamp Middle"), + "Swamp - [Central] Beneath Memorial": TunicLocationData("Swamp", "Swamp Mid"), "Hero's Grave - Feathers Relic": TunicLocationData("Swamp", "Hero Relic - Swamp", location_group="hero relic"), "West Furnace - Chest": TunicLocationData("West Garden", "Furnace Walking Path"), "Overworld - [West] Near West Garden Entrance": TunicLocationData("West Garden", "Overworld to West Garden from Furnace"), diff --git a/worlds/tunic/regions.py b/worlds/tunic/regions.py index 2225dcdc3144..c30a44bb8ff6 100644 --- a/worlds/tunic/regions.py +++ b/worlds/tunic/regions.py @@ -23,37 +23,3 @@ "Cathedral": set(), "Spirit Arena": set() } - - -tunic_ladder_regions: Dict[str, Set[str]] = { - "Menu": {"Overworld"}, - "Overworld": {"Dark Tomb Front", "West Garden", "Ruined Atoll", "Beneath the Well", "Beneath the Well Back", - "Quarry", "Swamp", "Back of Swamp", "Spirit Arena", "Sealed Temple", "East Overworld", - "Upper Overworld", "Overworld Holy Cross", "East Forest", "Overworld Beach"}, - "Overworld Holy Cross": set(), - "East Forest": {"Lower Forest"}, - "Lower Forest": set(), - "East Overworld": {"East Forest", "Eastern Vault Fortress", "Beneath the Vault"}, - "Upper Overworld": {"Quarry Back", "Sealed Temple"}, - "Overworld Beach": {"West Garden", "Ruined Atoll"}, - "Dark Tomb Front": {"Dark Tomb"}, - "Dark Tomb": {"West Garden"}, - "Beneath the Well": {"Beneath the Well Back"}, - "Beneath the Well Back": {"Beneath the Well"}, - "West Garden": {"Overworld Beach"}, - "Ruined Atoll": {"Frog's Domain", "Library"}, - "Frog's Domain": set(), - "Library": set(), - "Eastern Vault Fortress": {"Beneath the Vault"}, - "Beneath the Vault": {"Eastern Vault Fortress"}, - "Quarry Back": {"Quarry"}, - "Quarry": {"Lower Quarry"}, - "Lower Quarry": {"Rooted Ziggurat"}, - "Rooted Ziggurat": set(), - "Swamp": {"Swamp Middle"}, - "Swamp Middle": {"Cathedral"}, - "Cathedral": {"Back of Swamp"}, - "Back of Swamp": set(), - "Spirit Arena": set(), - "Sealed Temple": set() -} From c25ed090f98f84ac04d4591ab66f5d83c1079cc6 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 7 Mar 2024 21:11:53 -0500 Subject: [PATCH 38/82] Remove above ruined passage -> east overworld with laurels, cause it opens up too much --- worlds/tunic/er_rules.py | 1 - 1 file changed, 1 deletion(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index ec8fd0cf3071..f0f899011edb 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -135,7 +135,6 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Above Ruined Passage"].connect( connecting_region=regions["East Overworld"], rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) - or state.has(laurels, player) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["East Overworld"].connect( connecting_region=regions["Above Ruined Passage"], From 7ecb2ab3c1a9857b6903b80bfa0cfb74a2544a9b Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 7 Mar 2024 21:27:08 -0500 Subject: [PATCH 39/82] Fix cathedral door logic bug --- worlds/tunic/er_rules.py | 2 +- worlds/tunic/er_scripts.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index f0f899011edb..f81df844dae4 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -806,7 +806,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: ice grapple through cathedral door, can do it both ways regions["Swamp Mid"].connect( connecting_region=regions["Swamp to Cathedral Main Entrance Region"], - rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) + rule=lambda state: (has_ability(state, player, prayer, options, ability_unlocks) and state.has(laurels, player)) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) regions["Swamp to Cathedral Main Entrance Region"].connect( connecting_region=regions["Swamp Mid"], diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index f130779b680f..63a2d58a2327 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -68,7 +68,7 @@ def create_er_regions(world: "TunicWorld") -> Dict[Portal, Portal]: "Quarry Fuse": "Quarry", "Ziggurat Fuse": "Rooted Ziggurat Lower Back", "West Garden Fuse": "West Garden", - "Library Fuse": "Library Lab", + "Library Fuse": "Library Lab" } From 9e2000ed93f7487fe5518dcf42a5291510e3bab5 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 7 Mar 2024 23:51:50 -0500 Subject: [PATCH 40/82] emdash --- worlds/tunic/options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index 1b621a0a916a..41fcfd2ce98c 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -134,7 +134,7 @@ class LaurelsLocation(Choice): class ShuffleLadders(Toggle): """Turns several ladders in the game into items that must be found before they can be climbed on. Adds more layers of progression to the game by blocking access to many areas early on. - "Ladders were a mistake." -Andrew Shouldice""" + "Ladders were a mistake." —Andrew Shouldice""" internal_name = "shuffle_ladders" display_name = "Shuffle Ladders" From daf5caf66d1b905f00bde4cf0e734e92dd0d5651 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 8 Mar 2024 09:30:37 -0500 Subject: [PATCH 41/82] Update LS rules Add comments to make it clearer what's going on. Add exclusions for non-ER. --- worlds/tunic/er_rules.py | 68 +++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index f81df844dae4..00a9ef364379 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -727,16 +727,16 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Lower Quarry"], rule=lambda state: has_mask(state, player, options)) - # nmg: bring a scav over, then ice grapple through the door + # nmg: bring a scav over, then ice grapple through the door, only with ER on to avoid soft lock regions["Lower Quarry"].connect( connecting_region=regions["Lower Quarry Zig Door"], rule=lambda state: state.has("Activate Quarry Fuse", player) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) + or (has_ice_grapple_logic(False, state, player, options, ability_unlocks) and options.entrance_rando)) - # nmg: use ice grapple to get from the beginning of Quarry to the door without really needing mask + # nmg: use ice grapple to get from the beginning of Quarry to the door without really needing mask only with ER on regions["Quarry"].connect( connecting_region=regions["Lower Quarry Zig Door"], - rule=lambda state: has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + rule=lambda state: has_ice_grapple_logic(True, state, player, options, ability_unlocks) and options.entrance_rando) regions["Monastery Front"].connect( connecting_region=regions["Monastery Back"]) @@ -773,10 +773,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: can ice grapple on the voidlings to the double admin fight, still need to pray at the fuse regions["Rooted Ziggurat Lower Back"].connect( connecting_region=regions["Rooted Ziggurat Lower Front"], - rule=lambda state: ((state.has(laurels, player) or - has_ice_grapple_logic(True, state, player, options, ability_unlocks)) and - has_ability(state, player, prayer, options, ability_unlocks) - and has_sword(state, player)) or can_ladder_storage(state, player, options)) + rule=lambda state: ((state.has(laurels, player) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + and has_ability(state, player, prayer, options, ability_unlocks) + and has_sword(state, player)) + or can_ladder_storage(state, player, options)) regions["Rooted Ziggurat Lower Back"].connect( connecting_region=regions["Rooted Ziggurat Portal Room Entrance"], @@ -806,7 +807,8 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: ice grapple through cathedral door, can do it both ways regions["Swamp Mid"].connect( connecting_region=regions["Swamp to Cathedral Main Entrance Region"], - rule=lambda state: (has_ability(state, player, prayer, options, ability_unlocks) and state.has(laurels, player)) + rule=lambda state: (has_ability(state, player, prayer, options, ability_unlocks) + and state.has(laurels, player)) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) regions["Swamp to Cathedral Main Entrance Region"].connect( connecting_region=regions["Swamp Mid"], @@ -894,7 +896,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Far Shore to Library Region"].connect( connecting_region=regions["Far Shore"]) - # Misc + # Misc, to be consolidated when that plando connections pr gets merged regions["Shop Entrance 1"].connect( connecting_region=regions["Shop"]) regions["Shop Entrance 2"].connect( @@ -907,6 +909,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Shop"]) regions["Shop Entrance 6"].connect( connecting_region=regions["Shop"]) + regions["Shop Entrance 7"].connect( + connecting_region=regions["Shop"]) + regions["Shop Entrance 8"].connect( + connecting_region=regions["Shop"]) regions["Spirit Arena"].connect( connecting_region=regions["Spirit Arena Victory"], @@ -926,9 +932,11 @@ def get_portal_info(portal_sd: str) -> (str, str): raise Exception("no matches found in get_paired_region") ladder_storages: List[Tuple[str, str, Set[str]]] = [ + # LS from Overworld main # The upper Swamp entrance ("Overworld", "Overworld Redux, Swamp Redux 2_wall", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), + # Upper atoll entrance ("Overworld", "Overworld Redux, Atoll Redux_upper", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), # Furnace entrance, next to the sign that leads to West Garden @@ -949,38 +957,34 @@ def get_portal_info(portal_sd: str) -> (str, str): # Quarry entry ("Overworld", "Overworld Redux, Darkwoods Tunnel_", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well"}), - # East Forest entry ("Overworld", "Overworld Redux, Forest Belltower_", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), - # Fortress entry ("Overworld", "Overworld Redux, Fortress Courtyard_", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), - # Patrol Cave entry ("Overworld", "Overworld Redux, PatrolCave_", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Overworld Shortcut Ladders", "Ladder to Quarry", "Ladders near Dark Tomb"}), - - # Special Shop entry + # Special Shop entry, excluded in non-ER due to soft lock potential ("Overworld", "Overworld Redux, ShopSpecial_", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Overworld Shortcut Ladders", "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), - - # Temple Rafters + # Temple Rafters, excluded in non-ER + ladder rando due to soft lock potential ("Overworld", "Overworld Redux, Temple_rafters", {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", "Overworld Shortcut Ladders", "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), - - # Mountain Stairs + # Spot above the Quarry entrance, + # only gets you to the mountain stairs ("Overworld above Quarry Entrance", "Overworld Redux, Mountain_", {"Ladders near Dark Tomb"}), + # LS from the Overworld Beach # West Garden entry by the Furnace ("Overworld Beach", "Overworld Redux, Archipelagos Redux_lower", {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), @@ -1016,6 +1020,8 @@ def get_portal_info(portal_sd: str) -> (str, str): ("Overworld Beach", "Overworld Redux, Darkwoods Tunnel_", {"Ladder to Ruined Atoll"}), + # LS from that low spot where you normally walk to swamp + # Only has low ones you can't get to from main Overworld # West Garden main entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Archipelagos Redux_lower", {"Ladder to Swamp"}), @@ -1054,13 +1060,14 @@ def get_portal_info(portal_sd: str) -> (str, str): # Patrol Cave entry ("Overworld to West Garden Upper", "Overworld Redux, PatrolCave_", {"Ladders to West Bell"}), - # Special Shop entry + # Special Shop entry, excluded in non-ER due to soft lock potential ("Overworld to West Garden Upper", "Overworld Redux, ShopSpecial_", {"Ladders to West Bell"}), - # Temple Rafters + # Temple Rafters, excluded in non-ER and ladder rando due to soft lock potential ("Overworld to West Garden Upper", "Overworld Redux, Temple_rafters", {"Ladders to West Bell"}), + # In the furnace # Furnace ladder to the fuse entrance ("Furnace Ladder Area", "Furnace, Overworld Redux_gyro_upper_north", set()), # Furnace ladder to Dark Tomb @@ -1068,25 +1075,29 @@ def get_portal_info(portal_sd: str) -> (str, str): # Furnace ladder to the West Garden connector ("Furnace Ladder Area", "Furnace, Overworld Redux_gyro_west", set()), + # West Garden # West Garden exit after Garden Knight ("West Garden", "Archipelagos Redux, Overworld Redux_upper", set()), # West Garden laurels exit ("West Garden", "Archipelagos Redux, Overworld Redux_lowest", set()), - # Frog mouth entrance + # Atoll to Frog Stairs, use the little ladder you fix at the start ("Ruined Atoll", "Atoll Redux, Frog Stairs_mouth", set()), + ("Ruined Atoll", "Atoll Redux, Frog Stairs_eye", set()), + # East Forest # Entrance by the dancing fox holy cross spot ("East Forest", "East Forest Redux, East Forest Redux Laddercave_upper", set()), - # From the west side of guard house 1 to the east side + # From the west side of Guard House 1 to the east side ("Guard House 1 West", "East Forest Redux Laddercave, East Forest Redux_gate", set()), ("Guard House 1 West", "East Forest Redux Laddercave, Forest Boss Room_", set()), - # Upper exit from the Forest Grave Path, use ls at the ladder by the gate switch + # Upper exit from the Forest Grave Path, use LS at the ladder by the gate switch ("Forest Grave Path Main", "Sword Access, East Forest Redux_upper", set()), - # Fortress exterior shop, ls at the ladder by the telescope + # Fortress Exterior + # Fortress Exterior shop, ls at the ladder by the telescope ("Fortress Exterior from Overworld", "Fortress Courtyard, Shop_", set()), # Fortress main entry and grave path lower entry, ls at the ladder by the telescope ("Fortress Exterior from Overworld", "Fortress Courtyard, Fortress Main_Big Door", set()), @@ -1111,6 +1122,7 @@ def get_portal_info(portal_sd: str) -> (str, str): ("Fortress Exterior near cave", "Fortress Courtyard, Fortress East_", set()), # ls at the ladder, need to gain a little height to get up the stairs + # excluded in non-ER due to soft lock potential ("Lower Mountain", "Mountain, Mountaintop_", set()), # Where the rope is behind Monastery. Connecting here since, if you have this region, you don't need a sword @@ -1139,6 +1151,12 @@ def get_portal_info(portal_sd: str) -> (str, str): rule=lambda state: has_stick(state, player) and has_ability(state, player, holy_cross, options, ability_unlocks) and has_ladder("Swamp Ladders", state, player, options)) + # soft lock potential + elif portal_name in ["Special Shop Entrance", "Stairs to Top of the Mountain"] and not options.entrance_rando: + continue + # soft lock if you don't have the ladder, just exclude it for simplicity + elif portal_name == "Temple Rafters Entrance" and not options.entrance_rando and options.shuffle_ladders: + continue # if no ladder items are required, just do the basic stick only lambda elif not ladders: regions[region_name].connect( From e50f835c1e71bfe1049c2eb04eb592bf7fabf65c Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 8 Mar 2024 11:43:01 -0500 Subject: [PATCH 42/82] Simplify LS rules slightly --- worlds/tunic/er_rules.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 00a9ef364379..f7ebb21da7c8 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1158,26 +1158,26 @@ def get_portal_info(portal_sd: str) -> (str, str): elif portal_name == "Temple Rafters Entrance" and not options.entrance_rando and options.shuffle_ladders: continue # if no ladder items are required, just do the basic stick only lambda - elif not ladders: + elif not ladders or not options.shuffle_ladders: regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player)) - # if one ladder is required, use has_ladder + # one ladder required elif len(ladders) == 1: ladder = ladders.pop() regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and has_ladder(ladder, state, player, options)) - # if multiple ladders can be used, use has_any_ladder + and state.has(ladder, player)) + # if multiple ladders can be used else: regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and has_any_ladder(ladders, state, player, options)) + and state.has_any(ladders, player)) def set_er_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> None: From 222a6e4ecf4dee51429ad2a7944ae96a8e8cba59 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 8 Mar 2024 11:45:35 -0500 Subject: [PATCH 43/82] Remove unused helper --- worlds/tunic/er_rules.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index f7ebb21da7c8..bb93643d7fd6 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -32,10 +32,6 @@ def has_ladder(ladder: str, state: CollectionState, player: int, options: TunicO return not options.shuffle_ladders or state.has(ladder, player) -def has_any_ladder(ladders: Set[str], state: CollectionState, player: int, options: TunicOptions): - return not options.shuffle_ladders or state.has_any(ladders, player) - - def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], regions: Dict[str, Region], portal_pairs: Dict[Portal, Portal]) -> None: player = world.player From 2316e7d01a8021a04f39d97d62c4cf6cbb66e460 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 8 Mar 2024 15:00:07 -0500 Subject: [PATCH 44/82] Updating comments --- worlds/tunic/__init__.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index 856d70242596..9832e0a170ea 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -121,12 +121,12 @@ def create_items(self) -> None: items_to_create[rgb_hexagon] = 0 items_to_create[gold_hexagon] -= 3 - # Filler items that are still in the item pool to swap out + # Filler items in the item pool available_filler: List[str] = [filler for filler in items_to_create if items_to_create[filler] > 0 and item_table[filler].classification == ItemClassification.filler] - + + # Remove filler to make room for other items def remove_filler(amount: int): - # Remove filler to make room for other items for _ in range(0, amount): if not available_filler: fill = "Fool Trap" @@ -166,8 +166,8 @@ def remove_filler(amount: int): items_to_create["Scavenger Mask"] = 0 if self.options.lanternless: - mask_item = TunicItem("Lantern", ItemClassification.useful, self.item_name_to_id["Lantern"], self.player) - tunic_items.append(mask_item) + lantern_item = TunicItem("Lantern", ItemClassification.useful, self.item_name_to_id["Lantern"], self.player) + tunic_items.append(lantern_item) items_to_create["Lantern"] = 0 for item, quantity in items_to_create.items(): @@ -191,14 +191,16 @@ def create_regions(self) -> None: self.ability_unlocks["Pages 24-25 (Prayer)"] = passthrough["Hexagon Quest Prayer"] self.ability_unlocks["Pages 42-43 (Holy Cross)"] = passthrough["Hexagon Quest Holy Cross"] self.ability_unlocks["Pages 52-53 (Icebolt)"] = passthrough["Hexagon Quest Icebolt"] - + + # ladder rando uses ER with vanilla connections, so that we're not managing more rules files if self.options.entrance_rando or self.options.shuffle_ladders: portal_pairs = create_er_regions(self) if self.options.entrance_rando: + # these get interpreted by the game to tell it which entrances to connect for portal1, portal2 in portal_pairs.items(): self.tunic_portal_pairs[portal1.scene_destination()] = portal2.scene_destination() - else: + # for non-ER, non-ladder region_list = tunic_regions for region_name in region_list: @@ -247,9 +249,10 @@ def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]): name, connection = paths[location.parent_region] while connection != ("Menu", None): name, connection = connection - # was getting some cases like Library Grave -> Library Grave -> other place + # for LS entrances, we just want to give the portal name if "(LS)" in name: name, _ = name.split(" (LS) ") + # was getting some cases like Library Grave -> Library Grave -> other place if name in portal_names and name != previous_name: previous_name = name path_to_loc.append(name) From 80239f8ab04a7e18cdfb6181206df07f0ff45a6d Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 8 Mar 2024 19:00:45 -0500 Subject: [PATCH 45/82] Some pep8ing --- worlds/tunic/er_rules.py | 10 ++++++---- worlds/tunic/er_scripts.py | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index bb93643d7fd6..836798e26d28 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -732,7 +732,8 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # nmg: use ice grapple to get from the beginning of Quarry to the door without really needing mask only with ER on regions["Quarry"].connect( connecting_region=regions["Lower Quarry Zig Door"], - rule=lambda state: has_ice_grapple_logic(True, state, player, options, ability_unlocks) and options.entrance_rando) + rule=lambda state: has_ice_grapple_logic(True, state, player, options, ability_unlocks) + and options.entrance_rando) regions["Monastery Front"].connect( connecting_region=regions["Monastery Back"]) @@ -1072,7 +1073,7 @@ def get_portal_info(portal_sd: str) -> (str, str): ("Furnace Ladder Area", "Furnace, Overworld Redux_gyro_west", set()), # West Garden - # West Garden exit after Garden Knight + # exit after Garden Knight ("West Garden", "Archipelagos Redux, Overworld Redux_upper", set()), # West Garden laurels exit ("West Garden", "Archipelagos Redux, Overworld Redux_lowest", set()), @@ -1093,7 +1094,7 @@ def get_portal_info(portal_sd: str) -> (str, str): ("Forest Grave Path Main", "Sword Access, East Forest Redux_upper", set()), # Fortress Exterior - # Fortress Exterior shop, ls at the ladder by the telescope + # shop, ls at the ladder by the telescope ("Fortress Exterior from Overworld", "Fortress Courtyard, Shop_", set()), # Fortress main entry and grave path lower entry, ls at the ladder by the telescope ("Fortress Exterior from Overworld", "Fortress Courtyard, Fortress Main_Big Door", set()), @@ -1148,7 +1149,8 @@ def get_portal_info(portal_sd: str) -> (str, str): and has_ability(state, player, holy_cross, options, ability_unlocks) and has_ladder("Swamp Ladders", state, player, options)) # soft lock potential - elif portal_name in ["Special Shop Entrance", "Stairs to Top of the Mountain"] and not options.entrance_rando: + elif portal_name in ["Special Shop Entrance", "Stairs to Top of the Mountain"] \ + and not options.entrance_rando: continue # soft lock if you don't have the ladder, just exclude it for simplicity elif portal_name == "Temple Rafters Entrance" and not options.entrance_rando and options.shuffle_ladders: diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 63a2d58a2327..3307cbafb3a5 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -292,7 +292,8 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: break if portal1 is None: raise Exception("Too many shops in the pool, or something else went wrong") - portal2 = Portal(name=f"Shop Portal {i + 1}", region=f"Shop Entrance {i + 1}", destination="Previous Region", tag="_") + portal2 = Portal(name=f"Shop Portal {i + 1}", region=f"Shop Entrance {i + 1}", + destination="Previous Region", tag="_") portal_pairs[portal1] = portal2 # connect dead ends to random non-dead ends @@ -392,7 +393,8 @@ def gate_before_switch(check_portal: Portal, two_plus: List[Portal]) -> bool: 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"]: + if portal.region in ["Swamp Front", "Swamp to Cathedral Treasure Room", + "Swamp to Cathedral Main Entrance Region"]: i += 1 if i == 4: return True @@ -488,7 +490,8 @@ def create_plando_connections(plando_connections: List[PlandoConnection], portal2 = portal break if p_exit == "Shop Portal": - portal2 = Portal(name="Shop Portal", region=f"Shop Entrance {shop_num}", destination="Previous Region", tag="_") + portal2 = Portal(name="Shop Portal", region=f"Shop Entrance {shop_num}", + destination="Previous Region", tag="_") shop_num += 1 else: dead_ends.remove(portal2) From 97f3d118777f19b375f63b294063bf42472cc837 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 8 Mar 2024 20:20:15 -0500 Subject: [PATCH 46/82] Clear todo after doing the todo thing --- worlds/tunic/er_rules.py | 1 - 1 file changed, 1 deletion(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 836798e26d28..ce0f10a588fa 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -994,7 +994,6 @@ def get_portal_info(portal_sd: str) -> (str, str): # Rotating Lights entrance ("Overworld Beach", "Overworld Redux, Overworld Cave_", {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), - # todo: verify the ones below from the atoll ladder, see if there's any missing # Swamp upper entrance ("Overworld Beach", "Overworld Redux, Swamp Redux 2_wall", {"Ladder to Ruined Atoll"}), From b863b45e89bdceae7d0145d879af4ef6f6154e1c Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 9 Mar 2024 08:40:32 -0500 Subject: [PATCH 47/82] Add missed grapple connection from main Overworld to the beach --- worlds/tunic/er_rules.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index ce0f10a588fa..c543d26c6559 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -45,12 +45,15 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld Holy Cross"], rule=lambda state: has_ability(state, player, holy_cross, options, ability_unlocks)) + # grapple on the west side, down the stairs from moss wall, across from ruined shop regions["Overworld"].connect( connecting_region=regions["Overworld Beach"], - rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) or state.has(laurels, player)) + rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) + or state.has_any({laurels, grapple}, player)) regions["Overworld Beach"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) or state.has(laurels, player)) + rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) + or state.has_any({laurels, grapple}, player)) regions["Overworld Beach"].connect( connecting_region=regions["Overworld West Garden Laurels Entry"], From 0c5da9de259b9b5e7873106136dbf29d7b84c3db Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 9 Mar 2024 13:13:58 -0500 Subject: [PATCH 48/82] Fix rules for the chest beneath the quarry gate --- worlds/tunic/er_data.py | 16 ++++++++++------ worlds/tunic/er_rules.py | 22 +++++++++++++++++----- worlds/tunic/locations.py | 2 +- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index de620e08b9aa..cd7558af5ecb 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -541,6 +541,7 @@ class DeadEnd(IntEnum): "Overworld above Quarry Entrance": RegionInfo("Overworld Redux"), # top of the ladder where the chest is "Overworld after Temple Rafters": RegionInfo("Overworld Redux"), # the ledge after the rafter exit, before ladder "Overworld Quarry Entry": RegionInfo("Overworld Redux"), # at the top of the ladder to darkwoods + "Overworld after Envoy": RegionInfo("Overworld Redux"), # after the envoy on the bridge to quarry "Overworld above Patrol Cave": RegionInfo("Overworld Redux"), # where the hook is, and one ladder up from patrol "Overworld at Patrol Cave": RegionInfo("Overworld Redux"), # right at the patrol cave entrance "Overworld West Garden Laurels Entry": RegionInfo("Overworld Redux"), # west garden laurels entry @@ -731,7 +732,7 @@ class DeadEnd(IntEnum): "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 to Atoll Upper", "Overworld above Quarry Entrance", "Overworld after Envoy"): ["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", @@ -739,7 +740,8 @@ class DeadEnd(IntEnum): "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 to Atoll Upper", "Overworld Temple Door", "Overworld above Quarry Entrance", + "Overworld after Envoy"], ("Hourglass Cave",): ["Hourglass Cave", "Hourglass Cave Tower"], ("Old House Front",): @@ -843,7 +845,8 @@ class DeadEnd(IntEnum): "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 Well Ladder", "Overworld Beach", "Overworld to Atoll Upper", "Overworld above Quarry Entrance", + "Overworld after Envoy"): ["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", @@ -851,7 +854,7 @@ class DeadEnd(IntEnum): "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 to Atoll Upper", "Overworld above Quarry Entrance", "Overworld after Envoy"], # can laurels through the gate ("Old House Front", "Old House Back"): ["Old House Front", "Old House Back"], @@ -957,7 +960,8 @@ class DeadEnd(IntEnum): "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 Well Ladder", "Overworld Beach", "Overworld to Atoll Upper", "Overworld above Quarry Entrance", + "Overworld after Envoy"): ["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", @@ -965,7 +969,7 @@ class DeadEnd(IntEnum): "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 above Quarry Entrance", "Overworld after Envoy"], # can laurels through the gate ("Old House Front", "Old House Back"): ["Old House Front", "Old House Back"], diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index c543d26c6559..8c3999da8213 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -218,14 +218,26 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re rule=lambda state: has_ladder("Ladders near Dark Tomb", state, player, options)) regions["Overworld"].connect( + connecting_region=regions["Overworld after Envoy"], + rule=lambda state: state.has_any({laurels, grapple}, player) or options.logic_rules) + regions["Overworld after Envoy"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: state.has_any({laurels, grapple}, player) or options.logic_rules) + + regions["Overworld after Envoy"].connect( connecting_region=regions["Overworld Quarry Entry"], - rule=lambda state: (has_ladder("Ladder to Quarry", state, player, options) - and state.has_any({laurels, grapple}, player)) - or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) + rule=lambda state: has_ladder("Ladder to Quarry", state, player, options)) + regions["Overworld Quarry Entry"].connect( + connecting_region=regions["Overworld after Envoy"], + rule=lambda state: has_ladder("Ladder to Quarry", state, player, options)) + + # ice grapple through the gate + regions["Overworld"].connect( + connecting_region=regions["Overworld Quarry Entry"], + rule=lambda state: has_ice_grapple_logic(False, state, player, options, ability_unlocks)) regions["Overworld Quarry Entry"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladder to Quarry", state, player, options) and state.has(laurels, player) - or state.has(grapple, player)) + rule=lambda state: has_ice_grapple_logic(False, state, player, options, ability_unlocks)) regions["Overworld"].connect( connecting_region=regions["Overworld Swamp Upper Entry"], diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index 23550de82744..dc34728fac26 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -133,7 +133,7 @@ class TunicLocationData(NamedTuple): "Overworld - [Northwest] Shadowy Corner Chest": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Obscured In Tunnel To Beach": TunicLocationData("Overworld", "Overworld"), "Overworld - [Southwest] Grapple Chest Over Walkway": TunicLocationData("Overworld", "Overworld"), - "Overworld - [Northwest] Chest Beneath Quarry Gate": TunicLocationData("Overworld", "Overworld"), + "Overworld - [Northwest] Chest Beneath Quarry Gate": TunicLocationData("Overworld", "Overworld after Envoy"), "Overworld - [Southeast] Chest Near Swamp": TunicLocationData("Overworld", "Overworld Swamp Lower Entry"), "Overworld - [Southwest] From West Garden": TunicLocationData("Overworld", "Overworld Beach"), "Overworld - [East] Grapple Chest": TunicLocationData("Overworld", "Overworld above Patrol Cave"), From a63bbb4a6ce8647ac450ceb69f5096d4892686d7 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 9 Mar 2024 15:40:54 -0500 Subject: [PATCH 49/82] Several unrestricted logic fixes (how many more until I remove the option altogether) --- worlds/tunic/er_rules.py | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 8c3999da8213..f0a072826c48 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1161,7 +1161,37 @@ def get_portal_info(portal_sd: str) -> (str, str): name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and has_ability(state, player, holy_cross, options, ability_unlocks) - and has_ladder("Swamp Ladders", state, player, options)) + and (has_ladder("Swamp Ladders", state, player, options) or not options.entrance_rando)) + elif portal_name == "West Garden Exit after Boss" and not options.entrance_rando: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and (state.has_any({"Ladders to West Bell", "Dark Tomb Ladder"}, player))) + # soft locked unless you have either ladder. if you have laurels, you use the other Entrance + elif portal_name in ["Furnace Exit towards West Garden", "Furnace Exit to Dark Tomb"] \ + and not options.entrance_rando: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and state.has_any({"Dark Tomb Ladder", "Ladders to West Bell"}, player)) + # soft locked for the same reasons as above + elif portal_name in ["Entrance to Furnace near West Garden", "West Garden Entrance from Furnace"] \ + and not options.entrance_rando: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and state.has_any(ladders, player) + and state.has_any({"Dark Tomb Ladder", "Ladders to West Bell"}, player)) + # soft locked if you can't get past garden knight backwards or up the belltower ladders + elif portal_name == "West Garden Entrance near Belltower" and not options.entrance_rando: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) and state.has_any(ladders, player) + and state.has_any({"Ladders to West Bell", laurels}, player)) # soft lock potential elif portal_name in ["Special Shop Entrance", "Stairs to Top of the Mountain"] \ and not options.entrance_rando: From c5f84d072edeff61d95e574eb6b9133bf5af06ac Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 11:28:58 -0400 Subject: [PATCH 50/82] Add atoll to overworld lower LS --- worlds/tunic/er_rules.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index f0a072826c48..199330377436 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1092,7 +1092,8 @@ def get_portal_info(portal_sd: str) -> (str, str): # West Garden laurels exit ("West Garden", "Archipelagos Redux, Overworld Redux_lowest", set()), - # Atoll to Frog Stairs, use the little ladder you fix at the start + # Atoll, use the little ladder you fix at the beginning + ("Ruined Atoll", "Atoll Redux, Overworld Redux_lower", set()), ("Ruined Atoll", "Atoll Redux, Frog Stairs_mouth", set()), ("Ruined Atoll", "Atoll Redux, Frog Stairs_eye", set()), From b5d6715a13afd745facb9bfa7677660897ff2e83 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 14:30:59 -0400 Subject: [PATCH 51/82] Remove data version, since it is not necessary and will be removed eventually --- worlds/tunic/__init__.py | 1 - 1 file changed, 1 deletion(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index 9832e0a170ea..9621f9a8360b 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -45,7 +45,6 @@ class TunicWorld(World): game = "TUNIC" web = TunicWeb() - data_version = 2 options: TunicOptions options_dataclass = TunicOptions item_name_groups = item_name_groups From 40f6e94c9bdb0e6eff52d33c3493ef9f32080841 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 18:31:09 -0400 Subject: [PATCH 52/82] Add new region to deal with logic bug with ladders and ER together --- worlds/tunic/er_data.py | 3 ++- worlds/tunic/er_rules.py | 17 +++++++++++++++++ worlds/tunic/locations.py | 5 +++-- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index cd7558af5ecb..56f1f0cfff8b 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -37,7 +37,7 @@ def destination_scene(self) -> str: # the vanilla connection destination="Furnace", tag="_gyro_upper_east"), Portal(name="Entrance to Furnace near West Garden", region="Overworld to West Garden from Furnace", destination="Furnace", tag="_gyro_west"), - Portal(name="Entrance to Furnace from Beach", region="Overworld", + Portal(name="Entrance to Furnace from Beach", region="Overworld Tunnel Turret", destination="Furnace", tag="_gyro_lower"), Portal(name="Caustic Light Cave Entrance", region="Overworld Swamp Lower Entry", destination="Overworld Cave", tag="_"), @@ -558,6 +558,7 @@ class DeadEnd(IntEnum): "Overworld Temple Door": RegionInfo("Overworld Redux"), # the small space betweeen the door and the portal "Overworld Town Portal": RegionInfo("Overworld Redux"), "Overworld Spawn Portal": RegionInfo("Overworld Redux"), + "Overworld Tunnel Turret": RegionInfo("Overworld Redux"), # the tunnel turret by the southwest beach ladder "Stick House": RegionInfo("Sword Cave", dead_end=DeadEnd.all_cats), "Windmill": RegionInfo("Windmill"), "Old House Back": RegionInfo("Overworld Interiors"), # part with the hc door diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 199330377436..d184f3d5881e 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -309,6 +309,23 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld above Patrol Cave"], rule=lambda state: state.has(grapple, player)) + regions["Overworld Tunnel Turret"].connect( + connecting_region=regions["Overworld Beach"], + rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) + or state.has(grapple, player)) + regions["Overworld Beach"].connect( + connecting_region=regions["Overworld Tunnel Turret"], + rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + + regions["Overworld"].connect( + connecting_region=regions["Overworld Tunnel Turret"], + rule=lambda state: state.has(laurels, player) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + regions["Overworld Tunnel Turret"].connect( + connecting_region=regions["Overworld"], + rule=lambda state: state.has_any({grapple, laurels}, player)) + # Overworld side areas regions["Old House Front"].connect( connecting_region=regions["Old House Back"]) diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index dc34728fac26..ff948286f77b 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -1,10 +1,11 @@ -from typing import Dict, NamedTuple, Set, Optional +from typing import Dict, NamedTuple, Set, Optional, List class TunicLocationData(NamedTuple): region: str er_region: str # entrance rando region location_group: Optional[str] = None + location_groups: Optional[List[str]] = None location_base_id = 509342400 @@ -141,7 +142,7 @@ class TunicLocationData(NamedTuple): "Overworld - [Southwest] Beach Chest Near Flowers": TunicLocationData("Overworld", "Overworld Beach"), "Overworld - [Southwest] Bombable Wall Near Fountain": TunicLocationData("Overworld", "Overworld"), "Overworld - [West] Chest After Bell": TunicLocationData("Overworld", "Overworld Belltower"), - "Overworld - [Southwest] Tunnel Guarded By Turret": TunicLocationData("Overworld", "Overworld"), + "Overworld - [Southwest] Tunnel Guarded By Turret": TunicLocationData("Overworld", "Overworld Tunnel Turret"), "Overworld - [East] Between Ladders Near Ruined Passage": TunicLocationData("Overworld", "After Ruined Passage"), "Overworld - [Northeast] Chest Above Patrol Cave": TunicLocationData("Overworld", "Upper Overworld"), "Overworld - [Southwest] Beach Chest Beneath Guard": TunicLocationData("Overworld", "Overworld Beach"), From 9e32d9e4a4e2e5084bfaa921cc90a680684f5e7e Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 18:55:39 -0400 Subject: [PATCH 53/82] Rename ladder items to more consistent names --- worlds/tunic/er_rules.py | 238 +++++++++++++++++++-------------------- worlds/tunic/items.py | 42 +++---- 2 files changed, 140 insertions(+), 140 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index d184f3d5881e..bf19adef8995 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -48,11 +48,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # grapple on the west side, down the stairs from moss wall, across from ruined shop regions["Overworld"].connect( connecting_region=regions["Overworld Beach"], - rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Overworld Town", state, player, options) or state.has_any({laurels, grapple}, player)) regions["Overworld Beach"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Overworld Town", state, player, options) or state.has_any({laurels, grapple}, player)) regions["Overworld Beach"].connect( @@ -64,10 +64,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld Beach"].connect( connecting_region=regions["Overworld to Atoll Upper"], - rule=lambda state: has_ladder("Ladder to Ruined Atoll", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Ruined Atoll", state, player, options)) regions["Overworld to Atoll Upper"].connect( connecting_region=regions["Overworld Beach"], - rule=lambda state: has_ladder("Ladder to Ruined Atoll", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Ruined Atoll", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld to Atoll Upper"], @@ -84,14 +84,14 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld Belltower"].connect( connecting_region=regions["Overworld to West Garden Upper"], - rule=lambda state: has_ladder("Ladders to West Bell", state, player, options)) + rule=lambda state: has_ladder("Ladders - To West Bell", state, player, options)) regions["Overworld to West Garden Upper"].connect( connecting_region=regions["Overworld Belltower"], - rule=lambda state: has_ladder("Ladders to West Bell", state, player, options)) + rule=lambda state: has_ladder("Ladders - To West Bell", state, player, options)) regions["Overworld Belltower"].connect( connecting_region=regions["Overworld Belltower at Bell"], - rule=lambda state: has_ladder("Ladders to West Bell", state, player, options)) + rule=lambda state: has_ladder("Ladders - To West Bell", state, player, options)) # long dong, do not make a reverse connection here or to belltower regions["Overworld above Patrol Cave"].connect( @@ -109,35 +109,35 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["After Ruined Passage"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["After Ruined Passage"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) + rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Above Ruined Passage"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) or state.has(laurels, player)) regions["Above Ruined Passage"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) or state.has(laurels, player)) regions["After Ruined Passage"].connect( connecting_region=regions["Above Ruined Passage"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) + rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options)) regions["Above Ruined Passage"].connect( connecting_region=regions["After Ruined Passage"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) + rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options)) regions["Above Ruined Passage"].connect( connecting_region=regions["East Overworld"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["East Overworld"].connect( connecting_region=regions["Above Ruined Passage"], - rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) or state.has(laurels, player)) # nmg: ice grapple the slimes, works both ways consistently @@ -150,11 +150,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["East Overworld"], - rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["East Overworld"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options)) + rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options)) regions["East Overworld"].connect( connecting_region=regions["Overworld at Patrol Cave"]) @@ -164,35 +164,35 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld at Patrol Cave"].connect( connecting_region=regions["Overworld above Patrol Cave"], - rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options) + rule=lambda state: has_ladder("Ladders - Near Patrol Cave", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Overworld above Patrol Cave"].connect( connecting_region=regions["Overworld at Patrol Cave"], - rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options)) + rule=lambda state: has_ladder("Ladders - Near Patrol Cave", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld above Patrol Cave"], - rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options) or state.has(grapple, player)) regions["Overworld above Patrol Cave"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options)) + rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options)) regions["East Overworld"].connect( connecting_region=regions["Overworld above Patrol Cave"], - rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Overworld above Patrol Cave"].connect( connecting_region=regions["East Overworld"], - rule=lambda state: has_ladder("Overworld Shortcut Ladders", state, player, options)) + rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options)) regions["Overworld above Patrol Cave"].connect( connecting_region=regions["Upper Overworld"], - rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options) + rule=lambda state: has_ladder("Ladders - Near Patrol Cave", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Upper Overworld"].connect( connecting_region=regions["Overworld above Patrol Cave"], - rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options) + rule=lambda state: has_ladder("Ladders - Near Patrol Cave", state, player, options) or state.has(grapple, player)) regions["Upper Overworld"].connect( @@ -204,18 +204,18 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Upper Overworld"].connect( connecting_region=regions["Overworld after Temple Rafters"], - rule=lambda state: has_ladder("Ladder near Temple Rafters", state, player, options)) + rule=lambda state: has_ladder("Ladder - Near Temple Rafters", state, player, options)) regions["Overworld after Temple Rafters"].connect( connecting_region=regions["Upper Overworld"], - rule=lambda state: has_ladder("Ladder near Temple Rafters", state, player, options) + rule=lambda state: has_ladder("Ladder - Near Temple Rafters", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Overworld above Quarry Entrance"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladders near Dark Tomb", state, player, options)) + rule=lambda state: has_ladder("Ladders - Near Dark Tomb", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld above Quarry Entrance"], - rule=lambda state: has_ladder("Ladders near Dark Tomb", state, player, options)) + rule=lambda state: has_ladder("Ladders - Near Dark Tomb", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld after Envoy"], @@ -226,10 +226,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld after Envoy"].connect( connecting_region=regions["Overworld Quarry Entry"], - rule=lambda state: has_ladder("Ladder to Quarry", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Quarry", state, player, options)) regions["Overworld Quarry Entry"].connect( connecting_region=regions["Overworld after Envoy"], - rule=lambda state: has_ladder("Ladder to Quarry", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Quarry", state, player, options)) # ice grapple through the gate regions["Overworld"].connect( @@ -248,10 +248,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["Overworld Swamp Lower Entry"], - rule=lambda state: has_ladder("Ladder to Swamp", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Swamp", state, player, options)) regions["Overworld Swamp Lower Entry"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladder to Swamp", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Swamp", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld Special Shop Entry"], @@ -262,7 +262,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["Overworld Well Ladder"], - rule=lambda state: has_ladder("Ladder to Well", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Well", state, player, options)) regions["Overworld Well Ladder"].connect( connecting_region=regions["Overworld"]) @@ -311,11 +311,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld Tunnel Turret"].connect( connecting_region=regions["Overworld Beach"], - rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Overworld Town", state, player, options) or state.has(grapple, player)) regions["Overworld Beach"].connect( connecting_region=regions["Overworld Tunnel Turret"], - rule=lambda state: has_ladder("Overworld Town Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Overworld Town", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Overworld"].connect( @@ -363,7 +363,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Hourglass Cave"].connect( connecting_region=regions["Hourglass Cave Tower"], - rule=lambda state: has_ladder("Hourglass Cave Ladders", state, player, options)) + rule=lambda state: has_ladder("Ladders - Hourglass Cave", state, player, options)) # East Forest regions["Forest Belltower Upper"].connect( @@ -371,7 +371,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Forest Belltower Main"].connect( connecting_region=regions["Forest Belltower Lower"], - rule=lambda state: has_ladder("Ladder Drop to East Forest", state, player, options)) + rule=lambda state: has_ladder("Ladder - Drop to East Forest", state, player, options)) # nmg: ice grapple up to dance fox spot, and vice versa regions["East Forest"].connect( @@ -391,12 +391,12 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["East Forest"].connect( connecting_region=regions["Lower Forest"], - rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options) + rule=lambda state: has_ladder("Ladders - To Lower Forest", state, player, options) or (state.has_all({grapple, fire_wand, ice_dagger}, player) # do ice slime, then go to the lower hook and has_ability(state, player, icebolt, options, ability_unlocks))) regions["Lower Forest"].connect( connecting_region=regions["East Forest"], - rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Lower Forest", state, player, options)) regions["Guard House 1 East"].connect( connecting_region=regions["Guard House 1 West"]) @@ -406,10 +406,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Guard House 2 Upper"].connect( connecting_region=regions["Guard House 2 Lower"], - rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Lower Forest", state, player, options)) regions["Guard House 2 Lower"].connect( connecting_region=regions["Guard House 2 Upper"], - rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Lower Forest", state, player, options)) # nmg: ice grapple from upper grave path exit to the rest of it regions["Forest Grave Path Upper"].connect( @@ -438,10 +438,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # don't need the ladder when entering at the ladder spot regions["Beneath the Well Ladder Exit"].connect( connecting_region=regions["Beneath the Well Front"], - rule=lambda state: has_ladder("Ladder to Well", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Well", state, player, options)) regions["Beneath the Well Front"].connect( connecting_region=regions["Beneath the Well Ladder Exit"], - rule=lambda state: has_ladder("Ladder to Well", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Well", state, player, options)) regions["Beneath the Well Front"].connect( connecting_region=regions["Beneath the Well Main"], @@ -452,10 +452,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Beneath the Well Main"].connect( connecting_region=regions["Beneath the Well Back"], - rule=lambda state: has_ladder("Well Back Ladder", state, player, options)) + rule=lambda state: has_ladder("Ladder - Back of Well", state, player, options)) regions["Beneath the Well Back"].connect( connecting_region=regions["Beneath the Well Main"], - rule=lambda state: has_ladder("Well Back Ladder", state, player, options) + rule=lambda state: has_ladder("Ladder - Back of Well", state, player, options) and (has_stick(state, player) or state.has(fire_wand, player))) regions["Well Boss"].connect( @@ -473,10 +473,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Dark Tomb Upper"].connect( connecting_region=regions["Dark Tomb Main"], - rule=lambda state: has_ladder("Dark Tomb Ladder", state, player, options)) + rule=lambda state: has_ladder("Ladder - Dark Tomb under Casket", state, player, options)) regions["Dark Tomb Main"].connect( connecting_region=regions["Dark Tomb Upper"], - rule=lambda state: has_ladder("Dark Tomb Ladder", state, player, options)) + rule=lambda state: has_ladder("Ladder - Dark Tomb under Casket", state, player, options)) regions["Dark Tomb Main"].connect( connecting_region=regions["Dark Tomb Dark Exit"]) @@ -532,7 +532,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Ladder Tops"], - rule=lambda state: has_ladder("South Atoll Ladders", state, player, options)) + rule=lambda state: has_ladder("Ladders - South Atoll", state, player, options)) regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Frog Mouth"], @@ -543,10 +543,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Frog Eye"], - rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) regions["Ruined Atoll Frog Eye"].connect( connecting_region=regions["Ruined Atoll"], - rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Portal"], @@ -557,30 +557,30 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Statue"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) - and has_ladder("South Atoll Ladders", state, player, options)) + and has_ladder("Ladders - South Atoll", state, player, options)) regions["Ruined Atoll Statue"].connect( connecting_region=regions["Ruined Atoll"]) regions["Frog Stairs Eye Exit"].connect( connecting_region=regions["Frog Stairs Upper"], - rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) regions["Frog Stairs Upper"].connect( connecting_region=regions["Frog Stairs Eye Exit"], - rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) regions["Frog Stairs Upper"].connect( connecting_region=regions["Frog Stairs Lower"], - rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) regions["Frog Stairs Lower"].connect( connecting_region=regions["Frog Stairs Upper"], - rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) regions["Frog Stairs Lower"].connect( connecting_region=regions["Frog Stairs to Frog's Domain"], - rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) regions["Frog Stairs to Frog's Domain"].connect( connecting_region=regions["Frog Stairs Lower"], - rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) regions["Frog's Domain"].connect( connecting_region=regions["Frog's Domain Back"], @@ -631,10 +631,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Fortress Exterior near cave"].connect( connecting_region=regions["Beneath the Vault Entry"], - rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Beneath the Vault", state, player, options)) regions["Beneath the Vault Entry"].connect( connecting_region=regions["Fortress Exterior near cave"], - rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options)) + rule=lambda state: has_ladder("Ladder - To Beneath the Vault", state, player, options)) regions["Fortress Courtyard"].connect( connecting_region=regions["Fortress Exterior from Overworld"], @@ -657,10 +657,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re 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)) + 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 Ladder Exit"], - rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options)) + 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"], @@ -824,12 +824,12 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # Swamp and Cathedral regions["Swamp Front"].connect( connecting_region=regions["Swamp Mid"], - rule=lambda state: has_ladder("Swamp Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Swamp", state, player, options) or state.has(laurels, player) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) # nmg: ice grapple through gate regions["Swamp Mid"].connect( connecting_region=regions["Swamp Front"], - rule=lambda state: has_ladder("Swamp Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Swamp", state, player, options) or state.has(laurels, player) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) # nmg: ice grapple through gate @@ -845,10 +845,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Swamp Mid"].connect( connecting_region=regions["Swamp Ledge under Cathedral Door"], - rule=lambda state: has_ladder("Swamp Ladders", state, player, options)) + rule=lambda state: has_ladder("Ladders - Swamp", state, player, options)) regions["Swamp Ledge under Cathedral Door"].connect( connecting_region=regions["Swamp Mid"], - rule=lambda state: has_ladder("Swamp Ladders", state, player, options) + rule=lambda state: has_ladder("Ladders - Swamp", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) # nmg: ice grapple the enemy at door regions["Swamp Ledge under Cathedral Door"].connect( @@ -964,136 +964,136 @@ def get_portal_info(portal_sd: str) -> (str, str): # LS from Overworld main # The upper Swamp entrance ("Overworld", "Overworld Redux, Swamp Redux 2_wall", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), # Upper atoll entrance ("Overworld", "Overworld Redux, Atoll Redux_upper", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), # Furnace entrance, next to the sign that leads to West Garden ("Overworld", "Overworld Redux, Furnace_gyro_west", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), # Upper West Garden entry, by the belltower ("Overworld", "Overworld Redux, Archipelagos Redux_upper", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), # Ruined Passage ("Overworld", "Overworld Redux, Ruins Passage_east", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), # Well rail, west side. Can ls in town, get extra height by going over the portal pad ("Overworld", "Overworld Redux, Sewer_west_aqueduct", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Quarry"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Quarry"}), # Well rail, east side. Need some height from the temple stairs ("Overworld", "Overworld Redux, Furnace_gyro_upper_north", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Quarry"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Quarry"}), # Quarry entry ("Overworld", "Overworld Redux, Darkwoods Tunnel_", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well"}), # East Forest entry ("Overworld", "Overworld Redux, Forest Belltower_", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", - "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", + "Ladders - Near Patrol Cave", "Ladder - To Quarry", "Ladders - Near Dark Tomb"}), # Fortress entry ("Overworld", "Overworld Redux, Fortress Courtyard_", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", - "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", + "Ladders - Near Patrol Cave", "Ladder - To Quarry", "Ladders - Near Dark Tomb"}), # Patrol Cave entry ("Overworld", "Overworld Redux, PatrolCave_", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", - "Overworld Shortcut Ladders", "Ladder to Quarry", "Ladders near Dark Tomb"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", + "Ladders - Overworld Shortcut", "Ladder - To Quarry", "Ladders - Near Dark Tomb"}), # Special Shop entry, excluded in non-ER due to soft lock potential ("Overworld", "Overworld Redux, ShopSpecial_", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", - "Overworld Shortcut Ladders", "Ladders near Patrol Cave", "Ladder to Quarry", - "Ladders near Dark Tomb"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", + "Ladders - Overworld Shortcut", "Ladders - Near Patrol Cave", "Ladder - To Quarry", + "Ladders - Near Dark Tomb"}), # Temple Rafters, excluded in non-ER + ladder rando due to soft lock potential ("Overworld", "Overworld Redux, Temple_rafters", - {"Ladders near Weathervane", "Ladder to Swamp", "Overworld Town Ladders", "Ladder to Well", - "Overworld Shortcut Ladders", "Ladders near Patrol Cave", "Ladder to Quarry", - "Ladders near Dark Tomb"}), + {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", + "Ladders - Overworld Shortcut", "Ladders - Near Patrol Cave", "Ladder - To Quarry", + "Ladders - Near Dark Tomb"}), # Spot above the Quarry entrance, # only gets you to the mountain stairs ("Overworld above Quarry Entrance", "Overworld Redux, Mountain_", - {"Ladders near Dark Tomb"}), + {"Ladders - Near Dark Tomb"}), # LS from the Overworld Beach # West Garden entry by the Furnace ("Overworld Beach", "Overworld Redux, Archipelagos Redux_lower", - {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), + {"Ladders - Overworld Town", "Ladder - To Ruined Atoll"}), # West Garden laurels entry ("Overworld Beach", "Overworld Redux, Archipelagos Redux_lowest", - {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), + {"Ladders - Overworld Town", "Ladder - To Ruined Atoll"}), # Swamp lower entrance ("Overworld Beach", "Overworld Redux, Swamp Redux 2_conduit", - {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), + {"Ladders - Overworld Town", "Ladder - To Ruined Atoll"}), # Rotating Lights entrance ("Overworld Beach", "Overworld Redux, Overworld Cave_", - {"Overworld Town Ladders", "Ladder to Ruined Atoll"}), + {"Ladders - Overworld Town", "Ladder - To Ruined Atoll"}), # Swamp upper entrance ("Overworld Beach", "Overworld Redux, Swamp Redux 2_wall", - {"Ladder to Ruined Atoll"}), + {"Ladder - To Ruined Atoll"}), # Furnace entrance, next to the sign that leads to West Garden ("Overworld Beach", "Overworld Redux, Furnace_gyro_west", - {"Ladder to Ruined Atoll"}), + {"Ladder - To Ruined Atoll"}), # Upper West Garden entry, by the belltower ("Overworld Beach", "Overworld Redux, Archipelagos Redux_upper", - {"Ladder to Ruined Atoll"}), + {"Ladder - To Ruined Atoll"}), # Ruined Passage ("Overworld Beach", "Overworld Redux, Ruins Passage_east", - {"Ladder to Ruined Atoll"}), + {"Ladder - To Ruined Atoll"}), # Well rail, west side. Can ls in town, get extra height by going over the portal pad ("Overworld Beach", "Overworld Redux, Sewer_west_aqueduct", - {"Ladder to Ruined Atoll"}), + {"Ladder - To Ruined Atoll"}), # Well rail, east side. Need some height from the temple stairs ("Overworld Beach", "Overworld Redux, Furnace_gyro_upper_north", - {"Ladder to Ruined Atoll"}), + {"Ladder - To Ruined Atoll"}), # Quarry entry ("Overworld Beach", "Overworld Redux, Darkwoods Tunnel_", - {"Ladder to Ruined Atoll"}), + {"Ladder - To Ruined Atoll"}), # LS from that low spot where you normally walk to swamp # Only has low ones you can't get to from main Overworld # West Garden main entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Archipelagos Redux_lower", - {"Ladder to Swamp"}), + {"Ladder - To Swamp"}), # Maze Cave entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Maze Room_", - {"Ladder to Swamp"}), + {"Ladder - To Swamp"}), # Hourglass Cave entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Town Basement_beach", - {"Ladder to Swamp"}), + {"Ladder - To Swamp"}), # Lower Atoll entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Atoll Redux_lower", - {"Ladder to Swamp"}), + {"Ladder - To Swamp"}), # Lowest West Garden entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Archipelagos Redux_lowest", - {"Ladder to Swamp"}), + {"Ladder - To Swamp"}), # from the ladders by the belltower # Ruined Passage ("Overworld to West Garden Upper", "Overworld Redux, Ruins Passage_east", - {"Ladders to West Bell"}), + {"Ladders - To West Bell"}), # Well rail, west side. Can ls in town, get extra height by going over the portal pad ("Overworld to West Garden Upper", "Overworld Redux, Sewer_west_aqueduct", - {"Ladders to West Bell"}), + {"Ladders - To West Bell"}), # Well rail, east side. Need some height from the temple stairs ("Overworld to West Garden Upper", "Overworld Redux, Furnace_gyro_upper_north", - {"Ladders to West Bell"}), + {"Ladders - To West Bell"}), # Quarry entry ("Overworld to West Garden Upper", "Overworld Redux, Darkwoods Tunnel_", - {"Ladders to West Bell"}), + {"Ladders - To West Bell"}), # East Forest entry ("Overworld to West Garden Upper", "Overworld Redux, Forest Belltower_", - {"Ladders to West Bell"}), + {"Ladders - To West Bell"}), # Fortress entry ("Overworld to West Garden Upper", "Overworld Redux, Fortress Courtyard_", - {"Ladders to West Bell"}), + {"Ladders - To West Bell"}), # Patrol Cave entry ("Overworld to West Garden Upper", "Overworld Redux, PatrolCave_", - {"Ladders to West Bell"}), + {"Ladders - To West Bell"}), # Special Shop entry, excluded in non-ER due to soft lock potential ("Overworld to West Garden Upper", "Overworld Redux, ShopSpecial_", - {"Ladders to West Bell"}), + {"Ladders - To West Bell"}), # Temple Rafters, excluded in non-ER and ladder rando due to soft lock potential ("Overworld to West Garden Upper", "Overworld Redux, Temple_rafters", - {"Ladders to West Bell"}), + {"Ladders - To West Bell"}), # In the furnace # Furnace ladder to the fuse entrance @@ -1159,10 +1159,10 @@ def get_portal_info(portal_sd: str) -> (str, str): # Swamp to Gauntlet ("Swamp Mid", "Swamp Redux 2, Cathedral Arena_", - {"Swamp Ladders"}), + {"Ladders - Swamp"}), # Swamp to Overworld upper ("Swamp Mid", "Swamp Redux 2, Overworld Redux_wall", - {"Swamp Ladders"}), + {"Ladders - Swamp"}), # Ladder by the hero grave ("Back of Swamp", "Swamp Redux 2, Overworld Redux_conduit", set()), ("Back of Swamp", "Swamp Redux 2, Shop_", set()), @@ -1179,13 +1179,13 @@ def get_portal_info(portal_sd: str) -> (str, str): name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and has_ability(state, player, holy_cross, options, ability_unlocks) - and (has_ladder("Swamp Ladders", state, player, options) or not options.entrance_rando)) + and (has_ladder("Ladders - Swamp", state, player, options) or not options.entrance_rando)) elif portal_name == "West Garden Exit after Boss" and not options.entrance_rando: regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and (state.has_any({"Ladders to West Bell", "Dark Tomb Ladder"}, player))) + and (state.has_any({"Ladders - To West Bell", "Ladder - Dark Tomb under Casket"}, player))) # soft locked unless you have either ladder. if you have laurels, you use the other Entrance elif portal_name in ["Furnace Exit towards West Garden", "Furnace Exit to Dark Tomb"] \ and not options.entrance_rando: @@ -1193,7 +1193,7 @@ def get_portal_info(portal_sd: str) -> (str, str): regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and state.has_any({"Dark Tomb Ladder", "Ladders to West Bell"}, player)) + and state.has_any({"Ladder - Dark Tomb under Casket", "Ladders - To West Bell"}, player)) # soft locked for the same reasons as above elif portal_name in ["Entrance to Furnace near West Garden", "West Garden Entrance from Furnace"] \ and not options.entrance_rando: @@ -1202,14 +1202,14 @@ def get_portal_info(portal_sd: str) -> (str, str): name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and state.has_any(ladders, player) - and state.has_any({"Dark Tomb Ladder", "Ladders to West Bell"}, player)) + and state.has_any({"Ladder - Dark Tomb under Casket", "Ladders - To West Bell"}, player)) # soft locked if you can't get past garden knight backwards or up the belltower ladders elif portal_name == "West Garden Entrance near Belltower" and not options.entrance_rando: regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and state.has_any(ladders, player) - and state.has_any({"Ladders to West Bell", laurels}, player)) + and state.has_any({"Ladders - To West Bell", laurels}, player)) # soft lock potential elif portal_name in ["Special Shop Entrance", "Stairs to Top of the Mountain"] \ and not options.entrance_rando: diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index b42089ab96df..44926b1fcf65 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -144,26 +144,26 @@ class TunicItemData(NamedTuple): "Pages 52-53 (Icebolt)": TunicItemData(ItemClassification.progression, 1, 128, "pages"), "Pages 54-55": TunicItemData(ItemClassification.useful, 1, 129, "pages"), - "Ladders near Weathervane": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), - "Overworld Shortcut Ladders": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), - "Ladder Drop to East Forest": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), - "Ladders to Lower Forest": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), - "Ladders near Patrol Cave": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), - "Ladder to Well": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), - "Well Back Ladder": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), - "Ladders to West Bell": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), - "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), - "Dark Tomb Ladder": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), - "Ladders near Dark Tomb": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), - "Ladder near Temple Rafters": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), - "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), - "Swamp Ladders": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), - "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), - "South Atoll Ladders": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), - "Ladders to Frog's Domain": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), - "Hourglass Cave Ladders": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), - "Overworld Town Ladders": TunicItemData(ItemClassification.progression, 0, 148, "ladders"), - "Ladder to Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 149, "ladders") + "Ladders - Near Weathervane": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), + "Ladders - Overworld Shortcut": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), + "Ladder - Drop to East Forest": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), + "Ladders - To Lower Forest": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), + "Ladders - Near Patrol Cave": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), + "Ladder - To Well": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), + "Ladder - Back of Well": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), + "Ladders - To West Bell": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), + "Ladder - To Quarry": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), + "Ladder - Dark Tomb under Casket": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), + "Ladders - Near Dark Tomb": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), + "Ladder - Near Temple Rafters": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), + "Ladder - To Swamp": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), + "Ladders - Swamp": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), + "Ladder - To Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), + "Ladders - South Atoll": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), + "Ladders - To Frog's Domain": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), + "Ladders - Hourglass Cave": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), + "Ladders - Overworld Town": TunicItemData(ItemClassification.progression, 0, 148, "ladders"), + "Ladder - To Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 149, "ladders") } fool_tiers: List[List[str]] = [ @@ -231,7 +231,7 @@ def get_item_group(item_name: str) -> str: "progressive sword": {"Sword Upgrade"}, "abilities": {"Pages 24-25 (Prayer)", "Pages 42-43 (Holy Cross)", "Pages 52-53 (Icebolt)"}, "questagons": {"Red Questagon", "Green Questagon", "Blue Questagon", "Gold Questagon"}, - "ladder to atoll": {"Ladder to Ruined Atoll"}, # fuzzy matching made it hint ladder to well, now it won't + "ladder - to atoll": {"Ladder - To Ruined Atoll"}, # fuzzy matching made it hint Ladder - To Well, now it won't } item_name_groups.update(extra_groups) From 51a50ff1256151bc8d132fbc9b5afe9214fc3aeb Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 20:50:19 -0400 Subject: [PATCH 54/82] Address review comments, also fix a tiny region issue --- worlds/tunic/__init__.py | 14 +++++++------- worlds/tunic/er_data.py | 14 ++++++++------ worlds/tunic/er_rules.py | 6 +++--- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index 9621f9a8360b..257ddd2e5821 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -87,7 +87,7 @@ def create_items(self) -> None: self.slot_data_items = [] items_to_create: Dict[str, int] = {item: data.quantity_in_item_pool for item, data in item_table.items()} - + for money_fool in fool_tiers[self.options.fool_traps]: items_to_create["Fool Trap"] += items_to_create[money_fool] items_to_create[money_fool] = 0 @@ -131,6 +131,8 @@ def remove_filler(amount: int): fill = "Fool Trap" else: fill = self.random.choice(available_filler) + if items_to_create[fill] == 0: + raise Exception("No filler items left to accommodate options selected. Turn down fool trap amount.") items_to_create[fill] -= 1 if items_to_create[fill] == 0: available_filler.remove(fill) @@ -142,7 +144,7 @@ def remove_filler(amount: int): items_to_create[item_name] = 1 ladder_count += 1 remove_filler(ladder_count) - + if hexagon_quest: # Calculate number of hexagons in item pool hexagon_goal = self.options.hexagon_goal @@ -199,14 +201,12 @@ def create_regions(self) -> None: for portal1, portal2 in portal_pairs.items(): self.tunic_portal_pairs[portal1.scene_destination()] = portal2.scene_destination() else: - # for non-ER, non-ladder - region_list = tunic_regions - - for region_name in region_list: + # for non-ER, non-ladders + for region_name in tunic_regions: region = Region(region_name, self.player, self.multiworld) self.multiworld.regions.append(region) - for region_name, exits in region_list.items(): + for region_name, exits in tunic_regions.items(): region = self.multiworld.get_region(region_name, self.player) region.add_exits(exits) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 56f1f0cfff8b..8f659cd0f1d4 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -726,6 +726,7 @@ class DeadEnd(IntEnum): # 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", @@ -733,7 +734,7 @@ class DeadEnd(IntEnum): "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 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", @@ -742,7 +743,7 @@ class DeadEnd(IntEnum): "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 after Envoy", "Overworld Tunnel Turret"], ("Hourglass Cave",): ["Hourglass Cave", "Hourglass Cave Tower"], ("Old House Front",): @@ -847,7 +848,7 @@ class DeadEnd(IntEnum): "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 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", @@ -855,7 +856,8 @@ class DeadEnd(IntEnum): "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 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"], @@ -962,7 +964,7 @@ class DeadEnd(IntEnum): "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 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", @@ -970,7 +972,7 @@ class DeadEnd(IntEnum): "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 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"], diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index bf19adef8995..f7ea04d02a48 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1187,7 +1187,7 @@ def get_portal_info(portal_sd: str) -> (str, str): rule=lambda state: has_stick(state, player) and (state.has_any({"Ladders - To West Bell", "Ladder - Dark Tomb under Casket"}, player))) # soft locked unless you have either ladder. if you have laurels, you use the other Entrance - elif portal_name in ["Furnace Exit towards West Garden", "Furnace Exit to Dark Tomb"] \ + elif portal_name in {"Furnace Exit towards West Garden", "Furnace Exit to Dark Tomb"} \ and not options.entrance_rando: regions[region_name].connect( regions[paired_region], @@ -1195,7 +1195,7 @@ def get_portal_info(portal_sd: str) -> (str, str): rule=lambda state: has_stick(state, player) and state.has_any({"Ladder - Dark Tomb under Casket", "Ladders - To West Bell"}, player)) # soft locked for the same reasons as above - elif portal_name in ["Entrance to Furnace near West Garden", "West Garden Entrance from Furnace"] \ + elif portal_name in {"Entrance to Furnace near West Garden", "West Garden Entrance from Furnace"} \ and not options.entrance_rando: regions[region_name].connect( regions[paired_region], @@ -1211,7 +1211,7 @@ def get_portal_info(portal_sd: str) -> (str, str): rule=lambda state: has_stick(state, player) and state.has_any(ladders, player) and state.has_any({"Ladders - To West Bell", laurels}, player)) # soft lock potential - elif portal_name in ["Special Shop Entrance", "Stairs to Top of the Mountain"] \ + elif portal_name in {"Special Shop Entrance", "Stairs to Top of the Mountain"} \ and not options.entrance_rando: continue # soft lock if you don't have the ladder, just exclude it for simplicity From d02b13e58b3e8624f0f403e27120ce6e589a350d Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 20:51:17 -0400 Subject: [PATCH 55/82] Add me to codeowners (Silent said it was okay) --- docs/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index d6730b7308ae..acb9045c8583 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -171,7 +171,7 @@ /worlds/tloz/ @Rosalie-A @t3hf1gm3nt # TUNIC -/worlds/tunic/ @silent-destroyer +/worlds/tunic/ @silent-destroyer @ScipioWright # Undertale /worlds/undertale/ @jonloveslegos From 340360dba6c770ccdc189a4070f1c91d7efcec2b Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 21:20:10 -0400 Subject: [PATCH 56/82] Add another ladder group --- worlds/tunic/er_data.py | 37 ++++++++++++++++++----------- worlds/tunic/er_rules.py | 50 ++++++++++++++++++++++++++++++++++++---- worlds/tunic/items.py | 3 ++- 3 files changed, 71 insertions(+), 19 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 8f659cd0f1d4..15e8fd0869ac 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -241,23 +241,23 @@ def destination_scene(self) -> str: # the vanilla connection Portal(name="Library Exterior Ladder", region="Library Exterior Ladder Region", destination="Library Hall", tag="_"), - Portal(name="Library Hall Bookshelf Exit", region="Library Hall", + Portal(name="Library Hall Bookshelf Exit", region="Library Hall Bookshelf", destination="Library Exterior", tag="_"), Portal(name="Library Hero's Grave", region="Library Hero's Grave Region", destination="RelicVoid", tag="_teleporter_relic plinth"), - Portal(name="Library Hall to Rotunda", region="Library Hall", + Portal(name="Library Hall to Rotunda", region="Library Hall to Rotunda", destination="Library Rotunda", tag="_"), - Portal(name="Library Rotunda Lower Exit", region="Library Rotunda", + Portal(name="Library Rotunda Lower Exit", region="Library Rotunda to Hall", destination="Library Hall", tag="_"), - Portal(name="Library Rotunda Upper Exit", region="Library Rotunda", + Portal(name="Library Rotunda Upper Exit", region="Library Rotunda to Lab", destination="Library Lab", tag="_"), Portal(name="Library Lab to Rotunda", region="Library Lab Lower", destination="Library Rotunda", tag="_"), Portal(name="Library to Far Shore", region="Library Portal", destination="Transit", tag="_teleporter_library teleporter"), - Portal(name="Library Lab to Librarian Arena", region="Library Lab", + Portal(name="Library Lab to Librarian Arena", region="Library Lab to Librarian", destination="Library Arena", tag="_"), Portal(name="Librarian Arena Exit", region="Library Arena", @@ -630,12 +630,17 @@ class DeadEnd(IntEnum): "Frog's Domain Back": RegionInfo("frog cave main"), "Library Exterior Tree Region": RegionInfo("Library Exterior"), "Library Exterior Ladder Region": RegionInfo("Library Exterior"), + "Library Hall Bookshelf": RegionInfo("Library Hall"), "Library Hall": RegionInfo("Library Hall"), "Library Hero's Grave Region": RegionInfo("Library Hall"), + "Library Hall to Rotunda": RegionInfo("Library Hall"), + "Library Rotunda to Hall": RegionInfo("Library Rotunda"), "Library Rotunda": RegionInfo("Library Rotunda"), + "Library Rotunda to Lab": RegionInfo("Library Rotunda"), "Library Lab": RegionInfo("Library Lab"), "Library Lab Lower": RegionInfo("Library Lab"), "Library Portal": RegionInfo("Library Lab"), + "Library Lab to Librarian": RegionInfo("Library Lab"), "Library Arena": RegionInfo("Library Arena", dead_end=DeadEnd.all_cats), "Fortress Exterior from East Forest": RegionInfo("Fortress Courtyard"), "Fortress Exterior from Overworld": RegionInfo("Fortress Courtyard"), @@ -784,8 +789,10 @@ class DeadEnd(IntEnum): ["Frog's Domain", "Frog's Domain Back"], ("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", "Library Hero's Grave 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 Lab to Librarian"): + ["Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab", "Library Lab to Librarian"], ("Library Lab", "Library Lab Lower", "Library Portal"): ["Library Lab", "Library Lab Lower", "Library Portal"], ("Fortress Courtyard Upper",): @@ -898,8 +905,10 @@ class DeadEnd(IntEnum): ["Frog's Domain", "Frog's Domain Back"], ("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", "Library Hero's Grave 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 Lab to Librarian"): + ["Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab", "Library Lab to Librarian"], ("Library Lab", "Library Lab Lower", "Library Portal"): ["Library Lab", "Library Lab Lower", "Library Portal"], ("Fortress Exterior from East Forest", "Fortress Exterior from Overworld", @@ -1015,10 +1024,12 @@ class DeadEnd(IntEnum): ["Frog's Domain", "Frog's Domain Back"], ("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", "Library Hero's Grave Region"], - ("Library Lab", "Library Lab Lower", "Library Portal"): - ["Library Lab", "Library Lab Lower", "Library Portal"], + ("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"): diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index f7ea04d02a48..0dbd4a8f2436 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -589,11 +589,20 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # Library regions["Library Exterior Tree Region"].connect( connecting_region=regions["Library Exterior Ladder Region"], - rule=lambda state: state.has(grapple, player) or state.has(laurels, player)) + rule=lambda state: state.has_any({grapple, laurels}, player) + and has_ladder("Ladders - Library", state, player, options)) regions["Library Exterior Ladder Region"].connect( connecting_region=regions["Library Exterior Tree Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) - and (state.has(grapple, player) or state.has(laurels, player))) + and state.has_any({grapple, laurels}, player) + and has_ladder("Ladders - Library", state, player, options)) + + regions["Library Hall Bookshelf"].connect( + connecting_region=regions["Library Hall"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + regions["Library Hall"].connect( + connecting_region=regions["Library Hall Bookshelf"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) regions["Library Hall"].connect( connecting_region=regions["Library Hero's Grave Region"], @@ -601,19 +610,50 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Library Hero's Grave Region"].connect( connecting_region=regions["Library Hall"]) + regions["Library Hall to Rotunda"].connect( + connecting_region=regions["Library Hall"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + regions["Library Hall"].connect( + connecting_region=regions["Library Hall to Rotunda"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + + regions["Library Rotunda to Hall"].connect( + connecting_region=regions["Library Rotunda"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + regions["Library Rotunda"].connect( + connecting_region=regions["Library Rotunda to Hall"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + + regions["Library Rotunda"].connect( + connecting_region=regions["Library Rotunda to Lab"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + regions["Library Rotunda to Lab"].connect( + connecting_region=regions["Library Rotunda"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + regions["Library Lab Lower"].connect( connecting_region=regions["Library Lab"], - rule=lambda state: state.has(laurels, player) or state.has(grapple, player)) + rule=lambda state: state.has_any({grapple, laurels}, player) + and has_ladder("Ladders - Library", state, player, options)) regions["Library Lab"].connect( connecting_region=regions["Library Lab Lower"], - rule=lambda state: state.has(laurels, player)) + rule=lambda state: state.has(laurels, player) + and has_ladder("Ladders - Library", state, player, options)) regions["Library Lab"].connect( connecting_region=regions["Library Portal"], - rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks)) + rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) + and has_ladder("Ladders - Library", state, player, options)) regions["Library Portal"].connect( connecting_region=regions["Library Lab"]) + regions["Library Lab"].connect( + connecting_region=regions["Library Lab to Librarian"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + regions["Library Lab to Librarian"].connect( + connecting_region=regions["Library Lab"], + rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + # Eastern Vault Fortress regions["Fortress Exterior from East Forest"].connect( connecting_region=regions["Fortress Exterior from Overworld"], diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 44926b1fcf65..359c01f7cb8e 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -163,7 +163,8 @@ class TunicItemData(NamedTuple): "Ladders - To Frog's Domain": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), "Ladders - Hourglass Cave": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), "Ladders - Overworld Town": TunicItemData(ItemClassification.progression, 0, 148, "ladders"), - "Ladder - To Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 149, "ladders") + "Ladder - To Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 149, "ladders"), + "Ladders - Library": TunicItemData(ItemClassification.progression, 0, 150, "ladders") } fool_tiers: List[List[str]] = [ From 0a2da8a7b5329e3f38dd44792dadd963caafe61f Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 21:23:53 -0400 Subject: [PATCH 57/82] Add Silvris's suggestion Tested it first to confirm Co-authored-by: Silvris <58583688+Silvris@users.noreply.github.com> --- worlds/tunic/__init__.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index 257ddd2e5821..5ed2462fe1b2 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -255,10 +255,7 @@ def extend_hint_information(self, hint_data: Dict[int, Dict[int, str]]): if name in portal_names and name != previous_name: previous_name = name path_to_loc.append(name) - hint_text = "" - for transition in reversed(path_to_loc): - hint_text += f"{transition} -> " - hint_text = hint_text.rstrip("-> ") + hint_text = " -> ".join(reversed(path_to_loc)) if hint_text: hint_data[self.player][location.address] = hint_text From f0711fb97af8f7b86978c6973cba15be03e78077 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 21:32:37 -0400 Subject: [PATCH 58/82] Add another suggested ladder --- worlds/tunic/er_data.py | 19 +++++++++++-------- worlds/tunic/er_rules.py | 8 +++++++- worlds/tunic/items.py | 3 ++- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 15e8fd0869ac..217186a279fd 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -676,6 +676,7 @@ class DeadEnd(IntEnum): "Monastery Hero's Grave Region": RegionInfo("Monastery"), "Monastery Rope": RegionInfo("Quarry Redux"), "Lower Quarry": RegionInfo("Quarry Redux"), + "Even Lower Quarry": RegionInfo("Quarry Redux"), "Lower Quarry Zig Door": RegionInfo("Quarry Redux"), "Rooted Ziggurat Entry": RegionInfo("ziggurat2020_0"), "Rooted Ziggurat Upper Entry": RegionInfo("ziggurat2020_1"), @@ -818,11 +819,12 @@ class DeadEnd(IntEnum): ["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"): + ("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"], + "Lower Quarry Zig Door", "Even Lower Quarry"], ("Monastery Rope",): ["Monastery Rope", "Quarry", "Quarry Entry", "Quarry Back", "Quarry Portal", "Lower Quarry", - "Lower Quarry Zig Door"], + "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",): @@ -932,11 +934,12 @@ class DeadEnd(IntEnum): ["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"): + ("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"], + "Lower Quarry Zig Door", "Even Lower Quarry"], ("Monastery Rope",): ["Monastery Rope", "Quarry", "Quarry Entry", "Quarry Back", "Quarry Portal", "Lower Quarry", - "Lower Quarry Zig Door"], + "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",): @@ -1056,9 +1059,9 @@ class DeadEnd(IntEnum): ["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"): + "Monastery Rope", "Even Lower Quarry"): ["Quarry", "Quarry Portal", "Lower Quarry", "Quarry Entry", "Quarry Back", "Quarry Monastery Entry", - "Monastery Rope", "Lower Quarry Zig Door"], + "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",): diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 0dbd4a8f2436..4667eb8ea458 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -795,8 +795,14 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Lower Quarry"], rule=lambda state: has_mask(state, player, options)) - # nmg: bring a scav over, then ice grapple through the door, only with ER on to avoid soft lock + # need the ladder, or you can ice grapple down in nmg regions["Lower Quarry"].connect( + connecting_region=regions["Even Lower Quarry"], + rule=lambda state: has_ladder("Ladder - Lower Quarry", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) + + # nmg: bring a scav over, then ice grapple through the door, only with ER on to avoid soft lock + regions["Even Lower Quarry"].connect( connecting_region=regions["Lower Quarry Zig Door"], rule=lambda state: state.has("Activate Quarry Fuse", player) or (has_ice_grapple_logic(False, state, player, options, ability_unlocks) and options.entrance_rando)) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 359c01f7cb8e..58e3651fb99a 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -164,7 +164,8 @@ class TunicItemData(NamedTuple): "Ladders - Hourglass Cave": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), "Ladders - Overworld Town": TunicItemData(ItemClassification.progression, 0, 148, "ladders"), "Ladder - To Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 149, "ladders"), - "Ladders - Library": TunicItemData(ItemClassification.progression, 0, 150, "ladders") + "Ladders - Library": TunicItemData(ItemClassification.progression, 0, 150, "ladders"), + "Ladder - Lower Quarry": TunicItemData(ItemClassification.progression, 0, 151, "ladders") } fool_tiers: List[List[str]] = [ From 4fef2c148cdf635893e79c2324d9a7282a4f3546 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 22:01:04 -0400 Subject: [PATCH 59/82] Renaming ladders, combining two into one. Also update docs to include the ladders item group. --- worlds/tunic/er_rules.py | 270 +++++++++++++++++++-------------------- worlds/tunic/items.py | 45 ++++--- 2 files changed, 157 insertions(+), 158 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 4667eb8ea458..5ec667b3bdf9 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -48,11 +48,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # grapple on the west side, down the stairs from moss wall, across from ruined shop regions["Overworld"].connect( connecting_region=regions["Overworld Beach"], - rule=lambda state: has_ladder("Ladders - Overworld Town", state, player, options) + rule=lambda state: has_ladder("Ladders in Overworld Town", state, player, options) or state.has_any({laurels, grapple}, player)) regions["Overworld Beach"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladders - Overworld Town", state, player, options) + rule=lambda state: has_ladder("Ladders in Overworld Town", state, player, options) or state.has_any({laurels, grapple}, player)) regions["Overworld Beach"].connect( @@ -64,10 +64,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld Beach"].connect( connecting_region=regions["Overworld to Atoll Upper"], - rule=lambda state: has_ladder("Ladder - To Ruined Atoll", state, player, options)) + rule=lambda state: has_ladder("Ladder to Ruined Atoll", state, player, options)) regions["Overworld to Atoll Upper"].connect( connecting_region=regions["Overworld Beach"], - rule=lambda state: has_ladder("Ladder - To Ruined Atoll", state, player, options)) + rule=lambda state: has_ladder("Ladder to Ruined Atoll", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld to Atoll Upper"], @@ -84,14 +84,14 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld Belltower"].connect( connecting_region=regions["Overworld to West Garden Upper"], - rule=lambda state: has_ladder("Ladders - To West Bell", state, player, options)) + rule=lambda state: has_ladder("Ladders to West Bell", state, player, options)) regions["Overworld to West Garden Upper"].connect( connecting_region=regions["Overworld Belltower"], - rule=lambda state: has_ladder("Ladders - To West Bell", state, player, options)) + rule=lambda state: has_ladder("Ladders to West Bell", state, player, options)) regions["Overworld Belltower"].connect( connecting_region=regions["Overworld Belltower at Bell"], - rule=lambda state: has_ladder("Ladders - To West Bell", state, player, options)) + rule=lambda state: has_ladder("Ladders to West Bell", state, player, options)) # long dong, do not make a reverse connection here or to belltower regions["Overworld above Patrol Cave"].connect( @@ -109,35 +109,35 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["After Ruined Passage"], - rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["After Ruined Passage"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options)) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Above Ruined Passage"], - rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) or state.has(laurels, player)) regions["Above Ruined Passage"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) or state.has(laurels, player)) regions["After Ruined Passage"].connect( connecting_region=regions["Above Ruined Passage"], - rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options)) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) regions["Above Ruined Passage"].connect( connecting_region=regions["After Ruined Passage"], - rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options)) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options)) regions["Above Ruined Passage"].connect( connecting_region=regions["East Overworld"], - rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["East Overworld"].connect( connecting_region=regions["Above Ruined Passage"], - rule=lambda state: has_ladder("Ladders - Near Weathervane", state, player, options) + rule=lambda state: has_ladder("Ladders near Weathervane", state, player, options) or state.has(laurels, player)) # nmg: ice grapple the slimes, works both ways consistently @@ -150,11 +150,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["East Overworld"], - rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options) + rule=lambda state: has_ladder("Ladders near Overworld Checkpoint", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["East Overworld"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options)) + rule=lambda state: has_ladder("Ladders near Overworld Checkpoint", state, player, options)) regions["East Overworld"].connect( connecting_region=regions["Overworld at Patrol Cave"]) @@ -164,35 +164,35 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld at Patrol Cave"].connect( connecting_region=regions["Overworld above Patrol Cave"], - rule=lambda state: has_ladder("Ladders - Near Patrol Cave", state, player, options) + rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Overworld above Patrol Cave"].connect( connecting_region=regions["Overworld at Patrol Cave"], - rule=lambda state: has_ladder("Ladders - Near Patrol Cave", state, player, options)) + rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld above Patrol Cave"], - rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options) + rule=lambda state: has_ladder("Ladders near Overworld Checkpoint", state, player, options) or state.has(grapple, player)) regions["Overworld above Patrol Cave"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options)) + rule=lambda state: has_ladder("Ladders near Overworld Checkpoint", state, player, options)) regions["East Overworld"].connect( connecting_region=regions["Overworld above Patrol Cave"], - rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options) + rule=lambda state: has_ladder("Ladders near Overworld Checkpoint", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Overworld above Patrol Cave"].connect( connecting_region=regions["East Overworld"], - rule=lambda state: has_ladder("Ladders - Overworld Shortcut", state, player, options)) + rule=lambda state: has_ladder("Ladders near Overworld Checkpoint", state, player, options)) regions["Overworld above Patrol Cave"].connect( connecting_region=regions["Upper Overworld"], - rule=lambda state: has_ladder("Ladders - Near Patrol Cave", state, player, options) + rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Upper Overworld"].connect( connecting_region=regions["Overworld above Patrol Cave"], - rule=lambda state: has_ladder("Ladders - Near Patrol Cave", state, player, options) + rule=lambda state: has_ladder("Ladders near Patrol Cave", state, player, options) or state.has(grapple, player)) regions["Upper Overworld"].connect( @@ -204,18 +204,18 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Upper Overworld"].connect( connecting_region=regions["Overworld after Temple Rafters"], - rule=lambda state: has_ladder("Ladder - Near Temple Rafters", state, player, options)) + rule=lambda state: has_ladder("Ladder near Temple Rafters", state, player, options)) regions["Overworld after Temple Rafters"].connect( connecting_region=regions["Upper Overworld"], - rule=lambda state: has_ladder("Ladder - Near Temple Rafters", state, player, options) + rule=lambda state: has_ladder("Ladder near Temple Rafters", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Overworld above Quarry Entrance"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladders - Near Dark Tomb", state, player, options)) + rule=lambda state: has_ladder("Ladders near Dark Tomb", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld above Quarry Entrance"], - rule=lambda state: has_ladder("Ladders - Near Dark Tomb", state, player, options)) + rule=lambda state: has_ladder("Ladders near Dark Tomb", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld after Envoy"], @@ -226,10 +226,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld after Envoy"].connect( connecting_region=regions["Overworld Quarry Entry"], - rule=lambda state: has_ladder("Ladder - To Quarry", state, player, options)) + rule=lambda state: has_ladder("Ladder to Quarry", state, player, options)) regions["Overworld Quarry Entry"].connect( connecting_region=regions["Overworld after Envoy"], - rule=lambda state: has_ladder("Ladder - To Quarry", state, player, options)) + rule=lambda state: has_ladder("Ladder to Quarry", state, player, options)) # ice grapple through the gate regions["Overworld"].connect( @@ -248,10 +248,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["Overworld Swamp Lower Entry"], - rule=lambda state: has_ladder("Ladder - To Swamp", state, player, options)) + rule=lambda state: has_ladder("Ladder to Swamp", state, player, options)) regions["Overworld Swamp Lower Entry"].connect( connecting_region=regions["Overworld"], - rule=lambda state: has_ladder("Ladder - To Swamp", state, player, options)) + rule=lambda state: has_ladder("Ladder to Swamp", state, player, options)) regions["Overworld"].connect( connecting_region=regions["Overworld Special Shop Entry"], @@ -262,7 +262,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["Overworld Well Ladder"], - rule=lambda state: has_ladder("Ladder - To Well", state, player, options)) + rule=lambda state: has_ladder("Ladders in Well", state, player, options)) regions["Overworld Well Ladder"].connect( connecting_region=regions["Overworld"]) @@ -311,11 +311,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld Tunnel Turret"].connect( connecting_region=regions["Overworld Beach"], - rule=lambda state: has_ladder("Ladders - Overworld Town", state, player, options) + rule=lambda state: has_ladder("Ladders in Overworld Town", state, player, options) or state.has(grapple, player)) regions["Overworld Beach"].connect( connecting_region=regions["Overworld Tunnel Turret"], - rule=lambda state: has_ladder("Ladders - Overworld Town", state, player, options) + rule=lambda state: has_ladder("Ladders in Overworld Town", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) regions["Overworld"].connect( @@ -363,7 +363,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Hourglass Cave"].connect( connecting_region=regions["Hourglass Cave Tower"], - rule=lambda state: has_ladder("Ladders - Hourglass Cave", state, player, options)) + rule=lambda state: has_ladder("Ladders in Hourglass Cave", state, player, options)) # East Forest regions["Forest Belltower Upper"].connect( @@ -371,7 +371,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Forest Belltower Main"].connect( connecting_region=regions["Forest Belltower Lower"], - rule=lambda state: has_ladder("Ladder - Drop to East Forest", state, player, options)) + rule=lambda state: has_ladder("Ladder to East Forest", state, player, options)) # nmg: ice grapple up to dance fox spot, and vice versa regions["East Forest"].connect( @@ -391,12 +391,12 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["East Forest"].connect( connecting_region=regions["Lower Forest"], - rule=lambda state: has_ladder("Ladders - To Lower Forest", state, player, options) + rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options) or (state.has_all({grapple, fire_wand, ice_dagger}, player) # do ice slime, then go to the lower hook and has_ability(state, player, icebolt, options, ability_unlocks))) regions["Lower Forest"].connect( connecting_region=regions["East Forest"], - rule=lambda state: has_ladder("Ladders - To Lower Forest", state, player, options)) + rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options)) regions["Guard House 1 East"].connect( connecting_region=regions["Guard House 1 West"]) @@ -406,10 +406,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Guard House 2 Upper"].connect( connecting_region=regions["Guard House 2 Lower"], - rule=lambda state: has_ladder("Ladders - To Lower Forest", state, player, options)) + rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options)) regions["Guard House 2 Lower"].connect( connecting_region=regions["Guard House 2 Upper"], - rule=lambda state: has_ladder("Ladders - To Lower Forest", state, player, options)) + rule=lambda state: has_ladder("Ladders to Lower Forest", state, player, options)) # nmg: ice grapple from upper grave path exit to the rest of it regions["Forest Grave Path Upper"].connect( @@ -438,10 +438,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # don't need the ladder when entering at the ladder spot regions["Beneath the Well Ladder Exit"].connect( connecting_region=regions["Beneath the Well Front"], - rule=lambda state: has_ladder("Ladder - To Well", state, player, options)) + rule=lambda state: has_ladder("Ladders in Well", state, player, options)) regions["Beneath the Well Front"].connect( connecting_region=regions["Beneath the Well Ladder Exit"], - rule=lambda state: has_ladder("Ladder - To Well", state, player, options)) + rule=lambda state: has_ladder("Ladders in Well", state, player, options)) regions["Beneath the Well Front"].connect( connecting_region=regions["Beneath the Well Main"], @@ -452,10 +452,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Beneath the Well Main"].connect( connecting_region=regions["Beneath the Well Back"], - rule=lambda state: has_ladder("Ladder - Back of Well", state, player, options)) + rule=lambda state: has_ladder("Ladders in Well", state, player, options)) regions["Beneath the Well Back"].connect( connecting_region=regions["Beneath the Well Main"], - rule=lambda state: has_ladder("Ladder - Back of Well", state, player, options) + rule=lambda state: has_ladder("Ladders in Well", state, player, options) and (has_stick(state, player) or state.has(fire_wand, player))) regions["Well Boss"].connect( @@ -473,10 +473,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Dark Tomb Upper"].connect( connecting_region=regions["Dark Tomb Main"], - rule=lambda state: has_ladder("Ladder - Dark Tomb under Casket", state, player, options)) + rule=lambda state: has_ladder("Ladder in Dark Tomb", state, player, options)) regions["Dark Tomb Main"].connect( connecting_region=regions["Dark Tomb Upper"], - rule=lambda state: has_ladder("Ladder - Dark Tomb under Casket", state, player, options)) + rule=lambda state: has_ladder("Ladder in Dark Tomb", state, player, options)) regions["Dark Tomb Main"].connect( connecting_region=regions["Dark Tomb Dark Exit"]) @@ -532,7 +532,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Ladder Tops"], - rule=lambda state: has_ladder("Ladders - South Atoll", state, player, options)) + rule=lambda state: has_ladder("Ladders in South Atoll", state, player, options)) regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Frog Mouth"], @@ -543,10 +543,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Frog Eye"], - rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) regions["Ruined Atoll Frog Eye"].connect( connecting_region=regions["Ruined Atoll"], - rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Portal"], @@ -557,30 +557,30 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Ruined Atoll"].connect( connecting_region=regions["Ruined Atoll Statue"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) - and has_ladder("Ladders - South Atoll", state, player, options)) + and has_ladder("Ladders in South Atoll", state, player, options)) regions["Ruined Atoll Statue"].connect( connecting_region=regions["Ruined Atoll"]) regions["Frog Stairs Eye Exit"].connect( connecting_region=regions["Frog Stairs Upper"], - rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) regions["Frog Stairs Upper"].connect( connecting_region=regions["Frog Stairs Eye Exit"], - rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) regions["Frog Stairs Upper"].connect( connecting_region=regions["Frog Stairs Lower"], - rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) regions["Frog Stairs Lower"].connect( connecting_region=regions["Frog Stairs Upper"], - rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) regions["Frog Stairs Lower"].connect( connecting_region=regions["Frog Stairs to Frog's Domain"], - rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) regions["Frog Stairs to Frog's Domain"].connect( connecting_region=regions["Frog Stairs Lower"], - rule=lambda state: has_ladder("Ladders - To Frog's Domain", state, player, options)) + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) regions["Frog's Domain"].connect( connecting_region=regions["Frog's Domain Back"], @@ -590,19 +590,19 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Library Exterior Tree Region"].connect( connecting_region=regions["Library Exterior Ladder Region"], rule=lambda state: state.has_any({grapple, laurels}, player) - and has_ladder("Ladders - Library", state, player, options)) + and has_ladder("Ladders in Library", state, player, options)) regions["Library Exterior Ladder Region"].connect( connecting_region=regions["Library Exterior Tree Region"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) and state.has_any({grapple, laurels}, player) - and has_ladder("Ladders - Library", state, player, options)) + and has_ladder("Ladders in Library", state, player, options)) regions["Library Hall Bookshelf"].connect( connecting_region=regions["Library Hall"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) regions["Library Hall"].connect( connecting_region=regions["Library Hall Bookshelf"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) regions["Library Hall"].connect( connecting_region=regions["Library Hero's Grave Region"], @@ -612,47 +612,47 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Library Hall to Rotunda"].connect( connecting_region=regions["Library Hall"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) regions["Library Hall"].connect( connecting_region=regions["Library Hall to Rotunda"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) regions["Library Rotunda to Hall"].connect( connecting_region=regions["Library Rotunda"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) regions["Library Rotunda"].connect( connecting_region=regions["Library Rotunda to Hall"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) regions["Library Rotunda"].connect( connecting_region=regions["Library Rotunda to Lab"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) regions["Library Rotunda to Lab"].connect( connecting_region=regions["Library Rotunda"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) regions["Library Lab Lower"].connect( connecting_region=regions["Library Lab"], rule=lambda state: state.has_any({grapple, laurels}, player) - and has_ladder("Ladders - Library", state, player, options)) + and has_ladder("Ladders in Library", state, player, options)) regions["Library Lab"].connect( connecting_region=regions["Library Lab Lower"], rule=lambda state: state.has(laurels, player) - and has_ladder("Ladders - Library", state, player, options)) + and has_ladder("Ladders in Library", state, player, options)) regions["Library Lab"].connect( connecting_region=regions["Library Portal"], rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) - and has_ladder("Ladders - Library", state, player, options)) + and has_ladder("Ladders in Library", state, player, options)) regions["Library Portal"].connect( connecting_region=regions["Library Lab"]) regions["Library Lab"].connect( connecting_region=regions["Library Lab to Librarian"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) regions["Library Lab to Librarian"].connect( connecting_region=regions["Library Lab"], - rule=lambda state: has_ladder("Ladders - Library", state, player, options)) + rule=lambda state: has_ladder("Ladders in Library", state, player, options)) # Eastern Vault Fortress regions["Fortress Exterior from East Forest"].connect( @@ -671,10 +671,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Fortress Exterior near cave"].connect( connecting_region=regions["Beneath the Vault Entry"], - rule=lambda state: has_ladder("Ladder - To Beneath the Vault", state, player, options)) + rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options)) regions["Beneath the Vault Entry"].connect( connecting_region=regions["Fortress Exterior near cave"], - rule=lambda state: has_ladder("Ladder - To Beneath the Vault", state, player, options)) + rule=lambda state: has_ladder("Ladder to Beneath the Vault", state, player, options)) regions["Fortress Courtyard"].connect( connecting_region=regions["Fortress Exterior from Overworld"], @@ -697,10 +697,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re 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)) + 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 Ladder Exit"], - rule=lambda state: has_ladder("Ladder - To Beneath the Vault", state, player, options)) + 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"], @@ -798,7 +798,7 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # need the ladder, or you can ice grapple down in nmg regions["Lower Quarry"].connect( connecting_region=regions["Even Lower Quarry"], - rule=lambda state: has_ladder("Ladder - Lower Quarry", state, player, options) + rule=lambda state: has_ladder("Ladders in Lower Quarry", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) # nmg: bring a scav over, then ice grapple through the door, only with ER on to avoid soft lock @@ -870,12 +870,12 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re # Swamp and Cathedral regions["Swamp Front"].connect( connecting_region=regions["Swamp Mid"], - rule=lambda state: has_ladder("Ladders - Swamp", state, player, options) + rule=lambda state: has_ladder("Ladders in Swamp", state, player, options) or state.has(laurels, player) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) # nmg: ice grapple through gate regions["Swamp Mid"].connect( connecting_region=regions["Swamp Front"], - rule=lambda state: has_ladder("Ladders - Swamp", state, player, options) + rule=lambda state: has_ladder("Ladders in Swamp", state, player, options) or state.has(laurels, player) or has_ice_grapple_logic(False, state, player, options, ability_unlocks)) # nmg: ice grapple through gate @@ -891,10 +891,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Swamp Mid"].connect( connecting_region=regions["Swamp Ledge under Cathedral Door"], - rule=lambda state: has_ladder("Ladders - Swamp", state, player, options)) + rule=lambda state: has_ladder("Ladders in Swamp", state, player, options)) regions["Swamp Ledge under Cathedral Door"].connect( connecting_region=regions["Swamp Mid"], - rule=lambda state: has_ladder("Ladders - Swamp", state, player, options) + rule=lambda state: has_ladder("Ladders in Swamp", state, player, options) or has_ice_grapple_logic(True, state, player, options, ability_unlocks)) # nmg: ice grapple the enemy at door regions["Swamp Ledge under Cathedral Door"].connect( @@ -1010,136 +1010,136 @@ def get_portal_info(portal_sd: str) -> (str, str): # LS from Overworld main # The upper Swamp entrance ("Overworld", "Overworld Redux, Swamp Redux 2_wall", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town"}), # Upper atoll entrance ("Overworld", "Overworld Redux, Atoll Redux_upper", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town"}), # Furnace entrance, next to the sign that leads to West Garden ("Overworld", "Overworld Redux, Furnace_gyro_west", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town"}), # Upper West Garden entry, by the belltower ("Overworld", "Overworld Redux, Archipelagos Redux_upper", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town"}), # Ruined Passage ("Overworld", "Overworld Redux, Ruins Passage_east", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town"}), # Well rail, west side. Can ls in town, get extra height by going over the portal pad ("Overworld", "Overworld Redux, Sewer_west_aqueduct", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Quarry"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town", "Ladder to Quarry"}), # Well rail, east side. Need some height from the temple stairs ("Overworld", "Overworld Redux, Furnace_gyro_upper_north", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Quarry"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town", "Ladder to Quarry"}), # Quarry entry ("Overworld", "Overworld Redux, Darkwoods Tunnel_", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town", "Ladders in Well"}), # East Forest entry ("Overworld", "Overworld Redux, Forest Belltower_", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", - "Ladders - Near Patrol Cave", "Ladder - To Quarry", "Ladders - Near Dark Tomb"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town", "Ladders in Well", + "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), # Fortress entry ("Overworld", "Overworld Redux, Fortress Courtyard_", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", - "Ladders - Near Patrol Cave", "Ladder - To Quarry", "Ladders - Near Dark Tomb"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town", "Ladders in Well", + "Ladders near Patrol Cave", "Ladder to Quarry", "Ladders near Dark Tomb"}), # Patrol Cave entry ("Overworld", "Overworld Redux, PatrolCave_", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", - "Ladders - Overworld Shortcut", "Ladder - To Quarry", "Ladders - Near Dark Tomb"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town", "Ladders in Well", + "Ladders near Overworld Checkpoint", "Ladder to Quarry", "Ladders near Dark Tomb"}), # Special Shop entry, excluded in non-ER due to soft lock potential ("Overworld", "Overworld Redux, ShopSpecial_", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", - "Ladders - Overworld Shortcut", "Ladders - Near Patrol Cave", "Ladder - To Quarry", - "Ladders - Near Dark Tomb"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town", "Ladders in Well", + "Ladders near Overworld Checkpoint", "Ladders near Patrol Cave", "Ladder to Quarry", + "Ladders near Dark Tomb"}), # Temple Rafters, excluded in non-ER + ladder rando due to soft lock potential ("Overworld", "Overworld Redux, Temple_rafters", - {"Ladders - Near Weathervane", "Ladder - To Swamp", "Ladders - Overworld Town", "Ladder - To Well", - "Ladders - Overworld Shortcut", "Ladders - Near Patrol Cave", "Ladder - To Quarry", - "Ladders - Near Dark Tomb"}), + {"Ladders near Weathervane", "Ladder to Swamp", "Ladders in Overworld Town", "Ladders in Well", + "Ladders near Overworld Checkpoint", "Ladders near Patrol Cave", "Ladder to Quarry", + "Ladders near Dark Tomb"}), # Spot above the Quarry entrance, # only gets you to the mountain stairs ("Overworld above Quarry Entrance", "Overworld Redux, Mountain_", - {"Ladders - Near Dark Tomb"}), + {"Ladders near Dark Tomb"}), # LS from the Overworld Beach # West Garden entry by the Furnace ("Overworld Beach", "Overworld Redux, Archipelagos Redux_lower", - {"Ladders - Overworld Town", "Ladder - To Ruined Atoll"}), + {"Ladders in Overworld Town", "Ladder to Ruined Atoll"}), # West Garden laurels entry ("Overworld Beach", "Overworld Redux, Archipelagos Redux_lowest", - {"Ladders - Overworld Town", "Ladder - To Ruined Atoll"}), + {"Ladders in Overworld Town", "Ladder to Ruined Atoll"}), # Swamp lower entrance ("Overworld Beach", "Overworld Redux, Swamp Redux 2_conduit", - {"Ladders - Overworld Town", "Ladder - To Ruined Atoll"}), + {"Ladders in Overworld Town", "Ladder to Ruined Atoll"}), # Rotating Lights entrance ("Overworld Beach", "Overworld Redux, Overworld Cave_", - {"Ladders - Overworld Town", "Ladder - To Ruined Atoll"}), + {"Ladders in Overworld Town", "Ladder to Ruined Atoll"}), # Swamp upper entrance ("Overworld Beach", "Overworld Redux, Swamp Redux 2_wall", - {"Ladder - To Ruined Atoll"}), + {"Ladder to Ruined Atoll"}), # Furnace entrance, next to the sign that leads to West Garden ("Overworld Beach", "Overworld Redux, Furnace_gyro_west", - {"Ladder - To Ruined Atoll"}), + {"Ladder to Ruined Atoll"}), # Upper West Garden entry, by the belltower ("Overworld Beach", "Overworld Redux, Archipelagos Redux_upper", - {"Ladder - To Ruined Atoll"}), + {"Ladder to Ruined Atoll"}), # Ruined Passage ("Overworld Beach", "Overworld Redux, Ruins Passage_east", - {"Ladder - To Ruined Atoll"}), + {"Ladder to Ruined Atoll"}), # Well rail, west side. Can ls in town, get extra height by going over the portal pad ("Overworld Beach", "Overworld Redux, Sewer_west_aqueduct", - {"Ladder - To Ruined Atoll"}), + {"Ladder to Ruined Atoll"}), # Well rail, east side. Need some height from the temple stairs ("Overworld Beach", "Overworld Redux, Furnace_gyro_upper_north", - {"Ladder - To Ruined Atoll"}), + {"Ladder to Ruined Atoll"}), # Quarry entry ("Overworld Beach", "Overworld Redux, Darkwoods Tunnel_", - {"Ladder - To Ruined Atoll"}), + {"Ladder to Ruined Atoll"}), # LS from that low spot where you normally walk to swamp # Only has low ones you can't get to from main Overworld # West Garden main entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Archipelagos Redux_lower", - {"Ladder - To Swamp"}), + {"Ladder to Swamp"}), # Maze Cave entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Maze Room_", - {"Ladder - To Swamp"}), + {"Ladder to Swamp"}), # Hourglass Cave entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Town Basement_beach", - {"Ladder - To Swamp"}), + {"Ladder to Swamp"}), # Lower Atoll entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Atoll Redux_lower", - {"Ladder - To Swamp"}), + {"Ladder to Swamp"}), # Lowest West Garden entry from swamp ladder ("Overworld Swamp Lower Entry", "Overworld Redux, Archipelagos Redux_lowest", - {"Ladder - To Swamp"}), + {"Ladder to Swamp"}), # from the ladders by the belltower # Ruined Passage ("Overworld to West Garden Upper", "Overworld Redux, Ruins Passage_east", - {"Ladders - To West Bell"}), + {"Ladders to West Bell"}), # Well rail, west side. Can ls in town, get extra height by going over the portal pad ("Overworld to West Garden Upper", "Overworld Redux, Sewer_west_aqueduct", - {"Ladders - To West Bell"}), + {"Ladders to West Bell"}), # Well rail, east side. Need some height from the temple stairs ("Overworld to West Garden Upper", "Overworld Redux, Furnace_gyro_upper_north", - {"Ladders - To West Bell"}), + {"Ladders to West Bell"}), # Quarry entry ("Overworld to West Garden Upper", "Overworld Redux, Darkwoods Tunnel_", - {"Ladders - To West Bell"}), + {"Ladders to West Bell"}), # East Forest entry ("Overworld to West Garden Upper", "Overworld Redux, Forest Belltower_", - {"Ladders - To West Bell"}), + {"Ladders to West Bell"}), # Fortress entry ("Overworld to West Garden Upper", "Overworld Redux, Fortress Courtyard_", - {"Ladders - To West Bell"}), + {"Ladders to West Bell"}), # Patrol Cave entry ("Overworld to West Garden Upper", "Overworld Redux, PatrolCave_", - {"Ladders - To West Bell"}), + {"Ladders to West Bell"}), # Special Shop entry, excluded in non-ER due to soft lock potential ("Overworld to West Garden Upper", "Overworld Redux, ShopSpecial_", - {"Ladders - To West Bell"}), + {"Ladders to West Bell"}), # Temple Rafters, excluded in non-ER and ladder rando due to soft lock potential ("Overworld to West Garden Upper", "Overworld Redux, Temple_rafters", - {"Ladders - To West Bell"}), + {"Ladders to West Bell"}), # In the furnace # Furnace ladder to the fuse entrance @@ -1205,10 +1205,10 @@ def get_portal_info(portal_sd: str) -> (str, str): # Swamp to Gauntlet ("Swamp Mid", "Swamp Redux 2, Cathedral Arena_", - {"Ladders - Swamp"}), + {"Ladders in Swamp"}), # Swamp to Overworld upper ("Swamp Mid", "Swamp Redux 2, Overworld Redux_wall", - {"Ladders - Swamp"}), + {"Ladders in Swamp"}), # Ladder by the hero grave ("Back of Swamp", "Swamp Redux 2, Overworld Redux_conduit", set()), ("Back of Swamp", "Swamp Redux 2, Shop_", set()), @@ -1225,13 +1225,13 @@ def get_portal_info(portal_sd: str) -> (str, str): name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and has_ability(state, player, holy_cross, options, ability_unlocks) - and (has_ladder("Ladders - Swamp", state, player, options) or not options.entrance_rando)) + and (has_ladder("Ladders in Swamp", state, player, options) or not options.entrance_rando)) elif portal_name == "West Garden Exit after Boss" and not options.entrance_rando: regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and (state.has_any({"Ladders - To West Bell", "Ladder - Dark Tomb under Casket"}, player))) + and (state.has_any({"Ladders to West Bell", "Ladder in Dark Tomb"}, player))) # soft locked unless you have either ladder. if you have laurels, you use the other Entrance elif portal_name in {"Furnace Exit towards West Garden", "Furnace Exit to Dark Tomb"} \ and not options.entrance_rando: @@ -1239,7 +1239,7 @@ def get_portal_info(portal_sd: str) -> (str, str): regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and state.has_any({"Ladder - Dark Tomb under Casket", "Ladders - To West Bell"}, player)) + and state.has_any({"Ladder in Dark Tomb", "Ladders to West Bell"}, player)) # soft locked for the same reasons as above elif portal_name in {"Entrance to Furnace near West Garden", "West Garden Entrance from Furnace"} \ and not options.entrance_rando: @@ -1248,14 +1248,14 @@ def get_portal_info(portal_sd: str) -> (str, str): name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and state.has_any(ladders, player) - and state.has_any({"Ladder - Dark Tomb under Casket", "Ladders - To West Bell"}, player)) + and state.has_any({"Ladder in Dark Tomb", "Ladders to West Bell"}, player)) # soft locked if you can't get past garden knight backwards or up the belltower ladders elif portal_name == "West Garden Entrance near Belltower" and not options.entrance_rando: regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and state.has_any(ladders, player) - and state.has_any({"Ladders - To West Bell", laurels}, player)) + and state.has_any({"Ladders to West Bell", laurels}, player)) # soft lock potential elif portal_name in {"Special Shop Entrance", "Stairs to Top of the Mountain"} \ and not options.entrance_rando: diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 58e3651fb99a..1079b6cf00ea 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -144,28 +144,27 @@ class TunicItemData(NamedTuple): "Pages 52-53 (Icebolt)": TunicItemData(ItemClassification.progression, 1, 128, "pages"), "Pages 54-55": TunicItemData(ItemClassification.useful, 1, 129, "pages"), - "Ladders - Near Weathervane": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), - "Ladders - Overworld Shortcut": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), - "Ladder - Drop to East Forest": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), - "Ladders - To Lower Forest": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), - "Ladders - Near Patrol Cave": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), - "Ladder - To Well": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), - "Ladder - Back of Well": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), - "Ladders - To West Bell": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), - "Ladder - To Quarry": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), - "Ladder - Dark Tomb under Casket": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), - "Ladders - Near Dark Tomb": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), - "Ladder - Near Temple Rafters": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), - "Ladder - To Swamp": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), - "Ladders - Swamp": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), - "Ladder - To Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), - "Ladders - South Atoll": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), - "Ladders - To Frog's Domain": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), - "Ladders - Hourglass Cave": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), - "Ladders - Overworld Town": TunicItemData(ItemClassification.progression, 0, 148, "ladders"), - "Ladder - To Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 149, "ladders"), - "Ladders - Library": TunicItemData(ItemClassification.progression, 0, 150, "ladders"), - "Ladder - Lower Quarry": TunicItemData(ItemClassification.progression, 0, 151, "ladders") + "Ladders near Weathervane": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), + "Ladders near Overworld Checkpoint": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), + "Ladder to East Forest": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), + "Ladders to Lower Forest": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), + "Ladders near Patrol Cave": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), + "Ladders in Well": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), + "Ladders in Lower Quarry": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), + "Ladders to West Bell": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), + "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), + "Ladder in Dark Tomb": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), + "Ladders near Dark Tomb": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), + "Ladder near Temple Rafters": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), + "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), + "Ladders in Swamp": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), + "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), + "Ladders in South Atoll": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), + "Ladders to Frog's Domain": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), + "Ladders in Hourglass Cave": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), + "Ladders in Overworld Town": TunicItemData(ItemClassification.progression, 0, 148, "ladders"), + "Ladder to Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 149, "ladders"), + "Ladders in Library": TunicItemData(ItemClassification.progression, 0, 150, "ladders"), } fool_tiers: List[List[str]] = [ @@ -233,7 +232,7 @@ def get_item_group(item_name: str) -> str: "progressive sword": {"Sword Upgrade"}, "abilities": {"Pages 24-25 (Prayer)", "Pages 42-43 (Holy Cross)", "Pages 52-53 (Icebolt)"}, "questagons": {"Red Questagon", "Green Questagon", "Blue Questagon", "Gold Questagon"}, - "ladder - to atoll": {"Ladder - To Ruined Atoll"}, # fuzzy matching made it hint Ladder - To Well, now it won't + "ladder - to atoll": {"Ladder to Ruined Atoll"}, # fuzzy matching made it hint Ladders in Well, now it won't } item_name_groups.update(extra_groups) From deb6ba507d6db1d398aa16fd5aa5c79a25603cd9 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 22:17:31 -0400 Subject: [PATCH 60/82] Another edge case ls rule (why ls why) --- worlds/tunic/docs/en_TUNIC.md | 2 +- worlds/tunic/er_rules.py | 23 ++++++++++++++++++----- worlds/tunic/items.py | 3 ++- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/worlds/tunic/docs/en_TUNIC.md b/worlds/tunic/docs/en_TUNIC.md index ed0b31a9bbd1..3dc13ce13699 100644 --- a/worlds/tunic/docs/en_TUNIC.md +++ b/worlds/tunic/docs/en_TUNIC.md @@ -67,4 +67,4 @@ For the Entrance Randomizer: Bombs, consumables (non-bomb ones), weapons, melee weapons (stick and sword), keys, hexagons, offerings, hero relics, cards, golden treasures, money, pages, and abilities (the three ability pages). There are also a few groups being used for singular items: laurels, orb, dagger, magic rod, holy cross, prayer, icebolt, and progressive sword. ## What location groups are there? -Holy cross (for all holy cross checks), fairies (for the two fairy checks), well (for the coin well checks), shop, bosses (for the bosses with checks associated with them), and hero relic (for the 6 hero grave checks). +Holy cross (for all holy cross checks), fairies (for the two fairy checks), well (for the coin well checks), shop, bosses (for the bosses with checks associated with them), hero relic (for the 6 hero grave checks), and ladders (for the ladder items when you have shuffle ladders enabled). diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 5ec667b3bdf9..4c72f1d5a9c6 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1190,11 +1190,16 @@ def get_portal_info(portal_sd: str) -> (str, str): ("Fortress Exterior from East Forest", "Fortress Courtyard, Fortress East_", set()), # same as above, except from the Beneath the Vault entrance ladder - ("Fortress Exterior near cave", "Fortress Courtyard, Overworld Redux_", set()), - ("Fortress Exterior near cave", "Fortress Courtyard, Fortress Main_Big Door", set()), - ("Fortress Exterior near cave", "Fortress Courtyard, Fortress Reliquary_Lower", set()), - ("Fortress Exterior near cave", "Fortress Courtyard, Fortress Reliquary_Upper", set()), - ("Fortress Exterior near cave", "Fortress Courtyard, Fortress East_", set()), + ("Fortress Exterior near cave", "Fortress Courtyard, Overworld Redux_", + {"Ladder to Beneath the Vault"}), + ("Fortress Exterior near cave", "Fortress Courtyard, Fortress Main_Big Door", + {"Ladder to Beneath the Vault"}), + ("Fortress Exterior near cave", "Fortress Courtyard, Fortress Reliquary_Lower", + {"Ladder to Beneath the Vault"}), + ("Fortress Exterior near cave", "Fortress Courtyard, Fortress Reliquary_Upper", + {"Ladder to Beneath the Vault"}), + ("Fortress Exterior near cave", "Fortress Courtyard, Fortress East_", + {"Ladder to Beneath the Vault"}), # ls at the ladder, need to gain a little height to get up the stairs # excluded in non-ER due to soft lock potential @@ -1256,6 +1261,14 @@ def get_portal_info(portal_sd: str) -> (str, str): name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and state.has_any(ladders, player) and state.has_any({"Ladders to West Bell", laurels}, player)) + # soft locked if you can't get back out + elif portal_name == "Fortress Courtyard to Beneath the Vault" \ + and not options.entrance_rando and options.shuffle_ladders: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and state.has_all({ladder, "Ladder to Beneath the Vault"}, player)) # soft lock potential elif portal_name in {"Special Shop Entrance", "Stairs to Top of the Mountain"} \ and not options.entrance_rando: diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index 1079b6cf00ea..f336736436ce 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -232,7 +232,8 @@ def get_item_group(item_name: str) -> str: "progressive sword": {"Sword Upgrade"}, "abilities": {"Pages 24-25 (Prayer)", "Pages 42-43 (Holy Cross)", "Pages 52-53 (Icebolt)"}, "questagons": {"Red Questagon", "Green Questagon", "Blue Questagon", "Gold Questagon"}, - "ladder - to atoll": {"Ladder to Ruined Atoll"}, # fuzzy matching made it hint Ladders in Well, now it won't + "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"}, } item_name_groups.update(extra_groups) From 350f579aaaf7d2e024d46b24ec5970b2450347c1 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 23:10:32 -0400 Subject: [PATCH 61/82] Fix a few more edge cases --- worlds/tunic/er_data.py | 17 +++++++++-------- worlds/tunic/er_rules.py | 4 ++++ worlds/tunic/locations.py | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 217186a279fd..fb07170b9165 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -65,7 +65,7 @@ def destination_scene(self) -> str: # the vanilla connection destination="Archipelagos Redux", tag="_lowest"), Portal(name="Temple Door Entrance", region="Overworld Temple Door", destination="Temple", tag="_main"), - Portal(name="Temple Rafters Entrance", region="Upper Overworld", + Portal(name="Temple Rafters Entrance", region="Overworld after Temple Rafters", destination="Temple", tag="_rafters"), Portal(name="Ruined Shop Entrance", region="Overworld", destination="Ruined Shop", tag="_"), @@ -231,7 +231,7 @@ def destination_scene(self) -> str: # the vanilla connection Portal(name="Frog Stairs to Frog's Domain's Exit", region="Frog Stairs Lower", destination="frog cave main", tag="_Exit"), - Portal(name="Frog's Domain Ladder Exit", region="Frog's Domain", + Portal(name="Frog's Domain Ladder Exit", region="Frog's Domain Entry", destination="Frog Stairs", tag="_Entrance"), Portal(name="Frog's Domain Orb Exit", region="Frog's Domain Back", destination="Frog Stairs", tag="_Exit"), @@ -626,6 +626,7 @@ class DeadEnd(IntEnum): "Frog Stairs Upper": RegionInfo("Frog Stairs"), "Frog Stairs Lower": RegionInfo("Frog Stairs"), "Frog Stairs to Frog's Domain": RegionInfo("Frog Stairs"), + "Frog's Domain Entry": RegionInfo("frog cave main"), "Frog's Domain": RegionInfo("frog cave main"), "Frog's Domain Back": RegionInfo("frog cave main"), "Library Exterior Tree Region": RegionInfo("Library Exterior"), @@ -786,8 +787,8 @@ class DeadEnd(IntEnum): "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", "Frog's Domain Back"], + ("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"): @@ -903,8 +904,8 @@ class DeadEnd(IntEnum): "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", "Frog's Domain Back"], + ("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"): @@ -1023,8 +1024,8 @@ class DeadEnd(IntEnum): "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", "Frog's Domain Back"], + ("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"): diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 4c72f1d5a9c6..c8b069f7286b 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -582,6 +582,10 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Frog Stairs Lower"], rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + regions["Frog's Domain Entry"].connect( + connecting_region=regions["Frog's Domain"], + rule=lambda state: has_ladder("Ladders to Frog's Domain", state, player, options)) + regions["Frog's Domain"].connect( connecting_region=regions["Frog's Domain Back"], rule=lambda state: state.has(grapple, player)) diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index ff948286f77b..95c30b654cd8 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -143,7 +143,7 @@ class TunicLocationData(NamedTuple): "Overworld - [Southwest] Bombable Wall Near Fountain": TunicLocationData("Overworld", "Overworld"), "Overworld - [West] Chest After Bell": TunicLocationData("Overworld", "Overworld Belltower"), "Overworld - [Southwest] Tunnel Guarded By Turret": TunicLocationData("Overworld", "Overworld Tunnel Turret"), - "Overworld - [East] Between Ladders Near Ruined Passage": TunicLocationData("Overworld", "After Ruined Passage"), + "Overworld - [East] Between Ladders Near Ruined Passage": TunicLocationData("Overworld", "Above Ruined Passage"), "Overworld - [Northeast] Chest Above Patrol Cave": TunicLocationData("Overworld", "Upper Overworld"), "Overworld - [Southwest] Beach Chest Beneath Guard": TunicLocationData("Overworld", "Overworld Beach"), "Overworld - [Central] Chest Across From Well": TunicLocationData("Overworld", "Overworld"), From 99590a3ea5f87a12cb62bfef217f5c6df3d2e18a Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 23:39:57 -0400 Subject: [PATCH 62/82] maybe you shouldn't code when you're very tired? nahhhhh --- worlds/tunic/er_data.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index fb07170b9165..9a3eadfc0b16 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -793,10 +793,10 @@ class DeadEnd(IntEnum): ["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 Lab to Librarian"): - ["Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab", "Library Lab to Librarian"], - ("Library Lab", "Library Lab Lower", "Library Portal"): - ["Library Lab", "Library Lab Lower", "Library Portal"], + ("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"], @@ -910,10 +910,10 @@ class DeadEnd(IntEnum): ["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 Lab to Librarian"): - ["Library Rotunda to Hall", "Library Rotunda", "Library Rotunda to Lab", "Library Lab to Librarian"], - ("Library Lab", "Library Lab Lower", "Library Portal"): - ["Library Lab", "Library Lab Lower", "Library Portal"], + ("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", From 14a435c2b2fce60b721cfa36540d6737caeaad76 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 10 Mar 2024 23:52:44 -0400 Subject: [PATCH 63/82] what if we kissed on the roof of the library. haha, unless... --- worlds/tunic/er_rules.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index c8b069f7286b..8fe95d6557b6 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1454,7 +1454,8 @@ def set_er_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) lambda state: has_sword(state, player)) # nmg - kill Librarian with a lure, or gun I guess set_rule(multiworld.get_location("Librarian - Hexagon Green", player), - lambda state: has_sword(state, player) or options.logic_rules) + lambda state: (has_sword(state, player) or options.logic_rules) + and has_ladder("Ladders in Library", state, player, options)) # nmg - kill boss scav with orb + firecracker, or similar set_rule(multiworld.get_location("Rooted Ziggurat Lower - Hexagon Blue", player), lambda state: has_sword(state, player) or (state.has(grapple, player) and options.logic_rules)) From da719f5b4c95f847e680d7d6914b128d04339cd6 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Mon, 11 Mar 2024 08:10:45 -0400 Subject: [PATCH 64/82] so many little interactions between ER and ladders --- worlds/tunic/er_rules.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 8fe95d6557b6..5c259191e8cd 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -253,11 +253,11 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re connecting_region=regions["Overworld"], rule=lambda state: has_ladder("Ladder to Swamp", state, player, options)) - regions["Overworld"].connect( + regions["East Overworld"].connect( connecting_region=regions["Overworld Special Shop Entry"], rule=lambda state: state.has(laurels, player)) regions["Overworld Special Shop Entry"].connect( - connecting_region=regions["Overworld"], + connecting_region=regions["East Overworld"], rule=lambda state: state.has(laurels, player)) regions["Overworld"].connect( From 49ebdb5f1e0d99fdbfeabeca4c0d0277c77b6a33 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Mon, 11 Mar 2024 15:59:55 -0400 Subject: [PATCH 65/82] lmao we blocked the tiny library lab ladder --- worlds/tunic/er_rules.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 5c259191e8cd..011631956139 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -649,7 +649,9 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re rule=lambda state: has_ability(state, player, prayer, options, ability_unlocks) and has_ladder("Ladders in Library", state, player, options)) regions["Library Portal"].connect( - connecting_region=regions["Library Lab"]) + connecting_region=regions["Library Lab"], + rule=lambda state: has_ladder("Ladders in Library", state, player, options) + or state.has(laurels, player)) regions["Library Lab"].connect( connecting_region=regions["Library Lab to Librarian"], From 7e04b6b00b9e9f3258c6de9e1a69eeeff04c41dd Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 12 Mar 2024 08:45:08 -0400 Subject: [PATCH 66/82] incorrect region on a few locations --- worlds/tunic/locations.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/tunic/locations.py b/worlds/tunic/locations.py index 95c30b654cd8..4d95e91cb3cc 100644 --- a/worlds/tunic/locations.py +++ b/worlds/tunic/locations.py @@ -229,12 +229,12 @@ class TunicLocationData(NamedTuple): "Quarry - [West] Shooting Range Secret Path": TunicLocationData("Lower Quarry", "Lower Quarry"), "Quarry - [West] Near Shooting Range": TunicLocationData("Lower Quarry", "Lower Quarry"), "Quarry - [West] Below Shooting Range": TunicLocationData("Lower Quarry", "Lower Quarry"), - "Quarry - [Lowlands] Below Broken Ladder": TunicLocationData("Lower Quarry", "Lower Quarry"), + "Quarry - [Lowlands] Below Broken Ladder": TunicLocationData("Lower Quarry", "Even Lower Quarry"), "Quarry - [West] Upper Area Near Waterfall": TunicLocationData("Lower Quarry", "Lower Quarry"), - "Quarry - [Lowlands] Upper Walkway": TunicLocationData("Lower Quarry", "Lower Quarry"), + "Quarry - [Lowlands] Upper Walkway": TunicLocationData("Lower Quarry", "Even Lower Quarry"), "Quarry - [West] Lower Area Below Bridge": TunicLocationData("Lower Quarry", "Lower Quarry"), "Quarry - [West] Lower Area Isolated Chest": TunicLocationData("Lower Quarry", "Lower Quarry"), - "Quarry - [Lowlands] Near Elevator": TunicLocationData("Lower Quarry", "Lower Quarry"), + "Quarry - [Lowlands] Near Elevator": TunicLocationData("Lower Quarry", "Even Lower Quarry"), "Quarry - [West] Lower Area After Bridge": TunicLocationData("Lower Quarry", "Lower Quarry"), "Rooted Ziggurat Upper - Near Bridge Switch": TunicLocationData("Rooted Ziggurat", "Rooted Ziggurat Upper Front"), "Rooted Ziggurat Upper - Beneath Bridge To Administrator": TunicLocationData("Rooted Ziggurat", "Rooted Ziggurat Upper Back"), From 943955dc339860eefbf8bb5f540376987c6772c9 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 12 Mar 2024 09:55:37 -0400 Subject: [PATCH 67/82] Updating a few comments --- worlds/tunic/er_data.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/worlds/tunic/er_data.py b/worlds/tunic/er_data.py index 9a3eadfc0b16..c4552441e24c 100644 --- a/worlds/tunic/er_data.py +++ b/worlds/tunic/er_data.py @@ -527,38 +527,38 @@ class DeadEnd(IntEnum): # key is the AP region name. "Fake" in region info just means the mod won't receive that info at all tunic_er_regions: Dict[str, RegionInfo] = { "Menu": RegionInfo("Fake", dead_end=DeadEnd.all_cats), - "Overworld": RegionInfo("Overworld Redux"), - "Overworld Holy Cross": RegionInfo("Fake", dead_end=DeadEnd.all_cats), + "Overworld": RegionInfo("Overworld Redux"), # main overworld, the central area + "Overworld Holy Cross": RegionInfo("Fake", dead_end=DeadEnd.all_cats), # main overworld holy cross checks "Overworld Belltower": RegionInfo("Overworld Redux"), # the area with the belltower and chest - "Overworld Belltower at Bell": RegionInfo("Overworld Redux"), # the belltower itself, being able to ring it + "Overworld Belltower at Bell": RegionInfo("Overworld Redux"), # being able to ring the belltower, basically "Overworld Swamp Upper Entry": RegionInfo("Overworld Redux"), # upper swamp entry spot - "Overworld Swamp Lower Entry": RegionInfo("Overworld Redux"), # lower swamp entrance, rotating lights + "Overworld Swamp Lower Entry": RegionInfo("Overworld Redux"), # lower swamp entrance, rotating lights entrance "After Ruined Passage": RegionInfo("Overworld Redux"), # just the door and chest - "Above Ruined Passage": RegionInfo("Overworld Redux"), # one ladder up, just the chest in the trees + "Above Ruined Passage": RegionInfo("Overworld Redux"), # one ladder up from ruined passage "East Overworld": RegionInfo("Overworld Redux"), # where the east forest and fortress entrances are "Overworld Special Shop Entry": RegionInfo("Overworld Redux"), # special shop entry spot "Upper Overworld": RegionInfo("Overworld Redux"), # where the mountain stairs are "Overworld above Quarry Entrance": RegionInfo("Overworld Redux"), # top of the ladder where the chest is - "Overworld after Temple Rafters": RegionInfo("Overworld Redux"), # the ledge after the rafter exit, before ladder - "Overworld Quarry Entry": RegionInfo("Overworld Redux"), # at the top of the ladder to darkwoods - "Overworld after Envoy": RegionInfo("Overworld Redux"), # after the envoy on the bridge to quarry - "Overworld above Patrol Cave": RegionInfo("Overworld Redux"), # where the hook is, and one ladder up from patrol + "Overworld after Temple Rafters": RegionInfo("Overworld Redux"), # the ledge after the rafters exit, before ladder + "Overworld Quarry Entry": RegionInfo("Overworld Redux"), # at the top of the ladder, to darkwoods + "Overworld after Envoy": RegionInfo("Overworld Redux"), # after the envoy on the thin bridge to quarry "Overworld at Patrol Cave": RegionInfo("Overworld Redux"), # right at the patrol cave entrance + "Overworld above Patrol Cave": RegionInfo("Overworld Redux"), # where the hook is, and one ladder up from patrol "Overworld West Garden Laurels Entry": RegionInfo("Overworld Redux"), # west garden laurels entry "Overworld to West Garden Upper": RegionInfo("Overworld Redux"), # usually leads to garden knight - "Overworld to West Garden from Furnace": RegionInfo("Overworld Redux"), - "Overworld Well Ladder": RegionInfo("Overworld Redux"), # just the ladder entrance - "Overworld Beach": RegionInfo("Overworld Redux"), - "Overworld to Atoll Upper": RegionInfo("Overworld Redux"), - "Overworld Well to Furnace Rail": RegionInfo("Overworld Redux"), # the tiny rail passageway + "Overworld to West Garden from Furnace": RegionInfo("Overworld Redux"), # isolated stairway with one chest + "Overworld Well Ladder": RegionInfo("Overworld Redux"), # just the ladder entrance itself as a region + "Overworld Beach": RegionInfo("Overworld Redux"), # from the two turrets to invisble maze, and lower atoll entry + "Overworld Tunnel Turret": RegionInfo("Overworld Redux"), # the tunnel turret by the southwest beach ladder + "Overworld to Atoll Upper": RegionInfo("Overworld Redux"), # the little ledge before the ladder + "Overworld Well to Furnace Rail": RegionInfo("Overworld Redux"), # the rail hallway, bane of unrestricted logic "Overworld Ruined Passage Door": RegionInfo("Overworld Redux"), # the small space betweeen the door and the portal "Overworld Old House Door": RegionInfo("Overworld Redux"), # the too-small space between the door and the portal "Overworld Southeast Cross Door": RegionInfo("Overworld Redux"), # the small space betweeen the door and the portal - "Overworld Fountain Cross Door": RegionInfo("Overworld Redux"), + "Overworld Fountain Cross Door": RegionInfo("Overworld Redux"), # the small space between the door and the portal "Overworld Temple Door": RegionInfo("Overworld Redux"), # the small space betweeen the door and the portal - "Overworld Town Portal": RegionInfo("Overworld Redux"), - "Overworld Spawn Portal": RegionInfo("Overworld Redux"), - "Overworld Tunnel Turret": RegionInfo("Overworld Redux"), # the tunnel turret by the southwest beach ladder + "Overworld Town Portal": RegionInfo("Overworld Redux"), # being able to go to or come from the portal + "Overworld Spawn Portal": RegionInfo("Overworld Redux"), # being able to go to or come from the portal "Stick House": RegionInfo("Sword Cave", dead_end=DeadEnd.all_cats), "Windmill": RegionInfo("Windmill"), "Old House Back": RegionInfo("Overworld Interiors"), # part with the hc door @@ -602,8 +602,8 @@ class DeadEnd(IntEnum): "Dark Tomb Upper": RegionInfo("Crypt Redux"), # the part with the casket and the top of the ladder "Dark Tomb Main": RegionInfo("Crypt Redux"), "Dark Tomb Dark Exit": RegionInfo("Crypt Redux"), - "Dark Tomb Checkpoint": RegionInfo("Sewer_Boss"), # can laurels backwards - "Well Boss": RegionInfo("Sewer_Boss"), # can walk through (with bombs at least) + "Dark Tomb Checkpoint": RegionInfo("Sewer_Boss"), + "Well Boss": RegionInfo("Sewer_Boss"), "Beneath the Well Ladder Exit": RegionInfo("Sewer"), # just the ladder "Beneath the Well Front": RegionInfo("Sewer"), # the front, to separate it from the weapon requirement in the mid "Beneath the Well Main": RegionInfo("Sewer"), # the main section of it, requires a weapon From c0433d049345255236fc05dbfe1a44e716e22169 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Tue, 12 Mar 2024 14:23:41 -0400 Subject: [PATCH 68/82] Reorder ladder item IDs --- worlds/tunic/items.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/worlds/tunic/items.py b/worlds/tunic/items.py index f336736436ce..7483d55bf1cc 100644 --- a/worlds/tunic/items.py +++ b/worlds/tunic/items.py @@ -143,28 +143,28 @@ class TunicItemData(NamedTuple): "Pages 50-51": TunicItemData(ItemClassification.useful, 1, 127, "pages"), "Pages 52-53 (Icebolt)": TunicItemData(ItemClassification.progression, 1, 128, "pages"), "Pages 54-55": TunicItemData(ItemClassification.useful, 1, 129, "pages"), - + "Ladders near Weathervane": TunicItemData(ItemClassification.progression, 0, 130, "ladders"), "Ladders near Overworld Checkpoint": TunicItemData(ItemClassification.progression, 0, 131, "ladders"), - "Ladder to East Forest": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), - "Ladders to Lower Forest": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), - "Ladders near Patrol Cave": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), - "Ladders in Well": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), - "Ladders in Lower Quarry": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), - "Ladders to West Bell": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), - "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), - "Ladder in Dark Tomb": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), - "Ladders near Dark Tomb": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), - "Ladder near Temple Rafters": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), - "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), - "Ladders in Swamp": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), - "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), - "Ladders in South Atoll": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), - "Ladders to Frog's Domain": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), - "Ladders in Hourglass Cave": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), - "Ladders in Overworld Town": TunicItemData(ItemClassification.progression, 0, 148, "ladders"), - "Ladder to Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 149, "ladders"), - "Ladders in Library": TunicItemData(ItemClassification.progression, 0, 150, "ladders"), + "Ladders near Patrol Cave": TunicItemData(ItemClassification.progression, 0, 132, "ladders"), + "Ladder near Temple Rafters": TunicItemData(ItemClassification.progression, 0, 133, "ladders"), + "Ladders near Dark Tomb": TunicItemData(ItemClassification.progression, 0, 134, "ladders"), + "Ladder to Quarry": TunicItemData(ItemClassification.progression, 0, 135, "ladders"), + "Ladders to West Bell": TunicItemData(ItemClassification.progression, 0, 136, "ladders"), + "Ladders in Overworld Town": TunicItemData(ItemClassification.progression, 0, 137, "ladders"), + "Ladder to Ruined Atoll": TunicItemData(ItemClassification.progression, 0, 138, "ladders"), + "Ladder to Swamp": TunicItemData(ItemClassification.progression, 0, 139, "ladders"), + "Ladders in Well": TunicItemData(ItemClassification.progression, 0, 140, "ladders"), + "Ladder in Dark Tomb": TunicItemData(ItemClassification.progression, 0, 141, "ladders"), + "Ladder to East Forest": TunicItemData(ItemClassification.progression, 0, 142, "ladders"), + "Ladders to Lower Forest": TunicItemData(ItemClassification.progression, 0, 143, "ladders"), + "Ladder to Beneath the Vault": TunicItemData(ItemClassification.progression, 0, 144, "ladders"), + "Ladders in Hourglass Cave": TunicItemData(ItemClassification.progression, 0, 145, "ladders"), + "Ladders in South Atoll": TunicItemData(ItemClassification.progression, 0, 146, "ladders"), + "Ladders to Frog's Domain": TunicItemData(ItemClassification.progression, 0, 147, "ladders"), + "Ladders in Library": TunicItemData(ItemClassification.progression, 0, 148, "ladders"), + "Ladders in Lower Quarry": TunicItemData(ItemClassification.progression, 0, 149, "ladders"), + "Ladders in Swamp": TunicItemData(ItemClassification.progression, 0, 150, "ladders"), } fool_tiers: List[List[str]] = [ From 66d506f757c745e6f2a96f4210dd778b8f2b2468 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Thu, 14 Mar 2024 16:07:33 -0400 Subject: [PATCH 69/82] Add sword 4 can get you past envoy rule For going to quarry in ER/Ladder rando --- worlds/tunic/er_rules.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 011631956139..5869b05424ae 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -219,10 +219,14 @@ def set_er_region_rules(world: "TunicWorld", ability_unlocks: Dict[str, int], re regions["Overworld"].connect( connecting_region=regions["Overworld after Envoy"], - rule=lambda state: state.has_any({laurels, grapple}, player) or options.logic_rules) + rule=lambda state: state.has_any({laurels, grapple}, player) + or state.has("Sword Upgrade", player, 4) + or options.logic_rules) regions["Overworld after Envoy"].connect( connecting_region=regions["Overworld"], - rule=lambda state: state.has_any({laurels, grapple}, player) or options.logic_rules) + rule=lambda state: state.has_any({laurels, grapple}, player) + or state.has("Sword Upgrade", player, 4) + or options.logic_rules) regions["Overworld after Envoy"].connect( connecting_region=regions["Overworld Quarry Entry"], From adf06388d635afbd7b113b316f3923c1a1b88530 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 15 Mar 2024 08:04:11 -0400 Subject: [PATCH 70/82] Remove debug print --- worlds/tunic/er_scripts.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 3307cbafb3a5..91a814a2008a 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -112,9 +112,6 @@ def vanilla_portals() -> Dict[Portal, Portal]: portal_pairs[portal1] = portal2 portal_map.remove(portal1) if not portal2_sdt.startswith("Shop,"): - if portal2 not in portal_map: - print(portal1.scene_destination()) - print(portal1.destination_scene()) portal_map.remove(portal2) return portal_pairs From c2f2dd216b4c1bd0ab888c7d4d087ca9babc1266 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 15 Mar 2024 09:45:18 -0400 Subject: [PATCH 71/82] Change a few lists to sets to be slightly faster --- worlds/tunic/er_scripts.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 91a814a2008a..a7332831d9e4 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -320,7 +320,7 @@ def create_randomized_entrances(portal_pairs: Dict[Portal, Portal], regions: Dic region2 = regions[portal2.region] region1.connect(connecting_region=region2, name=portal1.name) # prevent the logic from thinking you can get to any shop-connected region from the shop - if portal2.name not in ["Shop", "Shop Portal"]: + if portal2.name not in {"Shop", "Shop Portal"}: region2.connect(connecting_region=region1, name=portal2.name) @@ -372,8 +372,8 @@ def gate_before_switch(check_portal: Portal, two_plus: List[Portal]) -> bool: 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"]: + 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": @@ -390,8 +390,8 @@ def gate_before_switch(check_portal: Portal, two_plus: List[Portal]) -> bool: 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"]: + if portal.region in {"Swamp Front", "Swamp to Cathedral Treasure Room", + "Swamp to Cathedral Main Entrance Region"}: i += 1 if i == 4: return True @@ -407,8 +407,8 @@ def gate_before_switch(check_portal: Portal, two_plus: List[Portal]) -> bool: # 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_"]: + 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": From 7d6b68126759ab5a401517f61f66efe5d2b3f800 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 15 Mar 2024 13:14:31 -0400 Subject: [PATCH 72/82] Fix missing tags --- worlds/tunic/er_scripts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 3323787029ff..11069253c4eb 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -228,7 +228,7 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: break if p_exit in ["Shop Portal", "Shop"]: portal2 = Portal(name="Shop Portal", region=f"Shop", - destination="Previous Region_") + destination="Previous Region", tag="_") shop_count -= 1 if shop_count < 0: shop_count += 2 @@ -373,7 +373,7 @@ def pair_portals(world: "TunicWorld") -> Dict[Portal, Portal]: break if portal1 is None: raise Exception("Too many shops in the pool, or something else went wrong.") - portal2 = Portal(name="Shop Portal", region="Shop", destination="Previous Region_") + portal2 = Portal(name="Shop Portal", region="Shop", destination="Previous Region", tag="_") portal_pairs[portal1] = portal2 From 3de0214e326478d33f717df7b9101f8e0ace6e03 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 15 Mar 2024 13:59:48 -0400 Subject: [PATCH 73/82] Fix portal region name --- worlds/tunic/er_scripts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/er_scripts.py b/worlds/tunic/er_scripts.py index 11069253c4eb..5756ec90be14 100644 --- a/worlds/tunic/er_scripts.py +++ b/worlds/tunic/er_scripts.py @@ -98,7 +98,7 @@ def vanilla_portals() -> Dict[Portal, Portal]: portal2_sdt = portal1.destination_scene() if portal2_sdt.startswith("Shop,"): - portal2 = Portal(name=f"Shop", region=f"Shop Entrance {shop_num}", + portal2 = Portal(name=f"Shop", region="Shop", destination="Previous Region", tag="_") shop_num += 1 From cc1d1ebf117ebf1dbaa33df015cbcf3d6ee5b7a0 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 15 Mar 2024 21:41:35 -0400 Subject: [PATCH 74/82] Un-pep8 option descriptions so the new lines don't make it look stupid on the webhost --- worlds/tunic/options.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index 89fdb0291e74..608c7714c65d 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -4,8 +4,7 @@ class SwordProgression(DefaultOnToggle): - """Adds four sword upgrades to the item pool that will progressively grant stronger melee weapons, including two new - swords with increased range and attack power.""" + """Adds four sword upgrades to the item pool that will progressively grant stronger melee weapons, including two new swords with increased range and attack power.""" internal_name = "sword_progression" display_name = "Sword Progression" @@ -24,10 +23,8 @@ class KeysBehindBosses(Toggle): class AbilityShuffling(Toggle): """Locks the usage of Prayer, Holy Cross*, and the Icebolt combo until the relevant pages of the manual have been found. - If playing Hexagon Quest, abilities are instead randomly unlocked after obtaining 25%, 50%, and 75% of the required - Hexagon goal amount. - *Certain Holy Cross usages are still allowed, such as the free bomb codes, the seeking spell, and other - player-facing codes. + If playing Hexagon Quest, abilities are instead randomly unlocked after obtaining 25%, 50%, and 75% of the required Hexagon goal amount. + *Certain Holy Cross usages are still allowed, such as the free bomb codes, the seeking spell, and other player-facing codes. """ internal_name = "ability_shuffling" display_name = "Shuffle Abilities" @@ -41,8 +38,7 @@ class LogicRules(Choice): Unrestricted: Logic in No Major Glitches, as well as ladder storage to get to certain places early. *Special Shop is not in logic without the Hero's Laurels due to soft lock potential. *Using Ladder Storage to get to individual chests is not in logic to avoid tedium. - *Getting knocked out of the air by enemies during Ladder Storage to reach places is not in logic, except for in - Rooted Ziggurat Lower. This is so you're not punished for playing with enemy rando on.""" + *Getting knocked out of the air by enemies during Ladder Storage to reach places is not in logic, except for in Rooted Ziggurat Lower. This is so you're not punished for playing with enemy rando on.""" internal_name = "logic_rules" display_name = "Logic Rules" option_restricted = 0 @@ -68,8 +64,7 @@ class Maskless(Toggle): class FoolTraps(Choice): - """Replaces low-to-medium value money rewards in the item pool with fool traps, which cause random negative - effects to the player.""" + """Replaces low-to-medium value money rewards in the item pool with fool traps, which cause random negative effects to the player.""" internal_name = "fool_traps" display_name = "Fool Traps" option_off = 0 @@ -80,8 +75,7 @@ class FoolTraps(Choice): class HexagonQuest(Toggle): - """An alternate goal that shuffles Gold "Questagon" items into the item pool and allows the game to be completed - after collecting the required number of them.""" + """An alternate goal that shuffles Gold "Questagon" items into the item pool and allows the game to be completed after collecting the required number of them.""" internal_name = "hexagon_quest" display_name = "Hexagon Quest" From 37868499b36d873658988cd312e908ddb1caf356 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 15 Mar 2024 22:45:30 -0400 Subject: [PATCH 75/82] Add more ladder storage logic, deplete brain cells --- worlds/tunic/er_rules.py | 42 +++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index aed9f92f05bb..9df1d45a57ed 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1229,7 +1229,7 @@ def get_portal_info(portal_sd: str) -> (str, str): regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and (state.has_any({"Ladders to West Bell", "Ladder in Dark Tomb"}, player))) + and (state.has("Ladders to West Bell", player))) # soft locked unless you have either ladder. if you have laurels, you use the other Entrance elif portal_name in {"Furnace Exit towards West Garden", "Furnace Exit to Dark Tomb"} \ and not options.entrance_rando: @@ -1255,20 +1255,44 @@ def get_portal_info(portal_sd: str) -> (str, str): rule=lambda state: has_stick(state, player) and state.has_any(ladders, player) and state.has_any({"Ladders to West Bell", laurels}, player)) # soft locked if you can't get back out - elif portal_name == "Fortress Courtyard to Beneath the Vault" \ - and not options.entrance_rando and options.shuffle_ladders: + elif portal_name == "Fortress Courtyard to Beneath the Vault" and not options.entrance_rando: regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and state.has_all({ladder, "Ladder to Beneath the Vault"}, player)) + and state.has_all({ladder, "Ladder to Beneath the Vault"}, player) + and has_lantern(state, player, options)) + elif portal_name == "Atoll Lower Entrance" and not options.entrance_rando: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and state.has_any({"Ladders in Overworld Town", grapple}, player)) + elif portal_name == "Atoll Upper Entrance" and not options.entrance_rando: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and state.has(grapple, player) or has_ability(state, player, prayer, options, ability_unlocks)) # soft lock potential - elif portal_name in {"Special Shop Entrance", "Stairs to Top of the Mountain"} \ - and not options.entrance_rando: - continue - # soft lock if you don't have the ladder, just exclude it for simplicity - elif portal_name == "Temple Rafters Entrance" and not options.entrance_rando and options.shuffle_ladders: + elif portal_name in {"Special Shop Entrance", "Stairs to Top of the Mountain", "Swamp Upper Entrance", + "Swamp Lower Entrance", "Caustic Light Cave Entrance"} and not options.entrance_rando: continue + # soft lock if you don't have the ladder, I regret writing unrestricted logic + elif portal_name == "Temple Rafters Entrance" and not options.entrance_rando: + regions[region_name].connect( + regions[paired_region], + name=portal_name + " (LS) " + region_name, + rule=lambda state: has_stick(state, player) + and state.has(ladder, player) + and (state.has("Ladder near Temple Rafters", player) + or (state.has_all({laurels, grapple}, player) + and ((state.has("Ladders near Patrol Cave", player) + and (state.has("Ladders near Dark Tomb", player) + or state.has("Ladder to Quarry", player) + and (state.has(fire_wand, player) or has_sword(state, player)))) + or state.has("Ladders near Overworld Checkpoint", player) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks))))) # if no ladder items are required, just do the basic stick only lambda elif not ladders or not options.shuffle_ladders: regions[region_name].connect( From 2d3138bac79a70be1f12b1210a9ef47351c83f3f Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 15 Mar 2024 23:02:28 -0400 Subject: [PATCH 76/82] ladders ladders ladders ladders --- worlds/tunic/er_rules.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 9df1d45a57ed..6b5cc11f16a6 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1217,7 +1217,7 @@ def get_portal_info(portal_sd: str) -> (str, str): for region_name, scene_dest, ladders in ladder_storages: portal_name, paired_region = get_portal_info(scene_dest) # this is the only exception, requiring holy cross as well - if portal_name == "Swamp to Cathedral Secret Legend Room Entrance": + if portal_name == "Swamp to Cathedral Secret Legend Room Entrance" and region_name == "Back of Swamp": regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, @@ -1229,6 +1229,7 @@ def get_portal_info(portal_sd: str) -> (str, str): regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) + and state.has_any(ladders, player) and (state.has("Ladders to West Bell", player))) # soft locked unless you have either ladder. if you have laurels, you use the other Entrance elif portal_name in {"Furnace Exit towards West Garden", "Furnace Exit to Dark Tomb"} \ @@ -1260,19 +1261,21 @@ def get_portal_info(portal_sd: str) -> (str, str): regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and state.has_all({ladder, "Ladder to Beneath the Vault"}, player) + and state.has("Ladder to Beneath the Vault", player) and has_lantern(state, player, options)) elif portal_name == "Atoll Lower Entrance" and not options.entrance_rando: regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) + and state.has_any(ladders, player) and state.has_any({"Ladders in Overworld Town", grapple}, player)) elif portal_name == "Atoll Upper Entrance" and not options.entrance_rando: regions[region_name].connect( regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) + and state.has_any(ladders, player) and state.has(grapple, player) or has_ability(state, player, prayer, options, ability_unlocks)) # soft lock potential elif portal_name in {"Special Shop Entrance", "Stairs to Top of the Mountain", "Swamp Upper Entrance", @@ -1284,7 +1287,7 @@ def get_portal_info(portal_sd: str) -> (str, str): regions[paired_region], name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) - and state.has(ladder, player) + and state.has_any(ladders, player) and (state.has("Ladder near Temple Rafters", player) or (state.has_all({laurels, grapple}, player) and ((state.has("Ladders near Patrol Cave", player) From 6bdd00fee22e55098f8a543aefad752550017449 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Fri, 15 Mar 2024 23:08:38 -0400 Subject: [PATCH 77/82] ice grapples are nice grapples (no they aren't) --- worlds/tunic/er_rules.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 6b5cc11f16a6..05d839e7a3bf 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1223,7 +1223,9 @@ def get_portal_info(portal_sd: str) -> (str, str): name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and has_ability(state, player, holy_cross, options, ability_unlocks) - and (has_ladder("Ladders in Swamp", state, player, options) or not options.entrance_rando)) + and (has_ladder("Ladders in Swamp", state, player, options) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks) + or not options.entrance_rando)) elif portal_name == "West Garden Exit after Boss" and not options.entrance_rando: regions[region_name].connect( regions[paired_region], @@ -1269,7 +1271,8 @@ def get_portal_info(portal_sd: str) -> (str, str): name=portal_name + " (LS) " + region_name, rule=lambda state: has_stick(state, player) and state.has_any(ladders, player) - and state.has_any({"Ladders in Overworld Town", grapple}, player)) + and (state.has_any({"Ladders in Overworld Town", grapple}, player) + or has_ice_grapple_logic(True, state, player, options, ability_unlocks))) elif portal_name == "Atoll Upper Entrance" and not options.entrance_rando: regions[region_name].connect( regions[paired_region], From 92c22dbc68e0948221a28da152d1a5d42829ef92 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sat, 16 Mar 2024 21:53:53 -0400 Subject: [PATCH 78/82] Change entrance_rando value in slot_data to an int(bool(value)) so it stays consistent on the mod-side --- worlds/tunic/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/__init__.py b/worlds/tunic/__init__.py index 54a793bb5c83..3220c6c9347d 100644 --- a/worlds/tunic/__init__.py +++ b/worlds/tunic/__init__.py @@ -271,7 +271,7 @@ def fill_slot_data(self) -> Dict[str, Any]: "logic_rules": self.options.logic_rules.value, "lanternless": self.options.lanternless.value, "maskless": self.options.maskless.value, - "entrance_rando": bool(self.options.entrance_rando.value), + "entrance_rando": int(bool(self.options.entrance_rando.value)), "shuffle_ladders": self.options.shuffle_ladders.value, "Hexagon Quest Prayer": self.ability_unlocks["Pages 24-25 (Prayer)"], "Hexagon Quest Holy Cross": self.ability_unlocks["Pages 42-43 (Holy Cross)"], From d214b9c48c4a5a046e2b153efe7e74a458e40959 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 17 Mar 2024 11:03:46 -0400 Subject: [PATCH 79/82] Remove a rule on a chest that we felt didn't really need to be there --- worlds/tunic/er_rules.py | 2 -- worlds/tunic/rules.py | 2 -- 2 files changed, 4 deletions(-) diff --git a/worlds/tunic/er_rules.py b/worlds/tunic/er_rules.py index 05d839e7a3bf..fdfd064561fe 100644 --- a/worlds/tunic/er_rules.py +++ b/worlds/tunic/er_rules.py @@ -1489,8 +1489,6 @@ def set_er_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) # these two swamp checks really want you to kill the big skeleton first set_rule(multiworld.get_location("Swamp - [South Graveyard] 4 Orange Skulls", player), lambda state: has_sword(state, player)) - set_rule(multiworld.get_location("Swamp - [South Graveyard] Guarded By Tentacles", player), - lambda state: has_sword(state, player)) # Hero's Grave and Far Shore set_rule(multiworld.get_location("Hero's Grave - Tooth Relic", player), diff --git a/worlds/tunic/rules.py b/worlds/tunic/rules.py index 890d0b226ef7..c82c5ca13339 100644 --- a/worlds/tunic/rules.py +++ b/worlds/tunic/rules.py @@ -320,8 +320,6 @@ def set_location_rules(world: "TunicWorld", ability_unlocks: Dict[str, int]) -> lambda state: state.has(laurels, player)) set_rule(multiworld.get_location("Swamp - [South Graveyard] 4 Orange Skulls", player), lambda state: has_sword(state, player)) - set_rule(multiworld.get_location("Swamp - [South Graveyard] Guarded By Tentacles", player), - lambda state: has_sword(state, player)) # Hero's Grave set_rule(multiworld.get_location("Hero's Grave - Tooth Relic", player), From 0d5a67d1255ec843536109046a2f7e58561882d4 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Sun, 17 Mar 2024 19:28:59 -0400 Subject: [PATCH 80/82] Update logicrules option description --- worlds/tunic/options.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index 608c7714c65d..ea3956402785 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -31,14 +31,16 @@ class AbilityShuffling(Toggle): class LogicRules(Choice): - """Set which logic rules to use for your world. + """ + Set which logic rules to use for your world. Restricted: Standard logic, no glitches. No Major Glitches: Sneaky Laurels zips, ice grapples through doors, shooting the west bell, and boss quick kills are included in logic. * Ice grappling through the Ziggurat door is not in logic since you will get stuck in there without Prayer. Unrestricted: Logic in No Major Glitches, as well as ladder storage to get to certain places early. - *Special Shop is not in logic without the Hero's Laurels due to soft lock potential. + *Torch is given to the player at the start of the game due to the high softlock potential with various tricks. Using the torch is not required in logic. *Using Ladder Storage to get to individual chests is not in logic to avoid tedium. - *Getting knocked out of the air by enemies during Ladder Storage to reach places is not in logic, except for in Rooted Ziggurat Lower. This is so you're not punished for playing with enemy rando on.""" + *Getting knocked out of the air by enemies during Ladder Storage to reach places is not in logic, except for in Rooted Ziggurat Lower. This is so you're not punished for playing with enemy rando on. + """ internal_name = "logic_rules" display_name = "Logic Rules" option_restricted = 0 From 4745ccc62cc0ac8bbe429bbbfe9537e03be2d38f Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Mon, 18 Mar 2024 09:42:57 -0400 Subject: [PATCH 81/82] Update entrance rando option description for clarity --- worlds/tunic/options.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index ea3956402785..fc8ac1b331d0 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -102,7 +102,7 @@ class ExtraHexagonPercentage(Range): class EntranceRando(TextChoice): """Randomize the connections between scenes. - You can choose a custom seed by editing this option. + You can choose a custom seed by changing this option's value. A small, very lost fox on a big adventure.""" internal_name = "entrance_rando" display_name = "Entrance Rando" From 29badc9d3d249c1d4a76612e82c01b0f135fe7c8 Mon Sep 17 00:00:00 2001 From: Scipio Wright Date: Mon, 18 Mar 2024 09:48:22 -0400 Subject: [PATCH 82/82] Update entrance rando option description again --- worlds/tunic/options.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/worlds/tunic/options.py b/worlds/tunic/options.py index fc8ac1b331d0..38ddcbe8e40f 100644 --- a/worlds/tunic/options.py +++ b/worlds/tunic/options.py @@ -101,9 +101,11 @@ class ExtraHexagonPercentage(Range): class EntranceRando(TextChoice): - """Randomize the connections between scenes. - You can choose a custom seed by changing this option's value. - A small, very lost fox on a big adventure.""" + """ + Randomize the connections between scenes. + If you set this to a value besides true or false, that value will be used as a custom seed. + A small, very lost fox on a big adventure. + """ internal_name = "entrance_rando" display_name = "Entrance Rando" alias_false = 0