From d4423da5104d9d0f00a46736686137162c3561f4 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Sat, 25 Oct 2025 19:35:31 -0400 Subject: [PATCH 01/22] Dungeon Boss Entrance Rando --- worlds/oot_soh/EntranceShuffle.py | 59 +++++++++++++++++ worlds/oot_soh/Enums.py | 55 ++++++++++++++++ worlds/oot_soh/LogicHelpers.py | 18 ++++-- worlds/oot_soh/Options.py | 63 +++++++++++++++---- worlds/oot_soh/__init__.py | 53 ++++++++++++++-- .../location_access/dungeons/deku_tree.py | 2 +- .../dungeons/dodongos_cavern.py | 5 +- .../location_access/dungeons/fire_temple.py | 2 +- .../location_access/dungeons/forest_temple.py | 3 +- .../dungeons/jabujabus_belly.py | 2 +- .../location_access/dungeons/shadow_temple.py | 2 +- .../location_access/dungeons/spirit_temple.py | 3 +- .../location_access/dungeons/water_temple.py | 3 +- 13 files changed, 239 insertions(+), 31 deletions(-) create mode 100644 worlds/oot_soh/EntranceShuffle.py diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py new file mode 100644 index 000000000000..91018e0609fc --- /dev/null +++ b/worlds/oot_soh/EntranceShuffle.py @@ -0,0 +1,59 @@ +from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames # , Ages, Regions +# from entrance_rando import ERPlacementState, Entrance +# from . import RegionAgeAccess + +# Pretty sure this is only needed for One Way entrances +entrance_matching = { + SOHBossEntranceNames.DEKU_TREE_BOSS_ENTRANCE: SOHBossEntranceExitNames.DEKU_TREE_BOSS_EXIT, + SOHBossEntranceNames.DODONGOS_CAVERN_BOSS_ENTRANCE: SOHBossEntranceExitNames.DODONGOS_CAVERN_BOSS_EXIT, + SOHBossEntranceNames.JABU_JABUS_BOSS_ENTRANCE: SOHBossEntranceExitNames.JABU_JABUS_BOSS_EXIT, + SOHBossEntranceNames.FOREST_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.FOREST_TEMPLE_BOSS_EXIT, + SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.FIRE_TEMPLE_BOSS_EXIT, + SOHBossEntranceNames.WATER_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.WATER_TEMPLE_BOSS_EXIT, + SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SHADOW_TEMPLE_BOSS_EXIT, + SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SPIRIT_TEMPLE_BOSS_EXIT, +} + + +# special_entrance_requirements = { +# SOHBossEntranceExitNames.JABU_JABUS_BOSS_EXIT.value: Ages.CHILD, +# SOHBossEntranceExitNames.WATER_TEMPLE_BOSS_EXIT.value: Ages.ADULT +# } + +# Couldn't get this to work. I instead opted for more groups that intermingle. I feel like this could work though. +# Two issues: +# 1. At this point no items have been collected so our age logic always returns false. +# 2. I was having a hard time +# def soh_oot_on_connect(er_state: ERPlacementState, placed_exits: list[Entrance], paired_entrances: list[Entrance]) -> bool: + +# updated: bool = False +# index: int = 0 +# regions_dict = {i.value: i for i in Regions} + +# for _ in paired_entrances: +# print( +# f"Entrance:{paired_entrances[index].name} | Exit Region: {placed_exits[index].connected_region.name}") +# if paired_entrances[index].name in special_entrance_requirements: + +# if er_state.collection_state._soh_can_reach_as_age(regions_dict.get(placed_exits[index].connected_region.name), special_entrance_requirements[paired_entrances[index].name], er_state.world.player): +# index += 1 +# continue + +# # pick another random exit and see if this age can reach it +# exits = [er_state.entrance_lookup.find_target( +# exit.value) for exit in SOHBossEntranceExitNames] +# er_state.world.random.shuffle(exits) +# picked_exit = None + +# for exit in exits: +# if er_state.collection_state._soh_can_reach_as_age(regions_dict.get(exit.connected_region.name), special_entrance_requirements[paired_entrances[index].name], er_state.world.player): +# picked_exit = exit +# break + +# er_state.connect(picked_exit, paired_entrances[index]) +# if not updated: +# updated = True + +# index += 1 + +# return updated diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index f5cd92064cde..b56d60101865 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -3843,3 +3843,58 @@ class Tricks(StrEnum): BOTTOM_OF_THE_WELL_SKULL_PUSH = "Bottom of the Well Skull Push" GANONS_CASTLE_BARRIER_SKIP_HOVER = "Ganons Castle Barrier Skip Hover" GANONS_CASTLE_GOLD_GAUNTLET_SKIP = "Ganons Castle Gold Gauntlet Skip" + + +class SOHEntranceGroups(IntEnum): + OTHER = 0 + DUNGEONS = 1 + CHILD_BOSSES = 2 + CHILD_ONLY_BOSSES = 3 + ADULT_BOSSES = 4 + ADULT_ONLY_BOSSES = 5 + OVERWORLD = 6 + INTERIOR = 7 + + +class SOHDungeonEntranceName(StrEnum): + DEKU_TREE_DUNGEON_ENTRANCE = "Deku Tree Dungeon Entrance" + DODONGOS_CAVERN_DUNGEON_ENTRANCE = "Dodongos Cavern Dungeon Entrance" + JABU_JABUS_DUNGEON_ENTRANCE = "Jabu Jabus Dungeon Entrance" + FOREST_TEMPLE_DUNGEON_ENTRANCE = "Forest Temple Dungeon Entrance" + FIRE_TEMPLE_DUNGEON_ENTRANCE = "Fire Temple Dungeon Entrance" + WATER_TEMPLE_DUNGEON_ENTRANCE = "Water Temple Dungeon Entrance" + SHADOW_TEMPLE_DUNGEON_ENTRANCE = "Shadow Temple Dungeon Entrance" + SPIRIT_TEMPLE_DUNGEON_ENTRANCE = "Spirit Temple Dungeon Entrance" + + +class SOHDungeonEntranceExitNames(StrEnum): + DEKU_TREE_DUNGEON_EXIT = "Deku Tree Dungeon Exit" + DODONGOS_CAVERN_DUNGEON_EXIT = "Dodongos Cavern Dungeon Exit" + JABU_JABUS_DUNGEON_EXIT = "Jabu Jabus Dungeon Exit" + FOREST_TEMPLE_DUNGEON_EXIT = "Forest Temple Dungeon Exit" + FIRE_TEMPLE_DUNGEON_EXIT = "Fire Temple Dungeon Exit" + WATER_TEMPLE_DUNGEON_EXIT = "Water Temple Dungeon Exit" + SHADOW_TEMPLE_DUNGEON_EXIT = "Shadow Temple Dungeon Exit" + SPIRIT_TEMPLE_DUNGEON_EXIT = "Spirit Temple Dungeon Exit" + + +class SOHBossEntranceNames(StrEnum): + DEKU_TREE_BOSS_ENTRANCE = "Deku Tree Boss Entrance" + DODONGOS_CAVERN_BOSS_ENTRANCE = "Dodongos Cavern Boss Entrance" + JABU_JABUS_BOSS_ENTRANCE = "Jabu Jabus Boss Entrance" + FOREST_TEMPLE_BOSS_ENTRANCE = "Forest Temple Boss Entrance" + FIRE_TEMPLE_BOSS_ENTRANCE = "Fire Temple Boss Entrance" + WATER_TEMPLE_BOSS_ENTRANCE = "Water Temple Boss Entrance" + SHADOW_TEMPLE_BOSS_ENTRANCE = "Shadow Temple Boss Entrance" + SPIRIT_TEMPLE_BOSS_ENTRANCE = "Spirit Temple Boss Entrance" + + +class SOHBossEntranceExitNames(StrEnum): + DEKU_TREE_BOSS_EXIT = "Deku Tree Boss Exit" + DODONGOS_CAVERN_BOSS_EXIT = "Dodongos Cavern Boss Exit" + JABU_JABUS_BOSS_EXIT = "Jabu Jabus Boss Exit" + FOREST_TEMPLE_BOSS_EXIT = "Forest Temple Boss Exit" + FIRE_TEMPLE_BOSS_EXIT = "Fire Temple Boss Exit" + WATER_TEMPLE_BOSS_EXIT = "Water Temple Boss Exit" + SHADOW_TEMPLE_BOSS_EXIT = "Shadow Temple Boss Exit" + SPIRIT_TEMPLE_BOSS_EXIT = "Spirit Temple Boss Exit" diff --git a/worlds/oot_soh/LogicHelpers.py b/worlds/oot_soh/LogicHelpers.py index eef0df996f32..bd8c624c6f89 100644 --- a/worlds/oot_soh/LogicHelpers.py +++ b/worlds/oot_soh/LogicHelpers.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Callable from collections import Counter -from BaseClasses import CollectionState, ItemClassification as IC, MultiWorld +from BaseClasses import CollectionState, ItemClassification as IC, MultiWorld, EntranceType from .Locations import SohLocation from worlds.generic.Rules import set_rule from worlds.AutoWorld import LogicMixin @@ -47,14 +47,22 @@ def locationRule(bundle): return True def connect_regions(parent_region: Regions, world: "SohWorld", - child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool]]]) -> None: + child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool], SOHBossEntranceNames, SOHEntranceGroups, EntranceType]]) -> None: for region in child_regions: regionName = region[0] + entranceName = None def regionRule(bundle): return True if len(region) > 1: - regionRule = region[1] # type: ignore # noqa - world.get_region(parent_region).connect(world.get_region(regionName), - rule=rule_wrapper.wrap(parent_region, regionRule, world)) + regionRule = region[1] + if len(region) > 2: + entranceName = region[2].value + entrance = world.get_region(parent_region).connect(world.get_region( + regionName), entranceName, rule_wrapper.wrap(parent_region, regionRule, world)) + + if len(region) > 3: + entrance.randomization_group = region[3].value + if len(region) > 4: + entrance.randomization_type = region[4] def add_events(parent_region: Regions, world: "SohWorld", diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index dee8edcbb597..cf7b511cb365 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -835,6 +835,43 @@ class TrueNoLogic(Toggle): display_name = "True No Logic" visibility = Visibility.spoiler + +class ShuffleEntrances(Toggle): + """ + Shuffle Entrances. Enables the use of all the below entrance options. + """ + display_name = "Shuffle Entrances" + + +class ShuffleDungeonBossEntrances(Choice): + """ + Shuffle the pool of dungeon boss entrances. This affects the boss rooms of all stone and medallion dungeons + Age Restricted - Shuffle the entrances of child and adult boss rooms separetly. + Full - Shuffle the entrances of all boss rooms together. Child may be expected to defeat Phantom Ganon and/or Bongo Bongo + """ + display_name = "Boss Entrances Shuffle" + option_off = 0 + option_age_restricted = 1 + option_full = 2 + default = 0 + + +class ShuffleDungeonEntrances(Choice): + """ + Shuffle the pool of dungeon entrances, including Bottom of the Well, Ice Cavern and Gerudo Training Ground. + Shuffling Ganon's Castle can be enabled separately. + Additionally, the entrances of Deku Tree, Fire Temple, Bottom of the Well and Gerudo Training Ground are + opened for both child and adult. + - Deku Tree will be open for adult after Mido has seen child Link with a sword and a shield. + - Bottom of the Well will be open for adult after playing Song of Storms to the Windmill guy as child. + - Gerudo Training Ground will be open for child after adult has paid to open the gate once. + """ + display_name = "Dungeon Entrances Shuffle" + option_off = 0 + option_on = 1 + option_on_plus_ganon = 2 + default = 0 + @dataclass class SohOptions(PerGameCommonOptions): @@ -919,6 +956,9 @@ class SohOptions(PerGameCommonOptions): ice_trap_count: IceTrapCount ice_trap_filler_replacement: IceTrapFillerReplacement true_no_logic: TrueNoLogic + shuffle_entrances: ShuffleEntrances + shuffle_dungeon_entrances: ShuffleDungeonEntrances + shuffle_boss_entrances: ShuffleDungeonBossEntrances soh_option_groups = [ @@ -946,17 +986,18 @@ class SohOptions(PerGameCommonOptions): TriforceHuntPiecesTotal, TriforceHuntPiecesRequiredPercentage, ]), - # OptionGroup("Shuffle Entrances", [ - # # Dungeon Entrances - # # Boss Entrances - # # Overworld Entrances - # # Interior Entrances - # # Grotto Entrances - # # Owl Drops - # # Warp Songs - # # Overworld Spawns - # # Decouple Entrances - # ]), + OptionGroup("Shuffle Entrances", [ + ShuffleEntrances, + ShuffleDungeonEntrances, + ShuffleDungeonBossEntrances + # Overworld Entrances + # Interior Entrances + # Grotto Entrances + # Owl Drops + # Warp Songs + # Overworld Spawns + # Decouple Entrances + ]), OptionGroup("Shuffle Items", [ # Shuffle Songs -- idk if this or the other ones here will be an actual option here, delete if not ShuffleTokens, diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index b5b7ea4c7b10..5dce85557633 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -3,7 +3,8 @@ from typing import Any, List, ClassVar -from BaseClasses import CollectionState, Item, Tutorial +from BaseClasses import CollectionState, Item, Tutorial, Entrance +from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances from worlds.AutoWorld import WebWorld, World from .Items import SohItem, item_data_table, item_table, item_name_groups, progressive_items from .Locations import location_table, location_name_groups @@ -18,6 +19,7 @@ from .UniversalTracker import setup_options_from_slot_data from settings import Group, Bool from Options import OptionError +from .EntranceShuffle import entrance_matching import logging logger = logging.getLogger("SOH_OOT") @@ -105,6 +107,9 @@ def generate_early(self) -> None: if self.options.shuffle_scrubs_minimum_price.value > self.options.shuffle_scrubs_maximum_price.value: self.options.shuffle_scrubs_maximum_price.value = self.options.shuffle_scrubs_minimum_price.value + # Entrance Rando stuff + self.explicit_indirect_conditions = True + def create_regions(self) -> None: create_regions_and_locations(self) place_locked_items(self) @@ -164,6 +169,42 @@ def set_rules(self) -> None: self.shop_vanilla_items = self.passthrough["shop_vanilla_items"] set_price_rules(self) + def connect_entrances(self): + if self.options.shuffle_entrances.value: + entrances_to_shuffle = set() + entrance_groups_combined = dict() + + # Dungeon Entrances + if self.options.shuffle_dungeon_entrances.value > 0: + for entrance in SOHBossEntranceNames: + entrances_to_shuffle.add(entrance) + + # Boss Entrances + if self.options.shuffle_boss_entrances.value > 0: + for entrance in SOHBossEntranceNames: + entrances_to_shuffle.add(entrance) + + if self.options.shuffle_boss_entrances.value == 1: + entrance_groups_combined.update({SOHEntranceGroups.CHILD_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], + SOHEntranceGroups.ADULT_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value], + SOHEntranceGroups.CHILD_ONLY_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], + SOHEntranceGroups.ADULT_ONLY_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value]}) + else: + entrance_groups_combined.update({SOHEntranceGroups.CHILD_ONLY_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], + SOHEntranceGroups.ADULT_ONLY_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value], + SOHEntranceGroups.CHILD_BOSSES.value: [SOHEntranceGroups.CHILD_ONLY_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value], + SOHEntranceGroups.ADULT_BOSSES.value: [SOHEntranceGroups.ADULT_ONLY_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value], + }) + + for entranceEnum in entrances_to_shuffle: + disconnect_entrance_for_randomization( + self.multiworld.get_entrance(entranceEnum.value, self.player), one_way_target_name=entrance_matching[entranceEnum].value) + + randomize_entrances( + self, True, entrance_groups_combined, True) + + return super().connect_entrances() + def get_pre_fill_items(self) -> List["Item"]: pre_fill_items = [] @@ -254,11 +295,11 @@ def remove(self, state: CollectionState, item: Item) -> bool: return changed # For debugging purposes - # def generate_output(self, output_directory: str): - # from Utils import visualize_regions - # visualize_regions(self.get_region(self.origin_region_name), f"SOH-Player{self.player}.puml", - # show_entrance_names=True, - # regions_to_highlight=self.multiworld.get_all_state().reachable_regions[self.player]) + def generate_output(self, output_directory: str): + from Utils import visualize_regions + visualize_regions(self.get_region(self.origin_region_name), f"SOH-Player{self.player}.puml", + show_entrance_names=True, + regions_to_highlight=self.multiworld.get_all_state().reachable_regions[self.player]) def fill_slot_data(self) -> dict[str, Any]: return { diff --git a/worlds/oot_soh/location_access/dungeons/deku_tree.py b/worlds/oot_soh/location_access/dungeons/deku_tree.py index 27d533cd8606..68e3c7cd2539 100644 --- a/worlds/oot_soh/location_access/dungeons/deku_tree.py +++ b/worlds/oot_soh/location_access/dungeons/deku_tree.py @@ -277,7 +277,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.DEKU_TREE_OUTSIDE_BOSS_ROOM, world, [ (Regions.DEKU_TREE_BASEMENT_UPPER, lambda bundle: True), (Regions.DEKU_TREE_BOSS_ENTRYWAY, lambda bundle: (has_item(Items.BRONZE_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle)) - and can_reflect_nuts(bundle)) + and can_reflect_nuts(bundle), SOHBossEntranceNames.DEKU_TREE_BOSS_ENTRANCE, SOHEntranceGroups.CHILD_BOSSES, EntranceType.ONE_WAY) ]) # Skipping master quest for now diff --git a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py index bf93b67b0714..6cd9a9b2d1a3 100644 --- a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py +++ b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py @@ -70,7 +70,7 @@ def set_region_rules(world: "SohWorld") -> None: lambda bundle: has_item(LocalEvents.DODONGOS_CAVERN_LIFT_PLATFORM, bundle)), (Regions.DODONGOS_CAVERN_BOSS_REGION, lambda bundle: has_item( LocalEvents.DODONGOS_CAVERN_EYES_LIT, bundle)), - (Regions.DODONGOS_CAVERN_BOSS_ENTRYWAY, lambda bundle: False), + # (Regions.DODONGOS_CAVERN_BOSS_ENTRYWAY, lambda bundle: False), ]) # Dodongos Cavern Lobby Switch @@ -402,7 +402,8 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DODONGOS_CAVERN_LOBBY, lambda bundle: True), (Regions.DODONGOS_CAVERN_BACK_ROOM, lambda bundle: can_break_mud_walls(bundle)), - (Regions.DODONGOS_CAVERN_BOSS_ENTRYWAY, lambda bundle: True), + (Regions.DODONGOS_CAVERN_BOSS_ENTRYWAY, lambda bundle: True, SOHBossEntranceNames.DODONGOS_CAVERN_BOSS_ENTRANCE, + SOHEntranceGroups.CHILD_BOSSES, EntranceType.ONE_WAY), ]) # Dodongos Cavern Back Room diff --git a/worlds/oot_soh/location_access/dungeons/fire_temple.py b/worlds/oot_soh/location_access/dungeons/fire_temple.py index bc3a5f927416..1ecaf1cfe392 100644 --- a/worlds/oot_soh/location_access/dungeons/fire_temple.py +++ b/worlds/oot_soh/location_access/dungeons/fire_temple.py @@ -68,7 +68,7 @@ def set_region_rules(world: "SohWorld") -> None: (is_adult(bundle) and (can_do_trick(Tricks.FIRE_BOSS_DOOR_JUMP, bundle) or has_item(LocalEvents.FIRE_TEMPLE_FIRE_MAZE_UPPER_PLATFORM_HIT, bundle) or - can_use(Items.HOVER_BOOTS, bundle)))) + can_use(Items.HOVER_BOOTS, bundle))), SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.ADULT_ONLY_BOSSES, EntranceType.ONE_WAY) ]) # Fire Temple Loop Enemies diff --git a/worlds/oot_soh/location_access/dungeons/forest_temple.py b/worlds/oot_soh/location_access/dungeons/forest_temple.py index 86a8548042c1..b923651beda4 100644 --- a/worlds/oot_soh/location_access/dungeons/forest_temple.py +++ b/worlds/oot_soh/location_access/dungeons/forest_temple.py @@ -510,7 +510,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.FOREST_TEMPLE_BOSS_REGION, world, [ (Regions.FOREST_TEMPLE_LOBBY, lambda bundle: True), - (Regions.FOREST_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True) + (Regions.FOREST_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True, SOHBossEntranceNames.FOREST_TEMPLE_BOSS_ENTRANCE, + SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY) ]) # Forest Temple Boss Entryway diff --git a/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py b/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py index fcc01392fe5d..f681ab302b4c 100644 --- a/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py +++ b/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py @@ -245,7 +245,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.JABU_JABUS_BELLY_NEAR_BOSS_ROOM, world, [ (Regions.JABU_JABUS_BELLY_MAIN, lambda bundle: True), (Regions.JABU_JABUS_BELLY_BOSS_ENTRYWAY, lambda bundle: can_use(Items.BOOMERANG, bundle) or (can_do_trick(Tricks.JABU_NEAR_BOSS_RANGED, bundle) and can_use_any([Items.HOOKSHOT, Items.FAIRY_BOW, Items.FAIRY_SLINGSHOT], bundle)) or ( - can_do_trick(Tricks.JABU_NEAR_BOSS_EXPLOSIVES, bundle) and (can_use(Items.BOMBCHUS_5, bundle) or (can_use(Items.HOVER_BOOTS, bundle) and can_use(Items.BOMB_BAG, bundle))))) + can_do_trick(Tricks.JABU_NEAR_BOSS_EXPLOSIVES, bundle) and (can_use(Items.BOMBCHUS_5, bundle) or (can_use(Items.HOVER_BOOTS, bundle) and can_use(Items.BOMB_BAG, bundle)))), SOHBossEntranceNames.JABU_JABUS_BOSS_ENTRANCE, SOHEntranceGroups.CHILD_ONLY_BOSSES, EntranceType.ONE_WAY) ]) # Skipping master quest for now diff --git a/worlds/oot_soh/location_access/dungeons/shadow_temple.py b/worlds/oot_soh/location_access/dungeons/shadow_temple.py index f31a86e78ab8..a2bc8edea874 100644 --- a/worlds/oot_soh/location_access/dungeons/shadow_temple.py +++ b/worlds/oot_soh/location_access/dungeons/shadow_temple.py @@ -178,7 +178,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.SHADOW_TEMPLE_BEYOND_BOAT, world, [ (Regions.SHADOW_TEMPLE_BOSS_ENTRYWAY, lambda bundle: (can_use(Items.FAIRY_BOW, bundle) or can_use(Items.DISTANT_SCARECROW, bundle) or (can_do_trick( - Tricks.SHADOW_STATUE, bundle) and can_use(Items.BOMBCHUS_5, bundle))) and small_keys(Items.SHADOW_TEMPLE_SMALL_KEY, 5, bundle) and can_use(Items.HOVER_BOOTS, bundle)), + Tricks.SHADOW_STATUE, bundle) and can_use(Items.BOMBCHUS_5, bundle))) and small_keys(Items.SHADOW_TEMPLE_SMALL_KEY, 5, bundle) and can_use(Items.HOVER_BOOTS, bundle), SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY), ]) # Shadow Temple Boss Entryway diff --git a/worlds/oot_soh/location_access/dungeons/spirit_temple.py b/worlds/oot_soh/location_access/dungeons/spirit_temple.py index c03e244ee36d..5049bf948715 100644 --- a/worlds/oot_soh/location_access/dungeons/spirit_temple.py +++ b/worlds/oot_soh/location_access/dungeons/spirit_temple.py @@ -203,7 +203,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, world, [ (Regions.SPIRIT_TEMPLE_CENTRAL_CHAMBER, lambda bundle: True), - (Regions.SPIRIT_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True) + (Regions.SPIRIT_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True, SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE, + SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY) ]) # Spirit Temple Boss Entryway diff --git a/worlds/oot_soh/location_access/dungeons/water_temple.py b/worlds/oot_soh/location_access/dungeons/water_temple.py index aba8ea48f3d8..ca111f026569 100644 --- a/worlds/oot_soh/location_access/dungeons/water_temple.py +++ b/worlds/oot_soh/location_access/dungeons/water_temple.py @@ -559,7 +559,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.WATER_TEMPLE_PRE_BOSS_ROOM, world, [ (Regions.WATER_TEMPLE_LOBBY, lambda bundle: True), - (Regions.WATER_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True) + (Regions.WATER_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True, SOHBossEntranceNames.WATER_TEMPLE_BOSS_ENTRANCE, + SOHEntranceGroups.ADULT_ONLY_BOSSES, EntranceType.ONE_WAY) ]) # Water Temple Boss Entryway From bc07931057312751f73753a540c2b4a95d13ad89 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Wed, 29 Oct 2025 10:11:38 -0400 Subject: [PATCH 02/22] Dungeon and Boss entrances randomized --- worlds/oot_soh/EntranceShuffle.py | 57 ++++--------- worlds/oot_soh/Enums.py | 58 ++++++++------ worlds/oot_soh/LogicHelpers.py | 2 +- worlds/oot_soh/Options.py | 13 ++- worlds/oot_soh/__init__.py | 79 +++++++++++-------- .../dungeons/bottom_of_the_well.py | 3 +- .../location_access/dungeons/deku_tree.py | 3 +- .../dungeons/dodongos_cavern.py | 4 +- .../location_access/dungeons/fire_temple.py | 5 +- .../location_access/dungeons/forest_temple.py | 3 +- .../location_access/dungeons/ganons_castle.py | 3 +- .../dungeons/gerudo_training_ground.py | 3 +- .../location_access/dungeons/ice_cavern.py | 5 +- .../dungeons/jabujabus_belly.py | 3 +- .../location_access/dungeons/shadow_temple.py | 7 +- .../location_access/dungeons/spirit_temple.py | 5 +- .../location_access/dungeons/water_temple.py | 3 +- .../overworld/castle_grounds.py | 21 ++--- .../overworld/death_mountain_crater.py | 43 ++++++---- .../overworld/death_mountain_trail.py | 4 +- .../overworld/desert_colossus.py | 24 +++--- .../overworld/gerudo_fortress.py | 22 +++--- .../location_access/overworld/graveyard.py | 4 +- .../location_access/overworld/kakariko.py | 8 +- .../overworld/kokiri_forest.py | 6 +- .../location_access/overworld/lake_hylia.py | 2 +- .../overworld/sacred_forest_meadow.py | 4 +- .../overworld/zoras_fountain.py | 7 +- 28 files changed, 215 insertions(+), 186 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 91018e0609fc..7e61adba082e 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -1,8 +1,13 @@ -from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames # , Ages, Regions +from typing import TYPE_CHECKING, Callable +from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames # , Ages, Regions +from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances # from entrance_rando import ERPlacementState, Entrance # from . import RegionAgeAccess -# Pretty sure this is only needed for One Way entrances +if TYPE_CHECKING: + from . import SohWorld + +# This is only needed for One Way entrances entrance_matching = { SOHBossEntranceNames.DEKU_TREE_BOSS_ENTRANCE: SOHBossEntranceExitNames.DEKU_TREE_BOSS_EXIT, SOHBossEntranceNames.DODONGOS_CAVERN_BOSS_ENTRANCE: SOHBossEntranceExitNames.DODONGOS_CAVERN_BOSS_EXIT, @@ -15,45 +20,11 @@ } -# special_entrance_requirements = { -# SOHBossEntranceExitNames.JABU_JABUS_BOSS_EXIT.value: Ages.CHILD, -# SOHBossEntranceExitNames.WATER_TEMPLE_BOSS_EXIT.value: Ages.ADULT -# } - -# Couldn't get this to work. I instead opted for more groups that intermingle. I feel like this could work though. -# Two issues: -# 1. At this point no items have been collected so our age logic always returns false. -# 2. I was having a hard time -# def soh_oot_on_connect(er_state: ERPlacementState, placed_exits: list[Entrance], paired_entrances: list[Entrance]) -> bool: - -# updated: bool = False -# index: int = 0 -# regions_dict = {i.value: i for i in Regions} - -# for _ in paired_entrances: -# print( -# f"Entrance:{paired_entrances[index].name} | Exit Region: {placed_exits[index].connected_region.name}") -# if paired_entrances[index].name in special_entrance_requirements: - -# if er_state.collection_state._soh_can_reach_as_age(regions_dict.get(placed_exits[index].connected_region.name), special_entrance_requirements[paired_entrances[index].name], er_state.world.player): -# index += 1 -# continue - -# # pick another random exit and see if this age can reach it -# exits = [er_state.entrance_lookup.find_target( -# exit.value) for exit in SOHBossEntranceExitNames] -# er_state.world.random.shuffle(exits) -# picked_exit = None - -# for exit in exits: -# if er_state.collection_state._soh_can_reach_as_age(regions_dict.get(exit.connected_region.name), special_entrance_requirements[paired_entrances[index].name], er_state.world.player): -# picked_exit = exit -# break - -# er_state.connect(picked_exit, paired_entrances[index]) -# if not updated: -# updated = True - -# index += 1 +# Might need to return the ER Placement state at the end +def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], entrance_groups: dict[int: list[int]]) -> None: + for entranceEnum in entrances_to_shuffle: + disconnect_entrance_for_randomization(world.multiworld.get_entrance( + entranceEnum.value, world.player), one_way_target_name=entrance_matching[entranceEnum].value if entranceEnum in entrance_matching else None) -# return updated + randomize_entrances( + world, (not bool(world.options.decouple_entrances)), entrance_groups, True) diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index b56d60101865..ba7fac1170a5 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -69,7 +69,7 @@ class Regions(StrEnum): GF_NEAR_GROTTO = "GF Near Grotto" GF_OUTSIDE_GTG = "GF Outside GTG" GF_TO_GTG = "GF to GTG" - GF_EXITING_GTG = "GF Exiting GTG" + # GF_EXITING_GTG = "GF Exiting GTG" GF_ABOVE_GTG = "GF Above GTG" GF_BOTTOM_OF_LOWER_VINES = "GF Bottom of Lower Vines" GF_TOP_OF_LOWER_VINES = "GF Top of Lower Vines" @@ -103,7 +103,7 @@ class Regions(StrEnum): WASTELAND_NEAR_COLOSSUS = "Wasteland Near Colossus" DESERT_COLOSSUS = "Desert Colossus" DESERT_COLOSSUS_OASIS = "Desert Colossus Oasis" - DESERT_COLOSSUS_OUTSIDE_TEMPLE = "Desert Colossus Outside Temple" + # DESERT_COLOSSUS_OUTSIDE_TEMPLE = "Desert Colossus Outside Temple" COLOSSUS_GREAT_FAIRY_FOUNTAIN = "Colossus Great Fairy Fountain" COLOSSUS_GROTTO = "Colossus Grotto" MARKET_ENTRANCE = "Market Entrance" @@ -124,7 +124,7 @@ class Regions(StrEnum): BEYOND_DOOR_OF_TIME = "Beyond Door of Time" MASTER_SWORD_PEDESTAL = "Master Sword Pedestal" CASTLE_GROUNDS = "Castle Grounds" - CASTLE_GROUNDS_FROM_GANONS_CASTLE = "Castle Grounds From Ganon's Castle" + # CASTLE_GROUNDS_FROM_GANONS_CASTLE = "Castle Grounds From Ganon's Castle" HYRULE_CASTLE_GROUNDS = "Hyrule Castle Grounds" HC_GARDEN_SONG_FROM_IMPA = "HC Garden Song From Impa" HC_GARDEN = "HC Garden" @@ -3845,29 +3845,24 @@ class Tricks(StrEnum): GANONS_CASTLE_GOLD_GAUNTLET_SKIP = "Ganons Castle Gold Gauntlet Skip" +# Probabaly need more than these for other shuffles, but for now this works. class SOHEntranceGroups(IntEnum): OTHER = 0 - DUNGEONS = 1 - CHILD_BOSSES = 2 - CHILD_ONLY_BOSSES = 3 - ADULT_BOSSES = 4 - ADULT_ONLY_BOSSES = 5 - OVERWORLD = 6 - INTERIOR = 7 + CHILD_DUNGEONS = 1 + CHILD_ONLY_DUNGEONS = 2 + ADULT_DUNGEONS = 3 + ADULT_ONLY_DUNGEONS = 4 + BOTH_DUNGEONS = 5 + CHILD_BOSSES = 6 + CHILD_ONLY_BOSSES = 7 + ADULT_BOSSES = 8 + ADULT_ONLY_BOSSES = 9 + EITHER_BOSSES = 10 + OVERWORLD = 11 + INTERIOR = 12 -class SOHDungeonEntranceName(StrEnum): - DEKU_TREE_DUNGEON_ENTRANCE = "Deku Tree Dungeon Entrance" - DODONGOS_CAVERN_DUNGEON_ENTRANCE = "Dodongos Cavern Dungeon Entrance" - JABU_JABUS_DUNGEON_ENTRANCE = "Jabu Jabus Dungeon Entrance" - FOREST_TEMPLE_DUNGEON_ENTRANCE = "Forest Temple Dungeon Entrance" - FIRE_TEMPLE_DUNGEON_ENTRANCE = "Fire Temple Dungeon Entrance" - WATER_TEMPLE_DUNGEON_ENTRANCE = "Water Temple Dungeon Entrance" - SHADOW_TEMPLE_DUNGEON_ENTRANCE = "Shadow Temple Dungeon Entrance" - SPIRIT_TEMPLE_DUNGEON_ENTRANCE = "Spirit Temple Dungeon Entrance" - - -class SOHDungeonEntranceExitNames(StrEnum): +class SOHDungeonExitNames(StrEnum): DEKU_TREE_DUNGEON_EXIT = "Deku Tree Dungeon Exit" DODONGOS_CAVERN_DUNGEON_EXIT = "Dodongos Cavern Dungeon Exit" JABU_JABUS_DUNGEON_EXIT = "Jabu Jabus Dungeon Exit" @@ -3876,6 +3871,25 @@ class SOHDungeonEntranceExitNames(StrEnum): WATER_TEMPLE_DUNGEON_EXIT = "Water Temple Dungeon Exit" SHADOW_TEMPLE_DUNGEON_EXIT = "Shadow Temple Dungeon Exit" SPIRIT_TEMPLE_DUNGEON_EXIT = "Spirit Temple Dungeon Exit" + GANONS_CASTLE_DUNGEON_EXIT = "Ganons Castle Dungeon Exit" + BOTTOM_OF_THE_WELL_DUNGEON_EXIT = "Bottom of the Well Dungeon Exit" + ICE_CAVERN_DUNGEON_EXIT = "Ice Cavern Dungeon Exit" + GERUDO_TRAINING_GROUND_DUNGEON_EXIT = "Gerudo Training Ground Dungeon Exit" + + +class SOHDungeonEntranceNames(StrEnum): + DEKU_TREE_DUNGEON_ENTRANCE = "Deku Tree Dungeon Entrance" + DODONGOS_CAVERN_DUNGEON_ENTRANCE = "Dodongos Cavern Dungeon Entrance" + JABU_JABUS_DUNGEON_ENTRANCE = "Jabu Jabus Dungeon Entrance" + FOREST_TEMPLE_DUNGEON_ENTRANCE = "Forest Temple Dungeon Entrance" + FIRE_TEMPLE_DUNGEON_ENTRANCE = "Fire Temple Dungeon Entrance" + WATER_TEMPLE_DUNGEON_ENTRANCE = "Water Temple Dungeon Entrance" + SHADOW_TEMPLE_DUNGEON_ENTRANCE = "Shadow Temple Dungeon Entrance" + SPIRIT_TEMPLE_DUNGEON_ENTRNACE = "Spirit Temple Dungeon Entrance" + GANONS_CASTLE_DUNGEON_ENTRANCE = "Ganons Castle Dungeon Entrance" + BOTTOM_OF_THE_WELL_DUNGEON_ENTRANCE = "Bottom of the Well Dungeon Entrance" + ICE_CAVERN_DUNGEON_ENTRANCE = "Ice Cavern Dungeon Entrance" + GERUDO_TRAINING_GROUND_DUNGEON_ENTRANCE = "Gerudo Training Ground Dungeon Entrance" class SOHBossEntranceNames(StrEnum): diff --git a/worlds/oot_soh/LogicHelpers.py b/worlds/oot_soh/LogicHelpers.py index bd8c624c6f89..14fb8aed6f33 100644 --- a/worlds/oot_soh/LogicHelpers.py +++ b/worlds/oot_soh/LogicHelpers.py @@ -47,7 +47,7 @@ def locationRule(bundle): return True def connect_regions(parent_region: Regions, world: "SohWorld", - child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool], SOHBossEntranceNames, SOHEntranceGroups, EntranceType]]) -> None: + child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool], SOHBossEntranceNames | SOHDungeonExitNames, SOHEntranceGroups, EntranceType]]) -> None: for region in child_regions: regionName = region[0] entranceName = None diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index cf7b511cb365..4456cd2f4211 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -873,6 +873,14 @@ class ShuffleDungeonEntrances(Choice): default = 0 +class DecoupleEntrances(Toggle): + """ + Decouple entrances when shuffling them. This means that you are no longer guaranteed to end up back where you came from when you go back through an entrance. + This also adds the one way entrance from Gerudo Valley to Lake Hylia in the pool of overworld entrances when they are shuffled. + """ + display_name = "Decouple Entrances" + + @dataclass class SohOptions(PerGameCommonOptions): closed_forest: ClosedForest @@ -959,6 +967,7 @@ class SohOptions(PerGameCommonOptions): shuffle_entrances: ShuffleEntrances shuffle_dungeon_entrances: ShuffleDungeonEntrances shuffle_boss_entrances: ShuffleDungeonBossEntrances + decouple_entrances: DecoupleEntrances soh_option_groups = [ @@ -989,14 +998,14 @@ class SohOptions(PerGameCommonOptions): OptionGroup("Shuffle Entrances", [ ShuffleEntrances, ShuffleDungeonEntrances, - ShuffleDungeonBossEntrances + ShuffleDungeonBossEntrances, + DecoupleEntrances # Overworld Entrances # Interior Entrances # Grotto Entrances # Owl Drops # Warp Songs # Overworld Spawns - # Decouple Entrances ]), OptionGroup("Shuffle Items", [ # Shuffle Songs -- idk if this or the other ones here will be an actual option here, delete if not diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index 5dce85557633..14e1b136c863 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -19,7 +19,7 @@ from .UniversalTracker import setup_options_from_slot_data from settings import Group, Bool from Options import OptionError -from .EntranceShuffle import entrance_matching +from .EntranceShuffle import randomize_entrances_soh import logging logger = logging.getLogger("SOH_OOT") @@ -108,7 +108,8 @@ def generate_early(self) -> None: self.options.shuffle_scrubs_maximum_price.value = self.options.shuffle_scrubs_minimum_price.value # Entrance Rando stuff - self.explicit_indirect_conditions = True + if (self.options.shuffle_dungeon_entrances.value > 0 or self.options.shuffle_boss_entrances.value > 0): + self.explicit_indirect_conditions = True def create_regions(self) -> None: create_regions_and_locations(self) @@ -170,38 +171,47 @@ def set_rules(self) -> None: set_price_rules(self) def connect_entrances(self): - if self.options.shuffle_entrances.value: - entrances_to_shuffle = set() - entrance_groups_combined = dict() + entrances_to_shuffle = set() - # Dungeon Entrances - if self.options.shuffle_dungeon_entrances.value > 0: - for entrance in SOHBossEntranceNames: + # Dungeon Entrances + if self.options.shuffle_dungeon_entrances.value > 0: + for entrance in SOHDungeonExitNames: + if entrance != SOHDungeonExitNames.GANONS_CASTLE_DUNGEON_EXIT or self.options.shuffle_dungeon_entrances == 2: entrances_to_shuffle.add(entrance) - # Boss Entrances - if self.options.shuffle_boss_entrances.value > 0: - for entrance in SOHBossEntranceNames: + for entrance in SOHDungeonEntranceNames: + if entrance != SOHDungeonEntranceNames.GANONS_CASTLE_DUNGEON_ENTRANCE or self.options.shuffle_dungeon_entrances == 2: entrances_to_shuffle.add(entrance) - if self.options.shuffle_boss_entrances.value == 1: - entrance_groups_combined.update({SOHEntranceGroups.CHILD_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], - SOHEntranceGroups.ADULT_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value], - SOHEntranceGroups.CHILD_ONLY_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], - SOHEntranceGroups.ADULT_ONLY_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value]}) - else: - entrance_groups_combined.update({SOHEntranceGroups.CHILD_ONLY_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], - SOHEntranceGroups.ADULT_ONLY_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value], - SOHEntranceGroups.CHILD_BOSSES.value: [SOHEntranceGroups.CHILD_ONLY_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value], - SOHEntranceGroups.ADULT_BOSSES.value: [SOHEntranceGroups.ADULT_ONLY_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value], - }) - - for entranceEnum in entrances_to_shuffle: - disconnect_entrance_for_randomization( - self.multiworld.get_entrance(entranceEnum.value, self.player), one_way_target_name=entrance_matching[entranceEnum].value) - - randomize_entrances( - self, True, entrance_groups_combined, True) + # These groupings are currently really fiddly. They need to be tweaked for accuracy. + randomize_entrances_soh( + self, entrances_to_shuffle, {SOHEntranceGroups.BOTH_DUNGEONS.value: [SOHEntranceGroups.BOTH_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value], + SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value: [SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value], + SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value: [SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value], + SOHEntranceGroups.CHILD_DUNGEONS.value: [SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value], + SOHEntranceGroups.ADULT_DUNGEONS.value: [SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value]}) + + entrances_to_shuffle.clear() + + # Boss Entrances + if self.options.shuffle_boss_entrances.value > 0: + for entrance in SOHBossEntranceNames: + entrances_to_shuffle.add(entrance) + + if self.options.shuffle_boss_entrances.value == 1: + randomize_entrances_soh( + self, entrances_to_shuffle, {SOHEntranceGroups.CHILD_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], + SOHEntranceGroups.ADULT_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value], + SOHEntranceGroups.CHILD_ONLY_BOSSES.value: [SOHEntranceGroups.CHILD_ONLY_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value], + SOHEntranceGroups.ADULT_ONLY_BOSSES.value: [SOHEntranceGroups.ADULT_ONLY_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value]}) + else: + randomize_entrances_soh( + self, entrances_to_shuffle, {SOHEntranceGroups.CHILD_ONLY_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], + SOHEntranceGroups.ADULT_ONLY_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value], + SOHEntranceGroups.CHILD_BOSSES.value: [SOHEntranceGroups.CHILD_ONLY_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value], + SOHEntranceGroups.ADULT_BOSSES.value: [SOHEntranceGroups.ADULT_ONLY_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value]}) + + entrances_to_shuffle.clear() return super().connect_entrances() @@ -295,11 +305,11 @@ def remove(self, state: CollectionState, item: Item) -> bool: return changed # For debugging purposes - def generate_output(self, output_directory: str): - from Utils import visualize_regions - visualize_regions(self.get_region(self.origin_region_name), f"SOH-Player{self.player}.puml", - show_entrance_names=True, - regions_to_highlight=self.multiworld.get_all_state().reachable_regions[self.player]) + # def generate_output(self, output_directory: str): + # from Utils import visualize_regions + # visualize_regions(self.get_region(self.origin_region_name), f"SOH-Player{self.player}.puml", + # show_entrance_names=True, + # regions_to_highlight=self.multiworld.get_all_state().reachable_regions[self.player]) def fill_slot_data(self) -> dict[str, Any]: return { @@ -383,4 +393,5 @@ def fill_slot_data(self) -> dict[str, Any]: "ice_trap_filler_replacement": self.options.ice_trap_filler_replacement.value, "no_logic": self.options.true_no_logic.value, "apworld_version": self.apworld_version, + # Need to figure out how to get the randomized entrances to Ship } diff --git a/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py b/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py index b322bff9246f..0e90385f05c5 100644 --- a/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py +++ b/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py @@ -26,7 +26,8 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.BOTTOM_OF_THE_WELL_PERIMETER, lambda bundle: is_child( bundle) and can_pass_enemy(bundle, Enemies.BIG_SKULLTULA)), # [Regions.BOTTOM_OF_THE_WELL_MQ_PERIMETER, lambda bundle: is_child(bundle), - (Regions.KAK_WELL, lambda bundle: True) + (Regions.KAK_WELL, lambda bundle: True, SOHDungeonExitNames.BOTTOM_OF_THE_WELL_DUNGEON_EXIT, + SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY) ]) # Bottom of the Well Perimeter diff --git a/worlds/oot_soh/location_access/dungeons/deku_tree.py b/worlds/oot_soh/location_access/dungeons/deku_tree.py index 68e3c7cd2539..1c2a59519708 100644 --- a/worlds/oot_soh/location_access/dungeons/deku_tree.py +++ b/worlds/oot_soh/location_access/dungeons/deku_tree.py @@ -30,7 +30,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.DEKU_TREE_ENTRYWAY, world, [ (Regions.DEKU_TREE_LOBBY, lambda bundle: True), - (Regions.KF_OUTSIDE_DEKU_TREE, lambda bundle: True) + (Regions.KF_OUTSIDE_DEKU_TREE, lambda bundle: True, SOHDungeonExitNames.DEKU_TREE_DUNGEON_EXIT, + SOHEntranceGroups.CHILD_DUNGEONS, EntranceType.TWO_WAY) ]) # Deku Lobby diff --git a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py index 6cd9a9b2d1a3..226812ee8dbf 100644 --- a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py +++ b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py @@ -26,9 +26,9 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.DODONGOS_CAVERN_ENTRYWAY, world, [ (Regions.DODONGOS_CAVERN_BEGINNING, lambda bundle: True), - (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True), + (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True, SOHDungeonExitNames.DODONGOS_CAVERN_DUNGEON_EXIT, + SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY), ]) - # Dodongos Cavern Beginning # Connections connect_regions(Regions.DODONGOS_CAVERN_BEGINNING, world, [ diff --git a/worlds/oot_soh/location_access/dungeons/fire_temple.py b/worlds/oot_soh/location_access/dungeons/fire_temple.py index 1ecaf1cfe392..ed7756810493 100644 --- a/worlds/oot_soh/location_access/dungeons/fire_temple.py +++ b/worlds/oot_soh/location_access/dungeons/fire_temple.py @@ -23,7 +23,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.FIRE_TEMPLE_ENTRYWAY, world, [ (Regions.FIRE_TEMPLE_FIRST_ROOM, lambda bundle: True), - (Regions.DMC_CENTRAL_LOCAL, lambda bundle: True) + (Regions.DMC_CENTRAL_LOCAL, lambda bundle: True, SOHDungeonExitNames.FIRE_TEMPLE_DUNGEON_EXIT, + SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) ]) # Fire Temple First Room @@ -68,7 +69,7 @@ def set_region_rules(world: "SohWorld") -> None: (is_adult(bundle) and (can_do_trick(Tricks.FIRE_BOSS_DOOR_JUMP, bundle) or has_item(LocalEvents.FIRE_TEMPLE_FIRE_MAZE_UPPER_PLATFORM_HIT, bundle) or - can_use(Items.HOVER_BOOTS, bundle))), SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.ADULT_ONLY_BOSSES, EntranceType.ONE_WAY) + can_use(Items.HOVER_BOOTS, bundle))), SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY) ]) # Fire Temple Loop Enemies diff --git a/worlds/oot_soh/location_access/dungeons/forest_temple.py b/worlds/oot_soh/location_access/dungeons/forest_temple.py index b923651beda4..fd1b25694b91 100644 --- a/worlds/oot_soh/location_access/dungeons/forest_temple.py +++ b/worlds/oot_soh/location_access/dungeons/forest_temple.py @@ -36,7 +36,8 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.FOREST_TEMPLE_ENTRYWAY, world, [ # Todo: Change this when we have IsVanilla vs. IsMQ (Regions.FOREST_TEMPLE_FIRST_ROOM, lambda bundle: True), - (Regions.SACRED_FOREST_MEADOW, lambda bundle: True) + (Regions.SACRED_FOREST_MEADOW, lambda bundle: True, SOHDungeonExitNames.FOREST_TEMPLE_DUNGEON_EXIT, + SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) ]) # Forest Temple First Room diff --git a/worlds/oot_soh/location_access/dungeons/ganons_castle.py b/worlds/oot_soh/location_access/dungeons/ganons_castle.py index c96d9905a74c..91ffdbde8a99 100644 --- a/worlds/oot_soh/location_access/dungeons/ganons_castle.py +++ b/worlds/oot_soh/location_access/dungeons/ganons_castle.py @@ -32,7 +32,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.GANONS_CASTLE_ENTRYWAY, world, [ (Regions.GANONS_CASTLE_LOBBY, lambda bundle: True), - (Regions.CASTLE_GROUNDS_FROM_GANONS_CASTLE, lambda bundle: True) + (Regions.GANONS_CASTLE_LEDGE, lambda bundle: True, + SOHDungeonExitNames.GANONS_CASTLE_DUNGEON_EXIT, SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) ]) # Ganon's Castle Lobby diff --git a/worlds/oot_soh/location_access/dungeons/gerudo_training_ground.py b/worlds/oot_soh/location_access/dungeons/gerudo_training_ground.py index 400913076c01..a4fec8763365 100644 --- a/worlds/oot_soh/location_access/dungeons/gerudo_training_ground.py +++ b/worlds/oot_soh/location_access/dungeons/gerudo_training_ground.py @@ -9,7 +9,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.GERUDO_TRAINING_GROUND_ENTRYWAY, world, [ (Regions.GERUDO_TRAINING_GROUND_LOBBY, lambda bundle: True), - (Regions.GF_EXITING_GTG, lambda bundle: True), + (Regions.GF_TO_GTG, lambda bundle: True, SOHDungeonExitNames.GERUDO_TRAINING_GROUND_DUNGEON_EXIT, + SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY), ]) # Gerudo Training Ground Lobby diff --git a/worlds/oot_soh/location_access/dungeons/ice_cavern.py b/worlds/oot_soh/location_access/dungeons/ice_cavern.py index 9c85c02ccf4a..ce8bfe566d93 100644 --- a/worlds/oot_soh/location_access/dungeons/ice_cavern.py +++ b/worlds/oot_soh/location_access/dungeons/ice_cavern.py @@ -12,13 +12,12 @@ class EventLocations(StrEnum): def set_region_rules(world: "SohWorld") -> None: # Ice Cavern Entryway - # Locations - add_locations(Regions.ICE_CAVERN_ENTRYWAY, world, []) # Connections connect_regions(Regions.ICE_CAVERN_ENTRYWAY, world, [ (Regions.ICE_CAVERN_BEGINNING, lambda bundle: True), # Skipping MQ - (Regions.ZF_LEDGE, lambda bundle: True) + (Regions.ZF_LEDGE, lambda bundle: True, SOHDungeonExitNames.ICE_CAVERN_DUNGEON_EXIT, + SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) ]) # Ice Cavern Beginning diff --git a/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py b/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py index f681ab302b4c..a55249b02e3b 100644 --- a/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py +++ b/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py @@ -31,7 +31,8 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.JABU_JABUS_BELLY_ENTRYWAY, world, [ # TODO: Add vanilla/MQ check (Regions.JABU_JABUS_BELLY_BEGINNING, lambda bundle: True), - (Regions.ZORAS_FOUNTAIN, lambda bundle: True) + (Regions.ZORAS_FOUNTAIN, lambda bundle: True, SOHDungeonExitNames.JABU_JABUS_DUNGEON_EXIT, + SOHEntranceGroups.CHILD_DUNGEONS, EntranceType.TWO_WAY) ]) # Jabu Jabu's Belly Beginning diff --git a/worlds/oot_soh/location_access/dungeons/shadow_temple.py b/worlds/oot_soh/location_access/dungeons/shadow_temple.py index a2bc8edea874..c1c3a23c4295 100644 --- a/worlds/oot_soh/location_access/dungeons/shadow_temple.py +++ b/worlds/oot_soh/location_access/dungeons/shadow_temple.py @@ -16,7 +16,8 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.SHADOW_TEMPLE_ENTRYWAY, world, [ (Regions.SHADOW_TEMPLE_BEGINNING, lambda bundle: (can_do_trick(Tricks.LENS_SHADOW, bundle) or can_use( Items.LENS_OF_TRUTH, bundle)) and (can_use(Items.HOVER_BOOTS, bundle) or can_use(Items.HOOKSHOT, bundle))), - (Regions.GRAVEYARD_WARP_PAD_REGION, lambda bundle: True) + (Regions.GRAVEYARD_WARP_PAD_REGION, lambda bundle: True, + SOHDungeonExitNames.SHADOW_TEMPLE_DUNGEON_EXIT, SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) ]) # Shadow Temple Beginning @@ -177,8 +178,8 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.SHADOW_TEMPLE_BEYOND_BOAT, world, [ - (Regions.SHADOW_TEMPLE_BOSS_ENTRYWAY, lambda bundle: (can_use(Items.FAIRY_BOW, bundle) or can_use(Items.DISTANT_SCARECROW, bundle) or (can_do_trick( - Tricks.SHADOW_STATUE, bundle) and can_use(Items.BOMBCHUS_5, bundle))) and small_keys(Items.SHADOW_TEMPLE_SMALL_KEY, 5, bundle) and can_use(Items.HOVER_BOOTS, bundle), SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY), + (Regions.SHADOW_TEMPLE_BOSS_ENTRYWAY, lambda bundle: (can_use(Items.FAIRY_BOW, bundle) or can_use(Items.DISTANT_SCARECROW, bundle) or (can_do_trick(Tricks.SHADOW_STATUE, bundle) and can_use(Items.BOMBCHUS_5, bundle))) + and small_keys(Items.SHADOW_TEMPLE_SMALL_KEY, 5, bundle) and can_use(Items.HOVER_BOOTS, bundle), SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY), ]) # Shadow Temple Boss Entryway diff --git a/worlds/oot_soh/location_access/dungeons/spirit_temple.py b/worlds/oot_soh/location_access/dungeons/spirit_temple.py index 5049bf948715..3c35d116f541 100644 --- a/worlds/oot_soh/location_access/dungeons/spirit_temple.py +++ b/worlds/oot_soh/location_access/dungeons/spirit_temple.py @@ -14,7 +14,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.SPIRIT_TEMPLE_ENTRYWAY, world, [ (Regions.SPIRIT_TEMPLE_LOBBY, lambda bundle: True), - (Regions.DESERT_COLOSSUS_OUTSIDE_TEMPLE, lambda bundle: True) + (Regions.DESERT_COLOSSUS, lambda bundle: True, SOHDungeonExitNames.SPIRIT_TEMPLE_DUNGEON_EXIT, + SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY) ]) # Spirit Temple Lobby @@ -204,7 +205,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, world, [ (Regions.SPIRIT_TEMPLE_CENTRAL_CHAMBER, lambda bundle: True), (Regions.SPIRIT_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True, SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE, - SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY) + SOHEntranceGroups.ADULT_ONLY_BOSSES, EntranceType.ONE_WAY) ]) # Spirit Temple Boss Entryway diff --git a/worlds/oot_soh/location_access/dungeons/water_temple.py b/worlds/oot_soh/location_access/dungeons/water_temple.py index ca111f026569..210cc0d2c83c 100644 --- a/worlds/oot_soh/location_access/dungeons/water_temple.py +++ b/worlds/oot_soh/location_access/dungeons/water_temple.py @@ -25,7 +25,8 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.WATER_TEMPLE_ENTRYWAY, world, [ (Regions.WATER_TEMPLE_LOBBY, lambda bundle: ( has_item(Items.BRONZE_SCALE, bundle))), - (Regions.LH_FROM_WATER_TEMPLE, lambda bundle: True) + (Regions.LH_FROM_WATER_TEMPLE, lambda bundle: True, SOHDungeonExitNames.WATER_TEMPLE_DUNGEON_EXIT, + SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) ]) # Water Temple Lobby diff --git a/worlds/oot_soh/location_access/overworld/castle_grounds.py b/worlds/oot_soh/location_access/overworld/castle_grounds.py index ac8a82ab8a97..7c2279af46c0 100644 --- a/worlds/oot_soh/location_access/overworld/castle_grounds.py +++ b/worlds/oot_soh/location_access/overworld/castle_grounds.py @@ -184,17 +184,20 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.CASTLE_GROUNDS, lambda bundle: True) ]) - # Castle Grounds from Ganon's Castle - # Connections - connect_regions(Regions.CASTLE_GROUNDS_FROM_GANONS_CASTLE, world, [ - (Regions.HYRULE_CASTLE_GROUNDS, lambda bundle: is_child(bundle)), - (Regions.GANONS_CASTLE_LEDGE, lambda bundle: is_adult(bundle)) - ]) + # Deviation from Ship, but makes ER easier + # # Castle Grounds from Ganon's Castle + # # Connections + # connect_regions(Regions.CASTLE_GROUNDS_FROM_GANONS_CASTLE, world, [ + # (Regions.HYRULE_CASTLE_GROUNDS, lambda bundle: is_child(bundle)), + # (Regions.GANONS_CASTLE_LEDGE, lambda bundle: is_adult(bundle)) + # ]) # Ganon's Castle Ledge # Connections connect_regions(Regions.GANONS_CASTLE_LEDGE, world, [ - (Regions.GANONS_CASTLE_GROUNDS, lambda bundle: has_item( - LocalEvents.HC_OGC_RAINBOW_BRIDGE_BUILT, bundle)), - (Regions.GANONS_CASTLE_ENTRYWAY, lambda bundle: is_adult(bundle)) + (Regions.GANONS_CASTLE_GROUNDS, lambda bundle: is_adult(bundle) + and has_item(LocalEvents.HC_OGC_RAINBOW_BRIDGE_BUILT, bundle)), + (Regions.HYRULE_CASTLE_GROUNDS, lambda bundle: is_child(bundle)), + (Regions.GANONS_CASTLE_ENTRYWAY, lambda bundle: is_adult(bundle), + SOHDungeonEntranceNames.GANONS_CASTLE_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_ONLY_DUNGEONS, EntranceType.TWO_WAY) ]) diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py index 40831fca872f..a693debdbc22 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py @@ -52,9 +52,8 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DMC_UPPER_NEARBY, lambda bundle: True), (Regions.DMC_LADDER_REGION_NEARBY, lambda bundle: fire_timer( bundle) >= 16 or hearts(bundle) >= 3), - (Regions.DMC_CENTRAL_NEARBY, lambda bundle: is_adult(bundle) and can_use(Items.GORON_TUNIC, bundle) and can_use(Items.DISTANT_SCARECROW, bundle) and (effective_health( - # TODO Implement Dungeon Shuffle Option to replace False - bundle) > 2 or (can_use(Items.BOTTLE_WITH_FAIRY, bundle) and False or can_use(Items.NAYRUS_LOVE, bundle)))), + (Regions.DMC_CENTRAL_NEARBY, lambda bundle: is_adult(bundle) and can_use(Items.GORON_TUNIC, bundle) and can_use(Items.DISTANT_SCARECROW, bundle) and ( + effective_health(bundle) > 2 or (can_use(Items.BOTTLE_WITH_FAIRY, bundle) and world.options.shuffle_dungeon_entrances.value > 0) or can_use(Items.NAYRUS_LOVE, bundle))), (Regions.DMC_LOWER_NEARBY, lambda bundle: False), (Regions.DMC_DISTANT_PLATFORM, lambda bundle: (fire_timer( bundle) >= 48 or hearts(bundle) >= 2) or hearts(bundle) >= 3), @@ -162,9 +161,8 @@ def set_region_rules(world: "SohWorld") -> None: bundle)) or can_use(Items.HOVER_BOOTS, bundle) or can_use(Items.HOOKSHOT, bundle)), (Regions.DMC_UPPER_NEARBY, lambda bundle: is_adult(bundle) and has_item(LocalEvents.DMC_BEAN_PLANTED, bundle)), - (Regions.FIRE_TEMPLE_ENTRYWAY, lambda bundle: (is_child(bundle) and hearts(bundle) >= 3 and False) or ( - # TODO Implement Dungeon Shuffle Option to replace False - is_adult(bundle) and fire_timer(bundle) >= 24)), + (Regions.FIRE_TEMPLE_ENTRYWAY, lambda bundle: (is_child(bundle) and hearts(bundle) >= 3 and world.options.shuffle_dungeon_entrances.value > 0) or ( + is_adult(bundle) and fire_timer(bundle) >= 24), SOHDungeonEntranceNames.FIRE_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY), (Regions.DMC_DISTANT_PLATFORM, lambda bundle: (fire_timer(bundle) >= 48 or hearts(bundle) >= 2) and can_use(Items.DISTANT_SCARECROW, bundle)), ]) @@ -204,10 +202,14 @@ def set_region_rules(world: "SohWorld") -> None: lambda bundle: can_break_lower_hives(bundle)), (Locations.DMC_UPPER_GROTTO_BEEHIVE_RIGHT, lambda bundle: can_break_lower_hives(bundle)), - (Locations.DMC_UPPER_GROTTO_GRASS1, lambda bundle: can_cut_shrubs(bundle)), - (Locations.DMC_UPPER_GROTTO_GRASS2, lambda bundle: can_cut_shrubs(bundle)), - (Locations.DMC_UPPER_GROTTO_GRASS3, lambda bundle: can_cut_shrubs(bundle)), - (Locations.DMC_UPPER_GROTTO_GRASS4, lambda bundle: can_cut_shrubs(bundle)) + (Locations.DMC_UPPER_GROTTO_GRASS1, + lambda bundle: can_cut_shrubs(bundle)), + (Locations.DMC_UPPER_GROTTO_GRASS2, + lambda bundle: can_cut_shrubs(bundle)), + (Locations.DMC_UPPER_GROTTO_GRASS3, + lambda bundle: can_cut_shrubs(bundle)), + (Locations.DMC_UPPER_GROTTO_GRASS4, + lambda bundle: can_cut_shrubs(bundle)) ]) # Connections connect_regions(Regions.DMC_UPPER_GROTTO, world, [ @@ -234,13 +236,20 @@ def set_region_rules(world: "SohWorld") -> None: # Death Mountain Crater Distant Platform # Locations add_locations(Regions.DMC_DISTANT_PLATFORM, world, [ - (Locations.DMC_DISTANT_PLATFORM_RUPEE1, lambda bundle: is_adult(bundle)), - (Locations.DMC_DISTANT_PLATFORM_RUPEE2, lambda bundle: is_adult(bundle)), - (Locations.DMC_DISTANT_PLATFORM_RUPEE3, lambda bundle: is_adult(bundle)), - (Locations.DMC_DISTANT_PLATFORM_RUPEE4, lambda bundle: is_adult(bundle)), - (Locations.DMC_DISTANT_PLATFORM_RUPEE5, lambda bundle: is_adult(bundle)), - (Locations.DMC_DISTANT_PLATFORM_RUPEE6, lambda bundle: is_adult(bundle)), - (Locations.DMC_DISTANT_PLATFORM_RED_RUPEE, lambda bundle: is_adult(bundle)) + (Locations.DMC_DISTANT_PLATFORM_RUPEE1, + lambda bundle: is_adult(bundle)), + (Locations.DMC_DISTANT_PLATFORM_RUPEE2, + lambda bundle: is_adult(bundle)), + (Locations.DMC_DISTANT_PLATFORM_RUPEE3, + lambda bundle: is_adult(bundle)), + (Locations.DMC_DISTANT_PLATFORM_RUPEE4, + lambda bundle: is_adult(bundle)), + (Locations.DMC_DISTANT_PLATFORM_RUPEE5, + lambda bundle: is_adult(bundle)), + (Locations.DMC_DISTANT_PLATFORM_RUPEE6, + lambda bundle: is_adult(bundle)), + (Locations.DMC_DISTANT_PLATFORM_RED_RUPEE, + lambda bundle: is_adult(bundle)) ]) # Connections connect_regions(Regions.DMC_DISTANT_PLATFORM, world, [ diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py index 2ad25937625f..5ecf381421a0 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py @@ -66,8 +66,8 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GORON_CITY, lambda bundle: True), (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: blast_or_smash(bundle) or (is_adult(bundle) and ((has_item(LocalEvents.DMT_BEAN_PLANTED, bundle) and has_item(Items.GORONS_BRACELET, bundle)) or (can_use(Items.HOVER_BOOTS, bundle) and can_do_trick(Tricks.DMT_CLIMB_HOVERS, bundle))))), - (Regions.DODONGOS_CAVERN_ENTRYWAY, lambda bundle: has_explosives( - bundle) or has_item(Items.GORONS_BRACELET, bundle) or is_adult(bundle)), + (Regions.DODONGOS_CAVERN_ENTRYWAY, lambda bundle: has_explosives(bundle) or has_item(Items.GORONS_BRACELET, bundle) or is_adult( + bundle), SOHDungeonEntranceNames.DODONGOS_CAVERN_DUNGEON_ENTRANCE, SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY), (Regions.DMT_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)) ]) diff --git a/worlds/oot_soh/location_access/overworld/desert_colossus.py b/worlds/oot_soh/location_access/overworld/desert_colossus.py index b09d2159f65f..45c9cbf22699 100644 --- a/worlds/oot_soh/location_access/overworld/desert_colossus.py +++ b/worlds/oot_soh/location_access/overworld/desert_colossus.py @@ -51,7 +51,8 @@ def set_region_rules(world: "SohWorld") -> None: (Locations.COLOSSUS_GOSSIP_STONE_FAIRY, lambda bundle: call_gossip_fairy(bundle)), (Locations.COLOSSUS_GOSSIP_STONE_BIG_FAIRY, - lambda bundle: can_use(Items.SONG_OF_STORMS, bundle)) + lambda bundle: can_use(Items.SONG_OF_STORMS, bundle)), + (Locations.SHEIK_AT_COLOSSUS, lambda bundle: True) ]) # Connections @@ -60,7 +61,8 @@ def set_region_rules(world: "SohWorld") -> None: has_item(Items.BRONZE_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle))), (Regions.COLOSSUS_GREAT_FAIRY_FOUNTAIN, lambda bundle: has_explosives(bundle)), - (Regions.SPIRIT_TEMPLE_ENTRYWAY, lambda bundle: True), + (Regions.SPIRIT_TEMPLE_ENTRYWAY, lambda bundle: True, SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE, + SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY), (Regions.WASTELAND_NEAR_COLOSSUS, lambda bundle: True), (Regions.COLOSSUS_GROTTO, lambda bundle: can_use( Items.SILVER_GAUNTLETS, bundle)) @@ -89,15 +91,15 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DESERT_COLOSSUS, lambda bundle: True) ]) - # Desert Colossus Outside Temple - # Locations - add_locations(Regions.DESERT_COLOSSUS_OUTSIDE_TEMPLE, world, [ - (Locations.SHEIK_AT_COLOSSUS, lambda bundle: True) - ]) - # Connections - connect_regions(Regions.DESERT_COLOSSUS_OUTSIDE_TEMPLE, world, [ - (Regions.DESERT_COLOSSUS, lambda bundle: True) - ]) + # # Desert Colossus Outside Temple + # # Locations + # add_locations(Regions.DESERT_COLOSSUS_OUTSIDE_TEMPLE, world, [ + # (Locations.SHEIK_AT_COLOSSUS, lambda bundle: True) + # ]) + # # Connections + # connect_regions(Regions.DESERT_COLOSSUS_OUTSIDE_TEMPLE, world, [ + # (Regions.DESERT_COLOSSUS, lambda bundle: True) + # ]) # Desert Colossus Great Fairy Fountain # Locations diff --git a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py index 3fd44aa5ccf9..6d884e4d571d 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py @@ -80,9 +80,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GF_OUTSIDE_GTG, world, [ - # TODO: Check for entrance rando - (Regions.GF_TO_GTG, lambda bundle: has_item( - LocalEvents.GTG_GATE_OPEN, bundle) and is_adult(bundle)), + (Regions.GF_TO_GTG, lambda bundle: True), (Regions.GF_JAIL_WINDOW, lambda bundle: can_use(Items.HOOKSHOT, bundle)), (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True), (Regions.GF_NEAR_GROTTO, lambda bundle: is_child(bundle) @@ -98,18 +96,24 @@ def set_region_rules(world: "SohWorld") -> None: # GF to GTG # Connections connect_regions(Regions.GF_TO_GTG, world, [ - (Regions.GERUDO_TRAINING_GROUND_ENTRYWAY, lambda bundle: True), - ]) - - # GF Exiting GTG - # Connections - connect_regions(Regions.GF_EXITING_GTG, world, [ + (Regions.GERUDO_TRAINING_GROUND_ENTRYWAY, lambda bundle: has_item(LocalEvents.GTG_GATE_OPEN, bundle) and (is_adult(bundle) or world.options.shuffle_dungeon_entrances > + 0), SOHDungeonEntranceNames.GERUDO_TRAINING_GROUND_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY), (Regions.GF_OUTSIDE_GTG, lambda bundle: is_child(bundle) or has_item(Items.GERUDO_MEMBERSHIP_CARD, bundle)), (Regions.GF_JAIL_WINDOW, lambda bundle: can_use(Items.HOOKSHOT, bundle)), (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True), ]) + # Deviation from Ship + # GF Exiting GTG + # Connections + # connect_regions(Regions.GF_EXITING_GTG, world, [ + # (Regions.GF_OUTSIDE_GTG, lambda bundle: is_child(bundle) + # or has_item(Items.GERUDO_MEMBERSHIP_CARD, bundle)), + # (Regions.GF_JAIL_WINDOW, lambda bundle: can_use(Items.HOOKSHOT, bundle)), + # (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True), + # ]) + # GF Above GTG # Connections connect_regions(Regions.GF_ABOVE_GTG, world, [ diff --git a/worlds/oot_soh/location_access/overworld/graveyard.py b/worlds/oot_soh/location_access/overworld/graveyard.py index 450c212c429f..cd3f342d42c3 100644 --- a/worlds/oot_soh/location_access/overworld/graveyard.py +++ b/worlds/oot_soh/location_access/overworld/graveyard.py @@ -200,6 +200,6 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.GRAVEYARD_WARP_PAD_REGION, world, [ (Regions.THE_GRAVEYARD, lambda bundle: True), - (Regions.SHADOW_TEMPLE_ENTRYWAY, lambda bundle: can_use(Items.DINS_FIRE, bundle) or (can_do_trick( - Tricks.GY_SHADOW_FIRE_ARROWS, bundle) and is_adult(bundle) and can_use(Items.FIRE_ARROW, bundle))) + (Regions.SHADOW_TEMPLE_ENTRYWAY, lambda bundle: can_use(Items.DINS_FIRE, bundle) or (can_do_trick(Tricks.GY_SHADOW_FIRE_ARROWS, bundle) and is_adult( + bundle) and can_use(Items.FIRE_ARROW, bundle)), SOHDungeonEntranceNames.SHADOW_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY) ]) diff --git a/worlds/oot_soh/location_access/overworld/kakariko.py b/worlds/oot_soh/location_access/overworld/kakariko.py index 89f3b3962416..5eb75d8d5801 100644 --- a/worlds/oot_soh/location_access/overworld/kakariko.py +++ b/worlds/oot_soh/location_access/overworld/kakariko.py @@ -430,9 +430,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.KAK_WELL, world, [ (Regions.KAKARIKO_VILLAGE, - lambda bundle: is_adult(bundle) or has_item(Items.BRONZE_SCALE, bundle) or has_item(Events.DRAIN_WELL, - bundle)), - # TODO: Add check for dungeon entrance randomization - (Regions.BOTTOM_OF_THE_WELL_ENTRYWAY, lambda bundle: is_child( - bundle) or has_item(Events.DRAIN_WELL, bundle)), + lambda bundle: is_adult(bundle) or has_item(Items.BRONZE_SCALE, bundle) or has_item(Events.DRAIN_WELL, bundle)), + (Regions.BOTTOM_OF_THE_WELL_ENTRYWAY, lambda bundle: is_child(bundle) or (has_item(Events.DRAIN_WELL, bundle) and world.options.shuffle_dungeon_entrances.value > + 0), SOHDungeonEntranceNames.BOTTOM_OF_THE_WELL_DUNGEON_ENTRANCE, SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY) ]) diff --git a/worlds/oot_soh/location_access/overworld/kokiri_forest.py b/worlds/oot_soh/location_access/overworld/kokiri_forest.py index f697f40ef08e..066d27e2317e 100644 --- a/worlds/oot_soh/location_access/overworld/kokiri_forest.py +++ b/worlds/oot_soh/location_access/overworld/kokiri_forest.py @@ -211,10 +211,8 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KF_OUTSIDE_DEKU_TREE, world, [ - (Regions.DEKU_TREE_ENTRYWAY, lambda bundle: (is_child(bundle)) - # Todo: Add dungeons shuffle rule when entrance shuffle is implementedd - and (world.options.closed_forest.value == 2 - or has_item(LocalEvents.MIDO_SWORD_AND_SHIELD, bundle))), + (Regions.DEKU_TREE_ENTRYWAY, lambda bundle: is_child(bundle) or (world.options.shuffle_dungeon_entrances.value > 0 and (world.options.closed_forest.value == 2 or has_item( + LocalEvents.MIDO_SWORD_AND_SHIELD, bundle))), SOHDungeonEntranceNames.DEKU_TREE_DUNGEON_ENTRANCE, SOHEntranceGroups.CHILD_DUNGEONS, EntranceType.TWO_WAY), (Regions.KOKIRI_FOREST, lambda bundle: (is_adult(bundle) and (can_pass_enemy(bundle, Enemies.BIG_SKULLTULA) or has_item(Events.FOREST_TEMPLE_COMPLETED, bundle))) diff --git a/worlds/oot_soh/location_access/overworld/lake_hylia.py b/worlds/oot_soh/location_access/overworld/lake_hylia.py index 6f8f1bcfd6f0..4eba984b3534 100644 --- a/worlds/oot_soh/location_access/overworld/lake_hylia.py +++ b/worlds/oot_soh/location_access/overworld/lake_hylia.py @@ -194,7 +194,7 @@ def set_region_rules(world: "SohWorld") -> None: has_item(Items.GOLDEN_SCALE, bundle))) or (is_adult(bundle) and can_use(Items.LONGSHOT, bundle) and - has_item(Items.GOLDEN_SCALE, bundle)))), + has_item(Items.GOLDEN_SCALE, bundle))), SOHDungeonEntranceNames.WATER_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_ONLY_DUNGEONS, EntranceType.TWO_WAY), ]) # LH Fishing Island diff --git a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py index 24323b25390c..de3265880fad 100644 --- a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py +++ b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py @@ -48,8 +48,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.SACRED_FOREST_MEADOW, world, [ (Regions.SFM_ENTRYWAY, lambda bundle: True), - (Regions.FOREST_TEMPLE_ENTRYWAY, - lambda bundle: can_use(Items.HOOKSHOT, bundle)), + (Regions.FOREST_TEMPLE_ENTRYWAY, lambda bundle: can_use(Items.HOOKSHOT, bundle), + SOHDungeonEntranceNames.FOREST_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_ONLY_DUNGEONS, EntranceType.TWO_WAY), (Regions.SFM_FAIRY_GROTTO, lambda bundle: True), (Regions.SFM_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)), ]) diff --git a/worlds/oot_soh/location_access/overworld/zoras_fountain.py b/worlds/oot_soh/location_access/overworld/zoras_fountain.py index 37834e7e44b4..3d8e7b9ed256 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_fountain.py +++ b/worlds/oot_soh/location_access/overworld/zoras_fountain.py @@ -52,8 +52,8 @@ def set_region_rules(world: "SohWorld") -> None: Items.SILVER_GAUNTLETS, bundle) and blast_or_smash(bundle)), (Regions.ZF_ROCK, lambda bundle: is_adult( bundle) and can_use(Items.SCARECROW, bundle)), - (Regions.JABU_JABUS_BELLY_ENTRYWAY, - lambda bundle: is_child(bundle) and (can_use(Items.BOTTLE_WITH_FISH, bundle) or world.options.jabu_jabu.value == 1)), + (Regions.JABU_JABUS_BELLY_ENTRYWAY, lambda bundle: is_child(bundle) and (can_use(Items.BOTTLE_WITH_FISH, bundle) + or world.options.jabu_jabu.value == 1), SOHDungeonEntranceNames.JABU_JABUS_DUNGEON_ENTRANCE, SOHEntranceGroups.CHILD_ONLY_DUNGEONS, EntranceType.TWO_WAY), (Regions.ZF_GREAT_FAIRY_FOUNTAIN, lambda bundle: has_explosives(bundle) or (can_do_trick( Tricks.ZF_GREAT_FAIRY_WITHOUT_EXPLOSIVES, bundle) and can_use(Items.MEGATON_HAMMER, bundle) and can_use(Items.SILVER_GAUNTLETS, bundle))) ]) @@ -124,7 +124,8 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.ZORAS_FOUNTAIN, lambda bundle: has_item(Items.BRONZE_SCALE, bundle)), (Regions.ZF_ICEBERGS, lambda bundle: is_adult(bundle)), (Regions.ZF_LAKEBED, lambda bundle: can_use(Items.IRON_BOOTS, bundle)), - (Regions.ICE_CAVERN_ENTRYWAY, lambda bundle: True) + (Regions.ICE_CAVERN_ENTRYWAY, lambda bundle: True, SOHDungeonEntranceNames.ICE_CAVERN_DUNGEON_ENTRANCE, + SOHEntranceGroups.ADULT_ONLY_DUNGEONS, EntranceType.TWO_WAY) ]) # Zora's Fountain Hidden Cave From 9c4ed4f0a40b90eb6c11fd49431141cbf301848c Mon Sep 17 00:00:00 2001 From: mattman107 Date: Sun, 2 Nov 2025 10:32:22 -0500 Subject: [PATCH 03/22] Remove unused option --- worlds/oot_soh/Options.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index 4456cd2f4211..2a6242298eac 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -835,13 +835,6 @@ class TrueNoLogic(Toggle): display_name = "True No Logic" visibility = Visibility.spoiler - -class ShuffleEntrances(Toggle): - """ - Shuffle Entrances. Enables the use of all the below entrance options. - """ - display_name = "Shuffle Entrances" - class ShuffleDungeonBossEntrances(Choice): """ @@ -964,7 +957,6 @@ class SohOptions(PerGameCommonOptions): ice_trap_count: IceTrapCount ice_trap_filler_replacement: IceTrapFillerReplacement true_no_logic: TrueNoLogic - shuffle_entrances: ShuffleEntrances shuffle_dungeon_entrances: ShuffleDungeonEntrances shuffle_boss_entrances: ShuffleDungeonBossEntrances decouple_entrances: DecoupleEntrances @@ -996,7 +988,6 @@ class SohOptions(PerGameCommonOptions): TriforceHuntPiecesRequiredPercentage, ]), OptionGroup("Shuffle Entrances", [ - ShuffleEntrances, ShuffleDungeonEntrances, ShuffleDungeonBossEntrances, DecoupleEntrances From 844dd076914589dfa4f082c00eeebeff7667eb18 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Sun, 2 Nov 2025 19:17:08 -0500 Subject: [PATCH 04/22] My proposed solution to the Sheik at Colossus problem --- worlds/oot_soh/EntranceShuffle.py | 33 ++++++++++++++++--- worlds/oot_soh/__init__.py | 14 ++++---- .../overworld/desert_colossus.py | 1 - 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 7e61adba082e..c10724d4fa88 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -1,8 +1,11 @@ from typing import TYPE_CHECKING, Callable -from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames # , Ages, Regions +from BaseClasses import Location, Region +from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations +from .Locations import SohLocation from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances -# from entrance_rando import ERPlacementState, Entrance -# from . import RegionAgeAccess +from entrance_rando import ERPlacementState, Entrance +from .LogicHelpers import rule_wrapper +from worlds.generic.Rules import set_rule if TYPE_CHECKING: from . import SohWorld @@ -21,10 +24,30 @@ # Might need to return the ER Placement state at the end -def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], entrance_groups: dict[int: list[int]]) -> None: +def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], entrance_groups: dict[int: list[int]], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None) -> None: for entranceEnum in entrances_to_shuffle: disconnect_entrance_for_randomization(world.multiworld.get_entrance( entranceEnum.value, world.player), one_way_target_name=entrance_matching[entranceEnum].value if entranceEnum in entrance_matching else None) + # Figure out decoupled entrances. For now setting to False + #randomize_entrances(world, (not bool(world.options.decouple_entrances)), entrance_groups, True, on_connect=on_connect) randomize_entrances( - world, (not bool(world.options.decouple_entrances)), entrance_groups, True) + world, False, entrance_groups, True, on_connect=on_connect) + + +# This should probably be double checked by someone who knows how to properly remove a location from a region and give it a new parent region +def on_connect_soh_sheik_at_collosus(er_state: ERPlacementState, placed_exits: list[Entrance], paired_entrances: list[Entrance]) -> bool: + if len(paired_entrances) >= 2 and paired_entrances[1].name == SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE: + world: SohWorld = er_state.world + def locationRule(bundle): return True + + print(f'Placed Exits: {placed_exits} | Paired Entrances: {paired_entrances}') + location: Location = world.get_location(Locations.SHEIK_AT_COLOSSUS) + location.parent_region.locations.remove(location) + + new_parent_region: Region = world.get_entrance(paired_entrances[0].name).parent_region + location.parent_region = new_parent_region + new_parent_region.add_locations({str(location.name): location.address}, SohLocation) + set_rule(world.get_location(location.name), rule_wrapper.wrap(new_parent_region, locationRule, world)) + + return False diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index 14e1b136c863..e3c921f16d66 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -19,7 +19,7 @@ from .UniversalTracker import setup_options_from_slot_data from settings import Group, Bool from Options import OptionError -from .EntranceShuffle import randomize_entrances_soh +from .EntranceShuffle import randomize_entrances_soh, on_connect_soh_sheik_at_collosus import logging logger = logging.getLogger("SOH_OOT") @@ -189,7 +189,7 @@ def connect_entrances(self): SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value: [SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value], SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value: [SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value], SOHEntranceGroups.CHILD_DUNGEONS.value: [SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value], - SOHEntranceGroups.ADULT_DUNGEONS.value: [SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value]}) + SOHEntranceGroups.ADULT_DUNGEONS.value: [SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value]}, on_connect_soh_sheik_at_collosus) entrances_to_shuffle.clear() @@ -305,11 +305,11 @@ def remove(self, state: CollectionState, item: Item) -> bool: return changed # For debugging purposes - # def generate_output(self, output_directory: str): - # from Utils import visualize_regions - # visualize_regions(self.get_region(self.origin_region_name), f"SOH-Player{self.player}.puml", - # show_entrance_names=True, - # regions_to_highlight=self.multiworld.get_all_state().reachable_regions[self.player]) + def generate_output(self, output_directory: str): + from Utils import visualize_regions + visualize_regions(self.get_region(self.origin_region_name), f"SOH-Player{self.player}.puml", + show_entrance_names=True, + regions_to_highlight=self.multiworld.get_all_state().reachable_regions[self.player]) def fill_slot_data(self) -> dict[str, Any]: return { diff --git a/worlds/oot_soh/location_access/overworld/desert_colossus.py b/worlds/oot_soh/location_access/overworld/desert_colossus.py index 45c9cbf22699..1cc5f41b5f3e 100644 --- a/worlds/oot_soh/location_access/overworld/desert_colossus.py +++ b/worlds/oot_soh/location_access/overworld/desert_colossus.py @@ -53,7 +53,6 @@ def set_region_rules(world: "SohWorld") -> None: (Locations.COLOSSUS_GOSSIP_STONE_BIG_FAIRY, lambda bundle: can_use(Items.SONG_OF_STORMS, bundle)), (Locations.SHEIK_AT_COLOSSUS, lambda bundle: True) - ]) # Connections connect_regions(Regions.DESERT_COLOSSUS, world, [ From 43fe2fe038368a3b86f879276d771db376eef0b7 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Sun, 2 Nov 2025 19:30:07 -0500 Subject: [PATCH 05/22] fix spelling --- worlds/oot_soh/EntranceShuffle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index c10724d4fa88..28a7d62c0b00 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -36,7 +36,7 @@ def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBoss # This should probably be double checked by someone who knows how to properly remove a location from a region and give it a new parent region -def on_connect_soh_sheik_at_collosus(er_state: ERPlacementState, placed_exits: list[Entrance], paired_entrances: list[Entrance]) -> bool: +def on_connect_soh_sheik_at_colossus(er_state: ERPlacementState, placed_exits: list[Entrance], paired_entrances: list[Entrance]) -> bool: if len(paired_entrances) >= 2 and paired_entrances[1].name == SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE: world: SohWorld = er_state.world def locationRule(bundle): return True From 7d4509d8d44b2c67a1fe72043d02f0fd32e415f9 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Tue, 4 Nov 2025 18:38:27 -0500 Subject: [PATCH 06/22] fix spelling. Confirmed decoupled doesn't currently work for dungeon entrances and their current groupings. --- worlds/oot_soh/EntranceShuffle.py | 6 +++--- worlds/oot_soh/__init__.py | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 28a7d62c0b00..3d444a9d1b6d 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -24,7 +24,7 @@ # Might need to return the ER Placement state at the end -def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], entrance_groups: dict[int: list[int]], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None) -> None: +def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], entrance_groups: dict[int: list[int]], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None, coupled: bool = True) -> None: for entranceEnum in entrances_to_shuffle: disconnect_entrance_for_randomization(world.multiworld.get_entrance( entranceEnum.value, world.player), one_way_target_name=entrance_matching[entranceEnum].value if entranceEnum in entrance_matching else None) @@ -32,7 +32,7 @@ def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBoss # Figure out decoupled entrances. For now setting to False #randomize_entrances(world, (not bool(world.options.decouple_entrances)), entrance_groups, True, on_connect=on_connect) randomize_entrances( - world, False, entrance_groups, True, on_connect=on_connect) + world, coupled, entrance_groups, True, on_connect=on_connect) # This should probably be double checked by someone who knows how to properly remove a location from a region and give it a new parent region @@ -41,7 +41,7 @@ def on_connect_soh_sheik_at_colossus(er_state: ERPlacementState, placed_exits: l world: SohWorld = er_state.world def locationRule(bundle): return True - print(f'Placed Exits: {placed_exits} | Paired Entrances: {paired_entrances}') + # print(f'Placed Exits: {placed_exits} | Paired Entrances: {paired_entrances}') location: Location = world.get_location(Locations.SHEIK_AT_COLOSSUS) location.parent_region.locations.remove(location) diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index e3c921f16d66..cac74764875a 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -19,7 +19,7 @@ from .UniversalTracker import setup_options_from_slot_data from settings import Group, Bool from Options import OptionError -from .EntranceShuffle import randomize_entrances_soh, on_connect_soh_sheik_at_collosus +from .EntranceShuffle import randomize_entrances_soh, on_connect_soh_sheik_at_colossus import logging logger = logging.getLogger("SOH_OOT") @@ -172,6 +172,9 @@ def set_rules(self) -> None: def connect_entrances(self): entrances_to_shuffle = set() + # Reverse decoupled option for randomize_entrances, because it is asking if you wanted coupled + # Update this when it is figured out why decoupled doesn't work with the current groupings + decoupled = True #(not self.options.decouple_entrances) # Dungeon Entrances if self.options.shuffle_dungeon_entrances.value > 0: @@ -189,7 +192,7 @@ def connect_entrances(self): SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value: [SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value], SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value: [SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value], SOHEntranceGroups.CHILD_DUNGEONS.value: [SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value], - SOHEntranceGroups.ADULT_DUNGEONS.value: [SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value]}, on_connect_soh_sheik_at_collosus) + SOHEntranceGroups.ADULT_DUNGEONS.value: [SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value]}, on_connect_soh_sheik_at_colossus, decoupled) entrances_to_shuffle.clear() From 95488219d89676f4de25b84b4ebf2e6f0c748b59 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Wed, 5 Nov 2025 09:46:23 -0500 Subject: [PATCH 07/22] touch coupled again --- worlds/oot_soh/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index cac74764875a..4d28dc5c39fc 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -172,9 +172,9 @@ def set_rules(self) -> None: def connect_entrances(self): entrances_to_shuffle = set() - # Reverse decoupled option for randomize_entrances, because it is asking if you wanted coupled + # Reverse decoupled option for randomize_entrances because it is asking if you wanted coupled # Update this when it is figured out why decoupled doesn't work with the current groupings - decoupled = True #(not self.options.decouple_entrances) + coupled = True#(not self.options.decouple_entrances) # Dungeon Entrances if self.options.shuffle_dungeon_entrances.value > 0: @@ -192,7 +192,7 @@ def connect_entrances(self): SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value: [SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value], SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value: [SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value], SOHEntranceGroups.CHILD_DUNGEONS.value: [SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value], - SOHEntranceGroups.ADULT_DUNGEONS.value: [SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value]}, on_connect_soh_sheik_at_colossus, decoupled) + SOHEntranceGroups.ADULT_DUNGEONS.value: [SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value]}, on_connect_soh_sheik_at_colossus, coupled) entrances_to_shuffle.clear() From 811e23df3b3b1b7170b21ef3224f0623ad512e36 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Thu, 6 Nov 2025 18:49:00 -0500 Subject: [PATCH 08/22] Clean up grouping --- worlds/oot_soh/EntranceShuffle.py | 73 +++++++++++++++++-- worlds/oot_soh/Enums.py | 63 +++++++++------- worlds/oot_soh/LogicHelpers.py | 4 +- worlds/oot_soh/Options.py | 11 ++- worlds/oot_soh/__init__.py | 45 ++++-------- .../dungeons/bottom_of_the_well.py | 2 +- .../location_access/dungeons/deku_tree.py | 4 +- .../dungeons/dodongos_cavern.py | 4 +- .../location_access/dungeons/fire_temple.py | 4 +- .../location_access/dungeons/forest_temple.py | 4 +- .../location_access/dungeons/ganons_castle.py | 2 +- .../dungeons/gerudo_training_ground.py | 2 +- .../location_access/dungeons/ice_cavern.py | 2 +- .../dungeons/jabujabus_belly.py | 4 +- .../location_access/dungeons/shadow_temple.py | 4 +- .../location_access/dungeons/spirit_temple.py | 4 +- .../location_access/dungeons/water_temple.py | 4 +- .../overworld/castle_grounds.py | 2 +- .../overworld/death_mountain_crater.py | 2 +- .../overworld/death_mountain_trail.py | 2 +- .../overworld/desert_colossus.py | 2 +- .../overworld/gerudo_fortress.py | 2 +- .../location_access/overworld/graveyard.py | 2 +- .../location_access/overworld/kakariko.py | 2 +- .../overworld/kokiri_forest.py | 2 +- .../location_access/overworld/lake_hylia.py | 2 +- .../overworld/sacred_forest_meadow.py | 2 +- .../overworld/zoras_fountain.py | 4 +- 28 files changed, 161 insertions(+), 99 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 3d444a9d1b6d..20c5b87b1ea1 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -1,8 +1,8 @@ from typing import TYPE_CHECKING, Callable from BaseClasses import Location, Region -from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations +from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups from .Locations import SohLocation -from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances +from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances, bake_target_group_lookup from entrance_rando import ERPlacementState, Entrance from .LogicHelpers import rule_wrapper from worlds.generic.Rules import set_rule @@ -22,22 +22,81 @@ SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SPIRIT_TEMPLE_BOSS_EXIT, } +default_group_lookup = { + SOHEntranceGroups.DUNGEON_ENTRANCE: [SOHEntranceGroups.DUNGEON_ENTRANCE], + SOHEntranceGroups.BOSS_ENTRANCE: [SOHEntranceGroups.BOSS_ENTRANCE], + SOHEntranceGroups.GROTTO: [SOHEntranceGroups.GROTTO], +} + + +mixed_group_lookup = {group: [all for all in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, + SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO, SOHEntranceGroups.OWL_DROP, SOHEntranceGroups.WARP_SONG)] + for group in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, + SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO, SOHEntranceGroups.OWL_DROP, SOHEntranceGroups.WARP_SONG)} + + +def get_target_groups(group: int) -> list[int]: + type = group & SOHEntranceGroups.TYPE_MASK + age = group & SOHEntranceGroups.AGE_MASK + + if(age == SOHEntranceGroups.ANY_AGE): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.ANY_AGE, SOHEntranceGroups.CHILD, SOHEntranceGroups.ADULT, SOHEntranceGroups.CHILD_ONLY, SOHEntranceGroups.ADULT_ONLY, SOHEntranceGroups.BOTH_AGE)] + + if(age == SOHEntranceGroups.BOTH_AGE): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.BOTH_AGE, SOHEntranceGroups.ADULT, SOHEntranceGroups.CHILD, SOHEntranceGroups.ANY_AGE)] + + if(age == SOHEntranceGroups.CHILD): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.CHILD, SOHEntranceGroups.CHILD_ONLY, SOHEntranceGroups.ADULT, SOHEntranceGroups.BOTH_AGE, SOHEntranceGroups.ANY_AGE)] + + if(age == SOHEntranceGroups.ADULT): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.ADULT, SOHEntranceGroups.ADULT_ONLY, SOHEntranceGroups.CHILD, SOHEntranceGroups.BOTH_AGE, SOHEntranceGroups.ANY_AGE)] + + if(age == SOHEntranceGroups.ADULT_ONLY): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.ADULT_ONLY, SOHEntranceGroups.ADULT, SOHEntranceGroups.ANY_AGE)] + + if(age == SOHEntranceGroups.CHILD_ONLY): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.CHILD_ONLY, SOHEntranceGroups.CHILD, SOHEntranceGroups.ANY_AGE)] + + return [pair_type | age for pair_type in default_group_lookup[type]] + + +def get_target_groups_age_restrictive(group: int) -> list[int]: + type = group & SOHEntranceGroups.TYPE_MASK + age = group & SOHEntranceGroups.AGE_MASK + + if(age == SOHEntranceGroups.CHILD): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.CHILD_ONLY, SOHEntranceGroups.CHILD)] + + if(age == SOHEntranceGroups.ADULT): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.ADULT_ONLY, SOHEntranceGroups.ADULT)] + + if(age == SOHEntranceGroups.ADULT_ONLY): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.ADULT, SOHEntranceGroups.ADULT_ONLY)] + + if(age == SOHEntranceGroups.CHILD_ONLY): + return [pair_type | ages for pair_type in default_group_lookup[type] for ages in (SOHEntranceGroups.CHILD, SOHEntranceGroups.CHILD_ONLY)] + + return [pair_type | age for pair_type in default_group_lookup[type]] + # Might need to return the ER Placement state at the end -def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], entrance_groups: dict[int: list[int]], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None, coupled: bool = True) -> None: +def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None, coupled: bool = True, ageRestricted: bool = False) -> None: for entranceEnum in entrances_to_shuffle: disconnect_entrance_for_randomization(world.multiworld.get_entrance( entranceEnum.value, world.player), one_way_target_name=entrance_matching[entranceEnum].value if entranceEnum in entrance_matching else None) - # Figure out decoupled entrances. For now setting to False - #randomize_entrances(world, (not bool(world.options.decouple_entrances)), entrance_groups, True, on_connect=on_connect) + if ageRestricted: + target_group_lookup = bake_target_group_lookup(world, get_target_groups_age_restrictive) + else: + target_group_lookup = bake_target_group_lookup(world, get_target_groups) + randomize_entrances( - world, coupled, entrance_groups, True, on_connect=on_connect) + world, coupled, target_group_lookup, True, on_connect=on_connect) # This should probably be double checked by someone who knows how to properly remove a location from a region and give it a new parent region def on_connect_soh_sheik_at_colossus(er_state: ERPlacementState, placed_exits: list[Entrance], paired_entrances: list[Entrance]) -> bool: - if len(paired_entrances) >= 2 and paired_entrances[1].name == SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE: + if er_state.world.options.decouple_entrances and len(paired_entrances) >= 2 and paired_entrances[1].name == SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE: world: SohWorld = er_state.world def locationRule(bundle): return True diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index ba7fac1170a5..94851505c226 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -3847,19 +3847,26 @@ class Tricks(StrEnum): # Probabaly need more than these for other shuffles, but for now this works. class SOHEntranceGroups(IntEnum): + # Entrance Type OTHER = 0 - CHILD_DUNGEONS = 1 - CHILD_ONLY_DUNGEONS = 2 - ADULT_DUNGEONS = 3 - ADULT_ONLY_DUNGEONS = 4 - BOTH_DUNGEONS = 5 - CHILD_BOSSES = 6 - CHILD_ONLY_BOSSES = 7 - ADULT_BOSSES = 8 - ADULT_ONLY_BOSSES = 9 - EITHER_BOSSES = 10 - OVERWORLD = 11 - INTERIOR = 12 + DUNGEON_ENTRANCE = 1 + BOSS_ENTRANCE = 2 + OVERWORLD = 3 + INTERIOR = 4 + THEIVES_HIDEOUT_ENTRANCE = 5 + GROTTO = 6 + OWL_DROP = 7 + WARP_SONG = 8 + # Age Accessible + ANY_AGE = 1 << 4 + CHILD = 2 << 4 + ADULT = 3 << 4 + CHILD_ONLY = 4 << 4 + ADULT_ONLY = 5 << 4 + BOTH_AGE = 6 << 4 + # Bitmasks + TYPE_MASK = ANY_AGE - 1 + AGE_MASK = ~0 << 4 class SOHDungeonExitNames(StrEnum): @@ -3893,22 +3900,22 @@ class SOHDungeonEntranceNames(StrEnum): class SOHBossEntranceNames(StrEnum): - DEKU_TREE_BOSS_ENTRANCE = "Deku Tree Boss Entrance" - DODONGOS_CAVERN_BOSS_ENTRANCE = "Dodongos Cavern Boss Entrance" - JABU_JABUS_BOSS_ENTRANCE = "Jabu Jabus Boss Entrance" - FOREST_TEMPLE_BOSS_ENTRANCE = "Forest Temple Boss Entrance" - FIRE_TEMPLE_BOSS_ENTRANCE = "Fire Temple Boss Entrance" - WATER_TEMPLE_BOSS_ENTRANCE = "Water Temple Boss Entrance" - SHADOW_TEMPLE_BOSS_ENTRANCE = "Shadow Temple Boss Entrance" - SPIRIT_TEMPLE_BOSS_ENTRANCE = "Spirit Temple Boss Entrance" + DEKU_TREE_BOSS_ENTRANCE = "Deku Tree Dungeon Boss Entrance" + DODONGOS_CAVERN_BOSS_ENTRANCE = "Dodongos Cavern Dungeon Boss Entrance" + JABU_JABUS_BOSS_ENTRANCE = "Jabu Jabus Dungeon Boss Entrance" + FOREST_TEMPLE_BOSS_ENTRANCE = "Forest Temple Dungeon Boss Entrance" + FIRE_TEMPLE_BOSS_ENTRANCE = "Fire Temple Dungeon Boss Entrance" + WATER_TEMPLE_BOSS_ENTRANCE = "Water Temple Dungeon Boss Entrance" + SHADOW_TEMPLE_BOSS_ENTRANCE = "Shadow Temple Dungeon Boss Entrance" + SPIRIT_TEMPLE_BOSS_ENTRANCE = "Spirit Temple Dungeon Boss Entrance" class SOHBossEntranceExitNames(StrEnum): - DEKU_TREE_BOSS_EXIT = "Deku Tree Boss Exit" - DODONGOS_CAVERN_BOSS_EXIT = "Dodongos Cavern Boss Exit" - JABU_JABUS_BOSS_EXIT = "Jabu Jabus Boss Exit" - FOREST_TEMPLE_BOSS_EXIT = "Forest Temple Boss Exit" - FIRE_TEMPLE_BOSS_EXIT = "Fire Temple Boss Exit" - WATER_TEMPLE_BOSS_EXIT = "Water Temple Boss Exit" - SHADOW_TEMPLE_BOSS_EXIT = "Shadow Temple Boss Exit" - SPIRIT_TEMPLE_BOSS_EXIT = "Spirit Temple Boss Exit" + DEKU_TREE_BOSS_EXIT = "Deku Tree Dungeon Boss Exit" + DODONGOS_CAVERN_BOSS_EXIT = "Dodongos Cavern Dungeon Boss Exit" + JABU_JABUS_BOSS_EXIT = "Jabu Jabus Dungeon Boss Exit" + FOREST_TEMPLE_BOSS_EXIT = "Forest Temple Dungeon Boss Exit" + FIRE_TEMPLE_BOSS_EXIT = "Fire Temple Dungeon Boss Exit" + WATER_TEMPLE_BOSS_EXIT = "Water Temple Dungeon Boss Exit" + SHADOW_TEMPLE_BOSS_EXIT = "Shadow Temple Dungeon Boss Exit" + SPIRIT_TEMPLE_BOSS_EXIT = "Spirit Temple Dungeon Boss Exit" diff --git a/worlds/oot_soh/LogicHelpers.py b/worlds/oot_soh/LogicHelpers.py index 14fb8aed6f33..275bcf0ba79b 100644 --- a/worlds/oot_soh/LogicHelpers.py +++ b/worlds/oot_soh/LogicHelpers.py @@ -47,7 +47,7 @@ def locationRule(bundle): return True def connect_regions(parent_region: Regions, world: "SohWorld", - child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool], SOHBossEntranceNames | SOHDungeonExitNames, SOHEntranceGroups, EntranceType]]) -> None: + child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool], SOHBossEntranceNames | SOHDungeonExitNames, int, EntranceType]]) -> None: for region in child_regions: regionName = region[0] entranceName = None @@ -60,7 +60,7 @@ def regionRule(bundle): return True regionName), entranceName, rule_wrapper.wrap(parent_region, regionRule, world)) if len(region) > 3: - entrance.randomization_group = region[3].value + entrance.randomization_group = region[3] if len(region) > 4: entrance.randomization_type = region[4] diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index 2a6242298eac..02571f52feef 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -874,6 +874,13 @@ class DecoupleEntrances(Toggle): display_name = "Decouple Entrances" +class MixedEntrancePools(Toggle): + """ + Shuffle entrances into a mixed pool instead of separate ones. Has no effect on pools whose entrances aren't shuffled, and "Shuffle Boss Entrances" must be set to "Full" to include them. + """ + display_name = "Mixed Entrances Pools" + + @dataclass class SohOptions(PerGameCommonOptions): closed_forest: ClosedForest @@ -960,6 +967,7 @@ class SohOptions(PerGameCommonOptions): shuffle_dungeon_entrances: ShuffleDungeonEntrances shuffle_boss_entrances: ShuffleDungeonBossEntrances decouple_entrances: DecoupleEntrances + mixed_entrances_pools: MixedEntrancePools soh_option_groups = [ @@ -990,7 +998,8 @@ class SohOptions(PerGameCommonOptions): OptionGroup("Shuffle Entrances", [ ShuffleDungeonEntrances, ShuffleDungeonBossEntrances, - DecoupleEntrances + DecoupleEntrances, + MixedEntrancePools # Overworld Entrances # Interior Entrances # Grotto Entrances diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index 4d28dc5c39fc..875222ba7c02 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -3,8 +3,7 @@ from typing import Any, List, ClassVar -from BaseClasses import CollectionState, Item, Tutorial, Entrance -from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances +from BaseClasses import CollectionState, Item, Tutorial from worlds.AutoWorld import WebWorld, World from .Items import SohItem, item_data_table, item_table, item_name_groups, progressive_items from .Locations import location_table, location_name_groups @@ -20,6 +19,7 @@ from settings import Group, Bool from Options import OptionError from .EntranceShuffle import randomize_entrances_soh, on_connect_soh_sheik_at_colossus +from entrance_rando import bake_target_group_lookup import logging logger = logging.getLogger("SOH_OOT") @@ -176,6 +176,15 @@ def connect_entrances(self): # Update this when it is figured out why decoupled doesn't work with the current groupings coupled = True#(not self.options.decouple_entrances) + # Boss Entrances + if self.options.shuffle_boss_entrances.value > 0: + for entrance in SOHBossEntranceNames: + entrances_to_shuffle.add(entrance) + + if self.options.shuffle_boss_entrances.value == 1: + randomize_entrances_soh(self, entrances_to_shuffle, ageRestricted=True) + entrances_to_shuffle.clear() + # Dungeon Entrances if self.options.shuffle_dungeon_entrances.value > 0: for entrance in SOHDungeonExitNames: @@ -186,35 +195,13 @@ def connect_entrances(self): if entrance != SOHDungeonEntranceNames.GANONS_CASTLE_DUNGEON_ENTRANCE or self.options.shuffle_dungeon_entrances == 2: entrances_to_shuffle.add(entrance) - # These groupings are currently really fiddly. They need to be tweaked for accuracy. - randomize_entrances_soh( - self, entrances_to_shuffle, {SOHEntranceGroups.BOTH_DUNGEONS.value: [SOHEntranceGroups.BOTH_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value], - SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value: [SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value], - SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value: [SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value], - SOHEntranceGroups.CHILD_DUNGEONS.value: [SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.CHILD_ONLY_DUNGEONS.value, SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value], - SOHEntranceGroups.ADULT_DUNGEONS.value: [SOHEntranceGroups.ADULT_DUNGEONS.value, SOHEntranceGroups.ADULT_ONLY_DUNGEONS.value, SOHEntranceGroups.CHILD_DUNGEONS.value, SOHEntranceGroups.BOTH_DUNGEONS.value]}, on_connect_soh_sheik_at_colossus, coupled) + # randomize_entrances_soh( + # self, entrances_to_shuffle, on_connect_soh_sheik_at_colossus, coupled) - entrances_to_shuffle.clear() + # entrances_to_shuffle.clear() - # Boss Entrances - if self.options.shuffle_boss_entrances.value > 0: - for entrance in SOHBossEntranceNames: - entrances_to_shuffle.add(entrance) - - if self.options.shuffle_boss_entrances.value == 1: - randomize_entrances_soh( - self, entrances_to_shuffle, {SOHEntranceGroups.CHILD_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], - SOHEntranceGroups.ADULT_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value], - SOHEntranceGroups.CHILD_ONLY_BOSSES.value: [SOHEntranceGroups.CHILD_ONLY_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value], - SOHEntranceGroups.ADULT_ONLY_BOSSES.value: [SOHEntranceGroups.ADULT_ONLY_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value]}) - else: - randomize_entrances_soh( - self, entrances_to_shuffle, {SOHEntranceGroups.CHILD_ONLY_BOSSES.value: [SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.CHILD_ONLY_BOSSES.value], - SOHEntranceGroups.ADULT_ONLY_BOSSES.value: [SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.ADULT_ONLY_BOSSES.value], - SOHEntranceGroups.CHILD_BOSSES.value: [SOHEntranceGroups.CHILD_ONLY_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value], - SOHEntranceGroups.ADULT_BOSSES.value: [SOHEntranceGroups.ADULT_ONLY_BOSSES.value, SOHEntranceGroups.CHILD_BOSSES.value, SOHEntranceGroups.ADULT_BOSSES.value]}) - - entrances_to_shuffle.clear() + randomize_entrances_soh( + self, entrances_to_shuffle, on_connect_soh_sheik_at_colossus, coupled) return super().connect_entrances() diff --git a/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py b/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py index 0e90385f05c5..368da5d5a563 100644 --- a/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py +++ b/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py @@ -27,7 +27,7 @@ def set_region_rules(world: "SohWorld") -> None: bundle) and can_pass_enemy(bundle, Enemies.BIG_SKULLTULA)), # [Regions.BOTTOM_OF_THE_WELL_MQ_PERIMETER, lambda bundle: is_child(bundle), (Regions.KAK_WELL, lambda bundle: True, SOHDungeonExitNames.BOTTOM_OF_THE_WELL_DUNGEON_EXIT, - SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY) ]) # Bottom of the Well Perimeter diff --git a/worlds/oot_soh/location_access/dungeons/deku_tree.py b/worlds/oot_soh/location_access/dungeons/deku_tree.py index 1c2a59519708..d63c74429910 100644 --- a/worlds/oot_soh/location_access/dungeons/deku_tree.py +++ b/worlds/oot_soh/location_access/dungeons/deku_tree.py @@ -31,7 +31,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.DEKU_TREE_ENTRYWAY, world, [ (Regions.DEKU_TREE_LOBBY, lambda bundle: True), (Regions.KF_OUTSIDE_DEKU_TREE, lambda bundle: True, SOHDungeonExitNames.DEKU_TREE_DUNGEON_EXIT, - SOHEntranceGroups.CHILD_DUNGEONS, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY) ]) # Deku Lobby @@ -278,7 +278,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.DEKU_TREE_OUTSIDE_BOSS_ROOM, world, [ (Regions.DEKU_TREE_BASEMENT_UPPER, lambda bundle: True), (Regions.DEKU_TREE_BOSS_ENTRYWAY, lambda bundle: (has_item(Items.BRONZE_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle)) - and can_reflect_nuts(bundle), SOHBossEntranceNames.DEKU_TREE_BOSS_ENTRANCE, SOHEntranceGroups.CHILD_BOSSES, EntranceType.ONE_WAY) + and can_reflect_nuts(bundle), SOHBossEntranceNames.DEKU_TREE_BOSS_ENTRANCE, SOHEntranceGroups.BOSS_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.ONE_WAY) ]) # Skipping master quest for now diff --git a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py index 226812ee8dbf..addc49365a11 100644 --- a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py +++ b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py @@ -27,7 +27,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.DODONGOS_CAVERN_ENTRYWAY, world, [ (Regions.DODONGOS_CAVERN_BEGINNING, lambda bundle: True), (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True, SOHDungeonExitNames.DODONGOS_CAVERN_DUNGEON_EXIT, - SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY), + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.BOTH_AGE, EntranceType.TWO_WAY), ]) # Dodongos Cavern Beginning # Connections @@ -403,7 +403,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DODONGOS_CAVERN_BACK_ROOM, lambda bundle: can_break_mud_walls(bundle)), (Regions.DODONGOS_CAVERN_BOSS_ENTRYWAY, lambda bundle: True, SOHBossEntranceNames.DODONGOS_CAVERN_BOSS_ENTRANCE, - SOHEntranceGroups.CHILD_BOSSES, EntranceType.ONE_WAY), + SOHEntranceGroups.BOSS_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.ONE_WAY), ]) # Dodongos Cavern Back Room diff --git a/worlds/oot_soh/location_access/dungeons/fire_temple.py b/worlds/oot_soh/location_access/dungeons/fire_temple.py index ed7756810493..2bd668098c31 100644 --- a/worlds/oot_soh/location_access/dungeons/fire_temple.py +++ b/worlds/oot_soh/location_access/dungeons/fire_temple.py @@ -24,7 +24,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.FIRE_TEMPLE_ENTRYWAY, world, [ (Regions.FIRE_TEMPLE_FIRST_ROOM, lambda bundle: True), (Regions.DMC_CENTRAL_LOCAL, lambda bundle: True, SOHDungeonExitNames.FIRE_TEMPLE_DUNGEON_EXIT, - SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY) ]) # Fire Temple First Room @@ -69,7 +69,7 @@ def set_region_rules(world: "SohWorld") -> None: (is_adult(bundle) and (can_do_trick(Tricks.FIRE_BOSS_DOOR_JUMP, bundle) or has_item(LocalEvents.FIRE_TEMPLE_FIRE_MAZE_UPPER_PLATFORM_HIT, bundle) or - can_use(Items.HOVER_BOOTS, bundle))), SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY) + can_use(Items.HOVER_BOOTS, bundle))), SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.BOSS_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.ONE_WAY) ]) # Fire Temple Loop Enemies diff --git a/worlds/oot_soh/location_access/dungeons/forest_temple.py b/worlds/oot_soh/location_access/dungeons/forest_temple.py index fd1b25694b91..6ebbf3437eb3 100644 --- a/worlds/oot_soh/location_access/dungeons/forest_temple.py +++ b/worlds/oot_soh/location_access/dungeons/forest_temple.py @@ -37,7 +37,7 @@ def set_region_rules(world: "SohWorld") -> None: # Todo: Change this when we have IsVanilla vs. IsMQ (Regions.FOREST_TEMPLE_FIRST_ROOM, lambda bundle: True), (Regions.SACRED_FOREST_MEADOW, lambda bundle: True, SOHDungeonExitNames.FOREST_TEMPLE_DUNGEON_EXIT, - SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY) ]) # Forest Temple First Room @@ -512,7 +512,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.FOREST_TEMPLE_BOSS_REGION, world, [ (Regions.FOREST_TEMPLE_LOBBY, lambda bundle: True), (Regions.FOREST_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True, SOHBossEntranceNames.FOREST_TEMPLE_BOSS_ENTRANCE, - SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY) + SOHEntranceGroups.BOSS_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.ONE_WAY) ]) # Forest Temple Boss Entryway diff --git a/worlds/oot_soh/location_access/dungeons/ganons_castle.py b/worlds/oot_soh/location_access/dungeons/ganons_castle.py index 91ffdbde8a99..c7e99516d5c9 100644 --- a/worlds/oot_soh/location_access/dungeons/ganons_castle.py +++ b/worlds/oot_soh/location_access/dungeons/ganons_castle.py @@ -33,7 +33,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.GANONS_CASTLE_ENTRYWAY, world, [ (Regions.GANONS_CASTLE_LOBBY, lambda bundle: True), (Regions.GANONS_CASTLE_LEDGE, lambda bundle: True, - SOHDungeonExitNames.GANONS_CASTLE_DUNGEON_EXIT, SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) + SOHDungeonExitNames.GANONS_CASTLE_DUNGEON_EXIT, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY) ]) # Ganon's Castle Lobby diff --git a/worlds/oot_soh/location_access/dungeons/gerudo_training_ground.py b/worlds/oot_soh/location_access/dungeons/gerudo_training_ground.py index a4fec8763365..5e426135db73 100644 --- a/worlds/oot_soh/location_access/dungeons/gerudo_training_ground.py +++ b/worlds/oot_soh/location_access/dungeons/gerudo_training_ground.py @@ -10,7 +10,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.GERUDO_TRAINING_GROUND_ENTRYWAY, world, [ (Regions.GERUDO_TRAINING_GROUND_LOBBY, lambda bundle: True), (Regions.GF_TO_GTG, lambda bundle: True, SOHDungeonExitNames.GERUDO_TRAINING_GROUND_DUNGEON_EXIT, - SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY), + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY), ]) # Gerudo Training Ground Lobby diff --git a/worlds/oot_soh/location_access/dungeons/ice_cavern.py b/worlds/oot_soh/location_access/dungeons/ice_cavern.py index ce8bfe566d93..01ccf2dfb0ba 100644 --- a/worlds/oot_soh/location_access/dungeons/ice_cavern.py +++ b/worlds/oot_soh/location_access/dungeons/ice_cavern.py @@ -17,7 +17,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.ICE_CAVERN_BEGINNING, lambda bundle: True), # Skipping MQ (Regions.ZF_LEDGE, lambda bundle: True, SOHDungeonExitNames.ICE_CAVERN_DUNGEON_EXIT, - SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY) ]) # Ice Cavern Beginning diff --git a/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py b/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py index a55249b02e3b..37e0fc802e5e 100644 --- a/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py +++ b/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py @@ -32,7 +32,7 @@ def set_region_rules(world: "SohWorld") -> None: # TODO: Add vanilla/MQ check (Regions.JABU_JABUS_BELLY_BEGINNING, lambda bundle: True), (Regions.ZORAS_FOUNTAIN, lambda bundle: True, SOHDungeonExitNames.JABU_JABUS_DUNGEON_EXIT, - SOHEntranceGroups.CHILD_DUNGEONS, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY) ]) # Jabu Jabu's Belly Beginning @@ -246,7 +246,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.JABU_JABUS_BELLY_NEAR_BOSS_ROOM, world, [ (Regions.JABU_JABUS_BELLY_MAIN, lambda bundle: True), (Regions.JABU_JABUS_BELLY_BOSS_ENTRYWAY, lambda bundle: can_use(Items.BOOMERANG, bundle) or (can_do_trick(Tricks.JABU_NEAR_BOSS_RANGED, bundle) and can_use_any([Items.HOOKSHOT, Items.FAIRY_BOW, Items.FAIRY_SLINGSHOT], bundle)) or ( - can_do_trick(Tricks.JABU_NEAR_BOSS_EXPLOSIVES, bundle) and (can_use(Items.BOMBCHUS_5, bundle) or (can_use(Items.HOVER_BOOTS, bundle) and can_use(Items.BOMB_BAG, bundle)))), SOHBossEntranceNames.JABU_JABUS_BOSS_ENTRANCE, SOHEntranceGroups.CHILD_ONLY_BOSSES, EntranceType.ONE_WAY) + can_do_trick(Tricks.JABU_NEAR_BOSS_EXPLOSIVES, bundle) and (can_use(Items.BOMBCHUS_5, bundle) or (can_use(Items.HOVER_BOOTS, bundle) and can_use(Items.BOMB_BAG, bundle)))), SOHBossEntranceNames.JABU_JABUS_BOSS_ENTRANCE, SOHEntranceGroups.BOSS_ENTRANCE | SOHEntranceGroups.CHILD_ONLY, EntranceType.ONE_WAY) ]) # Skipping master quest for now diff --git a/worlds/oot_soh/location_access/dungeons/shadow_temple.py b/worlds/oot_soh/location_access/dungeons/shadow_temple.py index c1c3a23c4295..9256a01974f8 100644 --- a/worlds/oot_soh/location_access/dungeons/shadow_temple.py +++ b/worlds/oot_soh/location_access/dungeons/shadow_temple.py @@ -17,7 +17,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.SHADOW_TEMPLE_BEGINNING, lambda bundle: (can_do_trick(Tricks.LENS_SHADOW, bundle) or can_use( Items.LENS_OF_TRUTH, bundle)) and (can_use(Items.HOVER_BOOTS, bundle) or can_use(Items.HOOKSHOT, bundle))), (Regions.GRAVEYARD_WARP_PAD_REGION, lambda bundle: True, - SOHDungeonExitNames.SHADOW_TEMPLE_DUNGEON_EXIT, SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) + SOHDungeonExitNames.SHADOW_TEMPLE_DUNGEON_EXIT, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.TWO_WAY) ]) # Shadow Temple Beginning @@ -179,7 +179,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.SHADOW_TEMPLE_BEYOND_BOAT, world, [ (Regions.SHADOW_TEMPLE_BOSS_ENTRYWAY, lambda bundle: (can_use(Items.FAIRY_BOW, bundle) or can_use(Items.DISTANT_SCARECROW, bundle) or (can_do_trick(Tricks.SHADOW_STATUE, bundle) and can_use(Items.BOMBCHUS_5, bundle))) - and small_keys(Items.SHADOW_TEMPLE_SMALL_KEY, 5, bundle) and can_use(Items.HOVER_BOOTS, bundle), SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.ADULT_BOSSES, EntranceType.ONE_WAY), + and small_keys(Items.SHADOW_TEMPLE_SMALL_KEY, 5, bundle) and can_use(Items.HOVER_BOOTS, bundle), SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE, SOHEntranceGroups.BOSS_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.ONE_WAY), ]) # Shadow Temple Boss Entryway diff --git a/worlds/oot_soh/location_access/dungeons/spirit_temple.py b/worlds/oot_soh/location_access/dungeons/spirit_temple.py index 3c35d116f541..d93664582547 100644 --- a/worlds/oot_soh/location_access/dungeons/spirit_temple.py +++ b/worlds/oot_soh/location_access/dungeons/spirit_temple.py @@ -15,7 +15,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.SPIRIT_TEMPLE_ENTRYWAY, world, [ (Regions.SPIRIT_TEMPLE_LOBBY, lambda bundle: True), (Regions.DESERT_COLOSSUS, lambda bundle: True, SOHDungeonExitNames.SPIRIT_TEMPLE_DUNGEON_EXIT, - SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.BOTH_AGE, EntranceType.TWO_WAY) ]) # Spirit Temple Lobby @@ -205,7 +205,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.SPIRIT_TEMPLE_INSIDE_STATUE_HEAD, world, [ (Regions.SPIRIT_TEMPLE_CENTRAL_CHAMBER, lambda bundle: True), (Regions.SPIRIT_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True, SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE, - SOHEntranceGroups.ADULT_ONLY_BOSSES, EntranceType.ONE_WAY) + SOHEntranceGroups.BOSS_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.ONE_WAY) ]) # Spirit Temple Boss Entryway diff --git a/worlds/oot_soh/location_access/dungeons/water_temple.py b/worlds/oot_soh/location_access/dungeons/water_temple.py index 210cc0d2c83c..a1d1822fbfe3 100644 --- a/worlds/oot_soh/location_access/dungeons/water_temple.py +++ b/worlds/oot_soh/location_access/dungeons/water_temple.py @@ -26,7 +26,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.WATER_TEMPLE_LOBBY, lambda bundle: ( has_item(Items.BRONZE_SCALE, bundle))), (Regions.LH_FROM_WATER_TEMPLE, lambda bundle: True, SOHDungeonExitNames.WATER_TEMPLE_DUNGEON_EXIT, - SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY) ]) # Water Temple Lobby @@ -561,7 +561,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.WATER_TEMPLE_PRE_BOSS_ROOM, world, [ (Regions.WATER_TEMPLE_LOBBY, lambda bundle: True), (Regions.WATER_TEMPLE_BOSS_ENTRYWAY, lambda bundle: True, SOHBossEntranceNames.WATER_TEMPLE_BOSS_ENTRANCE, - SOHEntranceGroups.ADULT_ONLY_BOSSES, EntranceType.ONE_WAY) + SOHEntranceGroups.BOSS_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.ONE_WAY) ]) # Water Temple Boss Entryway diff --git a/worlds/oot_soh/location_access/overworld/castle_grounds.py b/worlds/oot_soh/location_access/overworld/castle_grounds.py index 7c2279af46c0..7aa533442184 100644 --- a/worlds/oot_soh/location_access/overworld/castle_grounds.py +++ b/worlds/oot_soh/location_access/overworld/castle_grounds.py @@ -199,5 +199,5 @@ def set_region_rules(world: "SohWorld") -> None: and has_item(LocalEvents.HC_OGC_RAINBOW_BRIDGE_BUILT, bundle)), (Regions.HYRULE_CASTLE_GROUNDS, lambda bundle: is_child(bundle)), (Regions.GANONS_CASTLE_ENTRYWAY, lambda bundle: is_adult(bundle), - SOHDungeonEntranceNames.GANONS_CASTLE_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_ONLY_DUNGEONS, EntranceType.TWO_WAY) + SOHDungeonEntranceNames.GANONS_CASTLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.TWO_WAY) ]) diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py index a693debdbc22..f4d4f6bb2c6b 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py @@ -162,7 +162,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DMC_UPPER_NEARBY, lambda bundle: is_adult(bundle) and has_item(LocalEvents.DMC_BEAN_PLANTED, bundle)), (Regions.FIRE_TEMPLE_ENTRYWAY, lambda bundle: (is_child(bundle) and hearts(bundle) >= 3 and world.options.shuffle_dungeon_entrances.value > 0) or ( - is_adult(bundle) and fire_timer(bundle) >= 24), SOHDungeonEntranceNames.FIRE_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY), + is_adult(bundle) and fire_timer(bundle) >= 24), SOHDungeonEntranceNames.FIRE_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY), (Regions.DMC_DISTANT_PLATFORM, lambda bundle: (fire_timer(bundle) >= 48 or hearts(bundle) >= 2) and can_use(Items.DISTANT_SCARECROW, bundle)), ]) diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py index 5ecf381421a0..a922a0426968 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py @@ -67,7 +67,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: blast_or_smash(bundle) or (is_adult(bundle) and ((has_item(LocalEvents.DMT_BEAN_PLANTED, bundle) and has_item(Items.GORONS_BRACELET, bundle)) or (can_use(Items.HOVER_BOOTS, bundle) and can_do_trick(Tricks.DMT_CLIMB_HOVERS, bundle))))), (Regions.DODONGOS_CAVERN_ENTRYWAY, lambda bundle: has_explosives(bundle) or has_item(Items.GORONS_BRACELET, bundle) or is_adult( - bundle), SOHDungeonEntranceNames.DODONGOS_CAVERN_DUNGEON_ENTRANCE, SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY), + bundle), SOHDungeonEntranceNames.DODONGOS_CAVERN_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY), (Regions.DMT_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)) ]) diff --git a/worlds/oot_soh/location_access/overworld/desert_colossus.py b/worlds/oot_soh/location_access/overworld/desert_colossus.py index 1cc5f41b5f3e..3529554e12d9 100644 --- a/worlds/oot_soh/location_access/overworld/desert_colossus.py +++ b/worlds/oot_soh/location_access/overworld/desert_colossus.py @@ -61,7 +61,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.COLOSSUS_GREAT_FAIRY_FOUNTAIN, lambda bundle: has_explosives(bundle)), (Regions.SPIRIT_TEMPLE_ENTRYWAY, lambda bundle: True, SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE, - SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY), + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.BOTH_AGE, EntranceType.TWO_WAY), (Regions.WASTELAND_NEAR_COLOSSUS, lambda bundle: True), (Regions.COLOSSUS_GROTTO, lambda bundle: can_use( Items.SILVER_GAUNTLETS, bundle)) diff --git a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py index 6d884e4d571d..9072bdc24467 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py @@ -97,7 +97,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.GF_TO_GTG, world, [ (Regions.GERUDO_TRAINING_GROUND_ENTRYWAY, lambda bundle: has_item(LocalEvents.GTG_GATE_OPEN, bundle) and (is_adult(bundle) or world.options.shuffle_dungeon_entrances > - 0), SOHDungeonEntranceNames.GERUDO_TRAINING_GROUND_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_DUNGEONS, EntranceType.TWO_WAY), + 0), SOHDungeonEntranceNames.GERUDO_TRAINING_GROUND_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY), (Regions.GF_OUTSIDE_GTG, lambda bundle: is_child(bundle) or has_item(Items.GERUDO_MEMBERSHIP_CARD, bundle)), (Regions.GF_JAIL_WINDOW, lambda bundle: can_use(Items.HOOKSHOT, bundle)), diff --git a/worlds/oot_soh/location_access/overworld/graveyard.py b/worlds/oot_soh/location_access/overworld/graveyard.py index cd3f342d42c3..ce99bee2abd9 100644 --- a/worlds/oot_soh/location_access/overworld/graveyard.py +++ b/worlds/oot_soh/location_access/overworld/graveyard.py @@ -201,5 +201,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.GRAVEYARD_WARP_PAD_REGION, world, [ (Regions.THE_GRAVEYARD, lambda bundle: True), (Regions.SHADOW_TEMPLE_ENTRYWAY, lambda bundle: can_use(Items.DINS_FIRE, bundle) or (can_do_trick(Tricks.GY_SHADOW_FIRE_ARROWS, bundle) and is_adult( - bundle) and can_use(Items.FIRE_ARROW, bundle)), SOHDungeonEntranceNames.SHADOW_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY) + bundle) and can_use(Items.FIRE_ARROW, bundle)), SOHDungeonEntranceNames.SHADOW_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY) ]) diff --git a/worlds/oot_soh/location_access/overworld/kakariko.py b/worlds/oot_soh/location_access/overworld/kakariko.py index 5eb75d8d5801..f3e25e19529d 100644 --- a/worlds/oot_soh/location_access/overworld/kakariko.py +++ b/worlds/oot_soh/location_access/overworld/kakariko.py @@ -432,5 +432,5 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.KAKARIKO_VILLAGE, lambda bundle: is_adult(bundle) or has_item(Items.BRONZE_SCALE, bundle) or has_item(Events.DRAIN_WELL, bundle)), (Regions.BOTTOM_OF_THE_WELL_ENTRYWAY, lambda bundle: is_child(bundle) or (has_item(Events.DRAIN_WELL, bundle) and world.options.shuffle_dungeon_entrances.value > - 0), SOHDungeonEntranceNames.BOTTOM_OF_THE_WELL_DUNGEON_ENTRANCE, SOHEntranceGroups.BOTH_DUNGEONS, EntranceType.TWO_WAY) + 0), SOHDungeonEntranceNames.BOTTOM_OF_THE_WELL_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY) ]) diff --git a/worlds/oot_soh/location_access/overworld/kokiri_forest.py b/worlds/oot_soh/location_access/overworld/kokiri_forest.py index 066d27e2317e..c7203ca3b50a 100644 --- a/worlds/oot_soh/location_access/overworld/kokiri_forest.py +++ b/worlds/oot_soh/location_access/overworld/kokiri_forest.py @@ -212,7 +212,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.KF_OUTSIDE_DEKU_TREE, world, [ (Regions.DEKU_TREE_ENTRYWAY, lambda bundle: is_child(bundle) or (world.options.shuffle_dungeon_entrances.value > 0 and (world.options.closed_forest.value == 2 or has_item( - LocalEvents.MIDO_SWORD_AND_SHIELD, bundle))), SOHDungeonEntranceNames.DEKU_TREE_DUNGEON_ENTRANCE, SOHEntranceGroups.CHILD_DUNGEONS, EntranceType.TWO_WAY), + LocalEvents.MIDO_SWORD_AND_SHIELD, bundle))), SOHDungeonEntranceNames.DEKU_TREE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY), (Regions.KOKIRI_FOREST, lambda bundle: (is_adult(bundle) and (can_pass_enemy(bundle, Enemies.BIG_SKULLTULA) or has_item(Events.FOREST_TEMPLE_COMPLETED, bundle))) diff --git a/worlds/oot_soh/location_access/overworld/lake_hylia.py b/worlds/oot_soh/location_access/overworld/lake_hylia.py index 4eba984b3534..b28b903d89ec 100644 --- a/worlds/oot_soh/location_access/overworld/lake_hylia.py +++ b/worlds/oot_soh/location_access/overworld/lake_hylia.py @@ -194,7 +194,7 @@ def set_region_rules(world: "SohWorld") -> None: has_item(Items.GOLDEN_SCALE, bundle))) or (is_adult(bundle) and can_use(Items.LONGSHOT, bundle) and - has_item(Items.GOLDEN_SCALE, bundle))), SOHDungeonEntranceNames.WATER_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_ONLY_DUNGEONS, EntranceType.TWO_WAY), + has_item(Items.GOLDEN_SCALE, bundle))), SOHDungeonEntranceNames.WATER_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.TWO_WAY), ]) # LH Fishing Island diff --git a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py index de3265880fad..fe2becddd0f4 100644 --- a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py +++ b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py @@ -49,7 +49,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.SACRED_FOREST_MEADOW, world, [ (Regions.SFM_ENTRYWAY, lambda bundle: True), (Regions.FOREST_TEMPLE_ENTRYWAY, lambda bundle: can_use(Items.HOOKSHOT, bundle), - SOHDungeonEntranceNames.FOREST_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.ADULT_ONLY_DUNGEONS, EntranceType.TWO_WAY), + SOHDungeonEntranceNames.FOREST_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.TWO_WAY), (Regions.SFM_FAIRY_GROTTO, lambda bundle: True), (Regions.SFM_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)), ]) diff --git a/worlds/oot_soh/location_access/overworld/zoras_fountain.py b/worlds/oot_soh/location_access/overworld/zoras_fountain.py index 3d8e7b9ed256..7c7cda0a6cf9 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_fountain.py +++ b/worlds/oot_soh/location_access/overworld/zoras_fountain.py @@ -53,7 +53,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.ZF_ROCK, lambda bundle: is_adult( bundle) and can_use(Items.SCARECROW, bundle)), (Regions.JABU_JABUS_BELLY_ENTRYWAY, lambda bundle: is_child(bundle) and (can_use(Items.BOTTLE_WITH_FISH, bundle) - or world.options.jabu_jabu.value == 1), SOHDungeonEntranceNames.JABU_JABUS_DUNGEON_ENTRANCE, SOHEntranceGroups.CHILD_ONLY_DUNGEONS, EntranceType.TWO_WAY), + or world.options.jabu_jabu.value == 1), SOHDungeonEntranceNames.JABU_JABUS_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD_ONLY, EntranceType.TWO_WAY), (Regions.ZF_GREAT_FAIRY_FOUNTAIN, lambda bundle: has_explosives(bundle) or (can_do_trick( Tricks.ZF_GREAT_FAIRY_WITHOUT_EXPLOSIVES, bundle) and can_use(Items.MEGATON_HAMMER, bundle) and can_use(Items.SILVER_GAUNTLETS, bundle))) ]) @@ -125,7 +125,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.ZF_ICEBERGS, lambda bundle: is_adult(bundle)), (Regions.ZF_LAKEBED, lambda bundle: can_use(Items.IRON_BOOTS, bundle)), (Regions.ICE_CAVERN_ENTRYWAY, lambda bundle: True, SOHDungeonEntranceNames.ICE_CAVERN_DUNGEON_ENTRANCE, - SOHEntranceGroups.ADULT_ONLY_DUNGEONS, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.TWO_WAY) ]) # Zora's Fountain Hidden Cave From 1b77741b29a42d599e61bc26ae08dd977a88f7c5 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Fri, 7 Nov 2025 08:32:21 -0500 Subject: [PATCH 09/22] add indirect conditions --- worlds/oot_soh/EntranceShuffle.py | 13 ++++++++- worlds/oot_soh/Enums.py | 21 ++++++++++++++ worlds/oot_soh/LogicHelpers.py | 2 +- worlds/oot_soh/__init__.py | 28 +++++++++++-------- .../location_access/dungeons/deku_tree.py | 2 +- .../dungeons/dodongos_cavern.py | 2 +- .../location_access/dungeons/fire_temple.py | 2 +- .../location_access/dungeons/forest_temple.py | 2 +- .../dungeons/jabujabus_belly.py | 2 +- .../location_access/dungeons/shadow_temple.py | 2 +- .../location_access/dungeons/spirit_temple.py | 2 +- .../location_access/dungeons/water_temple.py | 2 +- 12 files changed, 58 insertions(+), 22 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 20c5b87b1ea1..cbbf8d38cef2 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -1,6 +1,6 @@ from typing import TYPE_CHECKING, Callable from BaseClasses import Location, Region -from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups +from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups, Regions, SOHBossWarpEntranceNames from .Locations import SohLocation from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances, bake_target_group_lookup from entrance_rando import ERPlacementState, Entrance @@ -22,6 +22,17 @@ SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SPIRIT_TEMPLE_BOSS_EXIT, } +boss_indirect_condition_matching = { + SOHBossEntranceNames.DEKU_TREE_BOSS_ENTRANCE: (Regions.DEKU_TREE_BOSS_ROOM, SOHBossWarpEntranceNames.DEKU_TREE_BOSS_WARP_ENTRANCE), + SOHBossEntranceNames.DODONGOS_CAVERN_BOSS_ENTRANCE: (Regions.DODONGOS_CAVERN_BOSS_ROOM, SOHBossWarpEntranceNames.DODONGOS_CAVERN_BOSS_WARP_ENTRANCE), + SOHBossEntranceNames.JABU_JABUS_BOSS_ENTRANCE: (Regions.JABU_JABUS_BELLY_BOSS_ROOM, SOHBossWarpEntranceNames.JABU_JABUS_BOSS_WARP_ENTRANCE), + SOHBossEntranceNames.FOREST_TEMPLE_BOSS_ENTRANCE: (Regions.FOREST_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.FOREST_TEMPLE_BOSS_WARP_ENTRANCE), + SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE: (Regions.FIRE_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.FIRE_TEMPLE_BOSS_WARP_ENTRANCE), + SOHBossEntranceNames.WATER_TEMPLE_BOSS_ENTRANCE: (Regions.WATER_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.WATER_TEMPLE_BOSS_WARP_ENTRANCE), + SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE: (Regions.SHADOW_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.SHADOW_TEMPLE_BOSS_WARP_ENTRANCE), + SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: (Regions.SPIRIT_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.SPIRIT_TEMPLE_BOSS_WARP_ENTRANCE), +} + default_group_lookup = { SOHEntranceGroups.DUNGEON_ENTRANCE: [SOHEntranceGroups.DUNGEON_ENTRANCE], SOHEntranceGroups.BOSS_ENTRANCE: [SOHEntranceGroups.BOSS_ENTRANCE], diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index 94851505c226..ced83d0b3548 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -3919,3 +3919,24 @@ class SOHBossEntranceExitNames(StrEnum): WATER_TEMPLE_BOSS_EXIT = "Water Temple Dungeon Boss Exit" SHADOW_TEMPLE_BOSS_EXIT = "Shadow Temple Dungeon Boss Exit" SPIRIT_TEMPLE_BOSS_EXIT = "Spirit Temple Dungeon Boss Exit" + +class SOHBossWarpEntranceNames(StrEnum): + DEKU_TREE_BOSS_WARP_ENTRANCE = "Deku Tree Dungeon Boss Warp Entrance" + DODONGOS_CAVERN_BOSS_WARP_ENTRANCE = "Dodongos Cavern Dungeon Boss Warp Entrance" + JABU_JABUS_BOSS_WARP_ENTRANCE = "Jabu Jabus Dungeon Boss Warp Entrance" + FOREST_TEMPLE_BOSS_WARP_ENTRANCE = "Forest Temple Dungeon Boss Warp Entrance" + FIRE_TEMPLE_BOSS_WARP_ENTRANCE = "Fire Temple Dungeon Boss Warp Entrance" + WATER_TEMPLE_BOSS_WARP_ENTRANCE = "Water Temple Dungeon Boss Warp Entrance" + SHADOW_TEMPLE_BOSS_WARP_ENTRANCE = "Shadow Temple Dungeon Boss Warp Entrance" + SPIRIT_TEMPLE_BOSS_WARP_ENTRANCE = "Spirit Temple Dungeon Boss Warp Entrance" + + +class SOHBossWarpExitNames(StrEnum): + DEKU_TREE_BOSS_WARP_EXIT = "Deku Tree Dungeon Boss Warp Exit" + DODONGOS_CAVERN_BOSS_WARP_EXIT = "Dodongos Cavern Dungeon Boss Warp Exit" + JABU_JABUS_BOSS_WARP_EXIT = "Jabu Jabus Dungeon Boss Warp Exit" + FOREST_TEMPLE_BOSS_WARP_EXIT = "Forest Temple Dungeon Boss Warp Exit" + FIRE_TEMPLE_BOSS_WARP_EXIT = "Fire Temple Dungeon Boss Warp Exit" + WATER_TEMPLE_BOSS_WARP_EXIT = "Water Temple Dungeon Boss Warp Exit" + SHADOW_TEMPLE_BOSS_WARP_EXIT = "Shadow Temple Dungeon Boss Warp Exit" + SPIRIT_TEMPLE_BOSS_WARP_EXIT = "Spirit Temple Dungeon Boss Warp Exit" \ No newline at end of file diff --git a/worlds/oot_soh/LogicHelpers.py b/worlds/oot_soh/LogicHelpers.py index 275bcf0ba79b..ca19f839c09f 100644 --- a/worlds/oot_soh/LogicHelpers.py +++ b/worlds/oot_soh/LogicHelpers.py @@ -47,7 +47,7 @@ def locationRule(bundle): return True def connect_regions(parent_region: Regions, world: "SohWorld", - child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool], SOHBossEntranceNames | SOHDungeonExitNames, int, EntranceType]]) -> None: + child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool], SOHBossEntranceNames | SOHDungeonExitNames | SOHBossWarpEntranceNames | SOHBossEntranceExitNames, int, EntranceType]]) -> None: for region in child_regions: regionName = region[0] entranceName = None diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index 875222ba7c02..2a8bfb3d75f3 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -18,7 +18,7 @@ from .UniversalTracker import setup_options_from_slot_data from settings import Group, Bool from Options import OptionError -from .EntranceShuffle import randomize_entrances_soh, on_connect_soh_sheik_at_colossus +from .EntranceShuffle import randomize_entrances_soh, on_connect_soh_sheik_at_colossus, boss_indirect_condition_matching from entrance_rando import bake_target_group_lookup import logging @@ -107,9 +107,6 @@ def generate_early(self) -> None: if self.options.shuffle_scrubs_minimum_price.value > self.options.shuffle_scrubs_maximum_price.value: self.options.shuffle_scrubs_maximum_price.value = self.options.shuffle_scrubs_minimum_price.value - # Entrance Rando stuff - if (self.options.shuffle_dungeon_entrances.value > 0 or self.options.shuffle_boss_entrances.value > 0): - self.explicit_indirect_conditions = True def create_regions(self) -> None: create_regions_and_locations(self) @@ -178,22 +175,29 @@ def connect_entrances(self): # Boss Entrances if self.options.shuffle_boss_entrances.value > 0: - for entrance in SOHBossEntranceNames: - entrances_to_shuffle.add(entrance) + for entranceName in SOHBossEntranceNames: + entrances_to_shuffle.add(entranceName) + + region = self.get_region(str(boss_indirect_condition_matching[entranceName][0])) + entrance = self.get_entrance(str(boss_indirect_condition_matching[entranceName][1])) + self.multiworld.register_indirect_condition(region, entrance) + if self.options.shuffle_boss_entrances.value == 1: randomize_entrances_soh(self, entrances_to_shuffle, ageRestricted=True) entrances_to_shuffle.clear() + print(self.multiworld.indirect_connections) + # Dungeon Entrances if self.options.shuffle_dungeon_entrances.value > 0: - for entrance in SOHDungeonExitNames: - if entrance != SOHDungeonExitNames.GANONS_CASTLE_DUNGEON_EXIT or self.options.shuffle_dungeon_entrances == 2: - entrances_to_shuffle.add(entrance) + for entranceName in SOHDungeonExitNames: + if entranceName != SOHDungeonExitNames.GANONS_CASTLE_DUNGEON_EXIT or self.options.shuffle_dungeon_entrances == 2: + entrances_to_shuffle.add(entranceName) - for entrance in SOHDungeonEntranceNames: - if entrance != SOHDungeonEntranceNames.GANONS_CASTLE_DUNGEON_ENTRANCE or self.options.shuffle_dungeon_entrances == 2: - entrances_to_shuffle.add(entrance) + for entranceName in SOHDungeonEntranceNames: + if entranceName != SOHDungeonEntranceNames.GANONS_CASTLE_DUNGEON_ENTRANCE or self.options.shuffle_dungeon_entrances == 2: + entrances_to_shuffle.add(entranceName) # randomize_entrances_soh( # self, entrances_to_shuffle, on_connect_soh_sheik_at_colossus, coupled) diff --git a/worlds/oot_soh/location_access/dungeons/deku_tree.py b/worlds/oot_soh/location_access/dungeons/deku_tree.py index d63c74429910..ae3b4c916020 100644 --- a/worlds/oot_soh/location_access/dungeons/deku_tree.py +++ b/worlds/oot_soh/location_access/dungeons/deku_tree.py @@ -329,5 +329,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.DEKU_TREE_BOSS_ROOM, world, [ (Regions.DEKU_TREE_BOSS_EXIT, lambda bundle: True), (Regions.KF_OUTSIDE_DEKU_TREE, lambda bundle: has_item( - Events.DEKU_TREE_COMPLETED, bundle)) + Events.DEKU_TREE_COMPLETED, bundle), SOHBossWarpEntranceNames.DEKU_TREE_BOSS_WARP_ENTRANCE, SOHEntranceGroups.OTHER, EntranceType.ONE_WAY) ]) diff --git a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py index addc49365a11..fe47bea35e29 100644 --- a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py +++ b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py @@ -454,5 +454,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.DODONGOS_CAVERN_BOSS_ROOM, world, [ (Regions.DODONGOS_CAVERN_BOSS_EXIT, lambda bundle: True), (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: has_item( - Events.DODONGOS_CAVERN_COMPLETED, bundle)), + Events.DODONGOS_CAVERN_COMPLETED, bundle), SOHBossWarpEntranceNames.DODONGOS_CAVERN_BOSS_WARP_ENTRANCE, SOHEntranceGroups.OTHER, EntranceType.ONE_WAY), ]) diff --git a/worlds/oot_soh/location_access/dungeons/fire_temple.py b/worlds/oot_soh/location_access/dungeons/fire_temple.py index 2bd668098c31..be0e5a571522 100644 --- a/worlds/oot_soh/location_access/dungeons/fire_temple.py +++ b/worlds/oot_soh/location_access/dungeons/fire_temple.py @@ -555,5 +555,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.FIRE_TEMPLE_BOSS_ROOM, world, [ (Regions.FIRE_TEMPLE_BOSS_ENTRYWAY, lambda bundle: False), (Regions.DMC_CENTRAL_LOCAL, lambda bundle: has_item( - Events.FIRE_TEMPLE_COMPLETED, bundle)) + Events.FIRE_TEMPLE_COMPLETED, bundle), SOHBossWarpEntranceNames.FIRE_TEMPLE_BOSS_WARP_ENTRANCE, SOHEntranceGroups.OTHER, EntranceType.ONE_WAY) ]) diff --git a/worlds/oot_soh/location_access/dungeons/forest_temple.py b/worlds/oot_soh/location_access/dungeons/forest_temple.py index 6ebbf3437eb3..56dfa3ccb793 100644 --- a/worlds/oot_soh/location_access/dungeons/forest_temple.py +++ b/worlds/oot_soh/location_access/dungeons/forest_temple.py @@ -541,5 +541,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.FOREST_TEMPLE_BOSS_ROOM, world, [ (Regions.FOREST_TEMPLE_BOSS_ENTRYWAY, lambda bundle: False), (Regions.SACRED_FOREST_MEADOW, lambda bundle: has_item( - Events.FOREST_TEMPLE_COMPLETED, bundle)) + Events.FOREST_TEMPLE_COMPLETED, bundle), SOHBossWarpEntranceNames.FOREST_TEMPLE_BOSS_WARP_ENTRANCE, SOHEntranceGroups.OTHER, EntranceType.ONE_WAY) ]) diff --git a/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py b/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py index 37e0fc802e5e..09c4d54c9ec1 100644 --- a/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py +++ b/worlds/oot_soh/location_access/dungeons/jabujabus_belly.py @@ -293,5 +293,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.JABU_JABUS_BELLY_BOSS_ROOM, world, [ # (Regions.JABU_JABUS_BELLY_BOSS_EXIT, lambda bundle: False), # readd for MQ stuff (Regions.ZORAS_FOUNTAIN, lambda bundle: has_item( - Events.JABU_JABUS_BELLY_COMPLETED, bundle)) + Events.JABU_JABUS_BELLY_COMPLETED, bundle), SOHBossWarpEntranceNames.JABU_JABUS_BOSS_WARP_ENTRANCE, SOHEntranceGroups.OTHER, EntranceType.ONE_WAY) ]) diff --git a/worlds/oot_soh/location_access/dungeons/shadow_temple.py b/worlds/oot_soh/location_access/dungeons/shadow_temple.py index 9256a01974f8..c075ca9ae6e7 100644 --- a/worlds/oot_soh/location_access/dungeons/shadow_temple.py +++ b/worlds/oot_soh/location_access/dungeons/shadow_temple.py @@ -207,5 +207,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.SHADOW_TEMPLE_BOSS_ROOM, world, [ (Regions.SHADOW_TEMPLE_BOSS_ENTRYWAY, lambda bundle: False), (Regions.GRAVEYARD_WARP_PAD_REGION, lambda bundle: has_item( - Events.SHADOW_TEMPLE_COMPLETED, bundle)) + Events.SHADOW_TEMPLE_COMPLETED, bundle), SOHBossWarpEntranceNames.SHADOW_TEMPLE_BOSS_WARP_ENTRANCE, SOHEntranceGroups.OTHER, EntranceType.ONE_WAY) ]) diff --git a/worlds/oot_soh/location_access/dungeons/spirit_temple.py b/worlds/oot_soh/location_access/dungeons/spirit_temple.py index d93664582547..2adcd28de205 100644 --- a/worlds/oot_soh/location_access/dungeons/spirit_temple.py +++ b/worlds/oot_soh/location_access/dungeons/spirit_temple.py @@ -233,5 +233,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.SPIRIT_TEMPLE_BOSS_ROOM, world, [ (Regions.SPIRIT_TEMPLE_BOSS_ENTRYWAY, lambda bundle: False), (Regions.DESERT_COLOSSUS, lambda bundle: has_item( - Events.SPIRIT_TEMPLE_COMPLETED, bundle)) + Events.SPIRIT_TEMPLE_COMPLETED, bundle), SOHBossWarpEntranceNames.SPIRIT_TEMPLE_BOSS_WARP_ENTRANCE, SOHEntranceGroups.OTHER, EntranceType.ONE_WAY) ]) diff --git a/worlds/oot_soh/location_access/dungeons/water_temple.py b/worlds/oot_soh/location_access/dungeons/water_temple.py index a1d1822fbfe3..c91a3ad6983a 100644 --- a/worlds/oot_soh/location_access/dungeons/water_temple.py +++ b/worlds/oot_soh/location_access/dungeons/water_temple.py @@ -589,5 +589,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.WATER_TEMPLE_BOSS_ROOM, world, [ (Regions.WATER_TEMPLE_BOSS_ENTRYWAY, lambda bundle: False), (Regions.LAKE_HYLIA, lambda bundle: has_item( - Events.WATER_TEMPLE_COMPLETED, bundle)) + Events.WATER_TEMPLE_COMPLETED, bundle), SOHBossWarpEntranceNames.WATER_TEMPLE_BOSS_WARP_ENTRANCE, SOHEntranceGroups.OTHER, EntranceType.ONE_WAY) ]) From 8ad5334a2aba03cf3145a5e6f317e951fcc4e2dc Mon Sep 17 00:00:00 2001 From: mattman107 Date: Sat, 8 Nov 2025 13:26:12 -0500 Subject: [PATCH 10/22] Add retries to the our GER randomization. --- worlds/oot_soh/EntranceShuffle.py | 16 +++++++++++++--- worlds/oot_soh/__init__.py | 13 +------------ .../overworld/death_mountain_trail.py | 2 +- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index cbbf8d38cef2..431444302a9d 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -2,7 +2,7 @@ from BaseClasses import Location, Region from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups, Regions, SOHBossWarpEntranceNames from .Locations import SohLocation -from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances, bake_target_group_lookup +from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances, bake_target_group_lookup, EntranceRandomizationError from entrance_rando import ERPlacementState, Entrance from .LogicHelpers import rule_wrapper from worlds.generic.Rules import set_rule @@ -45,6 +45,8 @@ for group in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO, SOHEntranceGroups.OWL_DROP, SOHEntranceGroups.WARP_SONG)} +# This is allowing us to brute force the problem of GER failing. May be a necessary evil as it doesn't do swap or automatic retries itself. +OOT_SOH_GER_RETRIES_AMOUNT: int = 1000 def get_target_groups(group: int) -> list[int]: type = group & SOHEntranceGroups.TYPE_MASK @@ -101,8 +103,16 @@ def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBoss else: target_group_lookup = bake_target_group_lookup(world, get_target_groups) - randomize_entrances( - world, coupled, target_group_lookup, True, on_connect=on_connect) + for i in range(OOT_SOH_GER_RETRIES_AMOUNT): + try: + randomize_entrances( + world, coupled, target_group_lookup, False, on_connect=on_connect) + break + except EntranceRandomizationError as error: + if i >= OOT_SOH_GER_RETRIES_AMOUNT - 1: + raise EntranceRandomizationError(f"OOT SOH: failed GER after {OOT_SOH_GER_RETRIES_AMOUNT} " + f"attempts. Final error here: \n\n{error}") + # This should probably be double checked by someone who knows how to properly remove a location from a region and give it a new parent region diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index e58ee3f64eeb..0aa893fa01de 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -180,24 +180,18 @@ def connect_entrances(self): entrances_to_shuffle = set() # Reverse decoupled option for randomize_entrances because it is asking if you wanted coupled # Update this when it is figured out why decoupled doesn't work with the current groupings - coupled = True#(not self.options.decouple_entrances) + coupled = (not self.options.decouple_entrances) # Boss Entrances if self.options.shuffle_boss_entrances.value > 0: for entranceName in SOHBossEntranceNames: entrances_to_shuffle.add(entranceName) - region = self.get_region(str(boss_indirect_condition_matching[entranceName][0])) - entrance = self.get_entrance(str(boss_indirect_condition_matching[entranceName][1])) - self.multiworld.register_indirect_condition(region, entrance) - if self.options.shuffle_boss_entrances.value == 1: randomize_entrances_soh(self, entrances_to_shuffle, ageRestricted=True) entrances_to_shuffle.clear() - print(self.multiworld.indirect_connections) - # Dungeon Entrances if self.options.shuffle_dungeon_entrances.value > 0: for entranceName in SOHDungeonExitNames: @@ -208,11 +202,6 @@ def connect_entrances(self): if entranceName != SOHDungeonEntranceNames.GANONS_CASTLE_DUNGEON_ENTRANCE or self.options.shuffle_dungeon_entrances == 2: entrances_to_shuffle.add(entranceName) - # randomize_entrances_soh( - # self, entrances_to_shuffle, on_connect_soh_sheik_at_colossus, coupled) - - # entrances_to_shuffle.clear() - randomize_entrances_soh( self, entrances_to_shuffle, on_connect_soh_sheik_at_colossus, coupled) diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py index a922a0426968..bdb3273d39fc 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py @@ -67,7 +67,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: blast_or_smash(bundle) or (is_adult(bundle) and ((has_item(LocalEvents.DMT_BEAN_PLANTED, bundle) and has_item(Items.GORONS_BRACELET, bundle)) or (can_use(Items.HOVER_BOOTS, bundle) and can_do_trick(Tricks.DMT_CLIMB_HOVERS, bundle))))), (Regions.DODONGOS_CAVERN_ENTRYWAY, lambda bundle: has_explosives(bundle) or has_item(Items.GORONS_BRACELET, bundle) or is_adult( - bundle), SOHDungeonEntranceNames.DODONGOS_CAVERN_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY), + bundle), SOHDungeonEntranceNames.DODONGOS_CAVERN_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.BOTH_AGE, EntranceType.TWO_WAY), (Regions.DMT_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)) ]) From 7fb00c4bcf65d0a388771eef6b208876fce2a021 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Sat, 8 Nov 2025 14:21:22 -0500 Subject: [PATCH 11/22] allow mixed entrances. It appears as though GER is preventing boss entrances into dungeon entrances though as dungeon entrances are like sudo dead ends. It like to keep goes as much as it can. --- worlds/oot_soh/EntranceShuffle.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 431444302a9d..256d31f7872b 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -44,6 +44,7 @@ SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO, SOHEntranceGroups.OWL_DROP, SOHEntranceGroups.WARP_SONG)] for group in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO, SOHEntranceGroups.OWL_DROP, SOHEntranceGroups.WARP_SONG)} + # This is allowing us to brute force the problem of GER failing. May be a necessary evil as it doesn't do swap or automatic retries itself. OOT_SOH_GER_RETRIES_AMOUNT: int = 1000 @@ -72,6 +73,29 @@ def get_target_groups(group: int) -> list[int]: return [pair_type | age for pair_type in default_group_lookup[type]] +def get_target_groups_mixed_entrance_pools(group: int) -> list[int]: + type = group & SOHEntranceGroups.TYPE_MASK + age = group & SOHEntranceGroups.AGE_MASK + + if(age == SOHEntranceGroups.ANY_AGE): + return [pair_type | ages for pair_type in mixed_group_lookup[type] for ages in (SOHEntranceGroups.ANY_AGE, SOHEntranceGroups.CHILD, SOHEntranceGroups.ADULT, SOHEntranceGroups.CHILD_ONLY, SOHEntranceGroups.ADULT_ONLY, SOHEntranceGroups.BOTH_AGE)] + + if(age == SOHEntranceGroups.BOTH_AGE): + return [pair_type | ages for pair_type in mixed_group_lookup[type] for ages in (SOHEntranceGroups.BOTH_AGE, SOHEntranceGroups.ADULT, SOHEntranceGroups.CHILD, SOHEntranceGroups.ANY_AGE)] + + if(age == SOHEntranceGroups.CHILD): + return [pair_type | ages for pair_type in mixed_group_lookup[type] for ages in (SOHEntranceGroups.CHILD, SOHEntranceGroups.CHILD_ONLY, SOHEntranceGroups.ADULT, SOHEntranceGroups.BOTH_AGE, SOHEntranceGroups.ANY_AGE)] + + if(age == SOHEntranceGroups.ADULT): + return [pair_type | ages for pair_type in mixed_group_lookup[type] for ages in (SOHEntranceGroups.ADULT, SOHEntranceGroups.ADULT_ONLY, SOHEntranceGroups.CHILD, SOHEntranceGroups.BOTH_AGE, SOHEntranceGroups.ANY_AGE)] + + if(age == SOHEntranceGroups.ADULT_ONLY): + return [pair_type | ages for pair_type in mixed_group_lookup[type] for ages in (SOHEntranceGroups.ADULT_ONLY, SOHEntranceGroups.ADULT, SOHEntranceGroups.ANY_AGE)] + + if(age == SOHEntranceGroups.CHILD_ONLY): + return [pair_type | ages for pair_type in mixed_group_lookup[type] for ages in (SOHEntranceGroups.CHILD_ONLY, SOHEntranceGroups.CHILD, SOHEntranceGroups.ANY_AGE)] + + return [pair_type | age for pair_type in mixed_group_lookup[type]] def get_target_groups_age_restrictive(group: int) -> list[int]: type = group & SOHEntranceGroups.TYPE_MASK @@ -100,6 +124,8 @@ def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBoss if ageRestricted: target_group_lookup = bake_target_group_lookup(world, get_target_groups_age_restrictive) + elif world.options.mixed_entrances_pools: + target_group_lookup = bake_target_group_lookup(world, get_target_groups_mixed_entrance_pools) else: target_group_lookup = bake_target_group_lookup(world, get_target_groups) From 44e7f1f0f122943179d2a9ee99fbdd9edcf102ed Mon Sep 17 00:00:00 2001 From: mattman107 Date: Fri, 14 Nov 2025 23:17:55 -0500 Subject: [PATCH 12/22] Fix GER retries and update groupings Disable decouple and mixed options as they don't work --- worlds/oot_soh/EntranceShuffle.py | 19 +++++++++++++------ worlds/oot_soh/Options.py | 6 ++++-- worlds/oot_soh/__init__.py | 14 +++++++++----- .../dungeons/bottom_of_the_well.py | 2 +- .../dungeons/dodongos_cavern.py | 2 +- .../overworld/death_mountain_crater.py | 2 +- .../overworld/death_mountain_trail.py | 2 +- .../overworld/desert_colossus.py | 2 +- .../overworld/gerudo_fortress.py | 2 +- .../location_access/overworld/graveyard.py | 2 +- .../location_access/overworld/kakariko.py | 2 +- .../overworld/kokiri_forest.py | 2 +- 12 files changed, 35 insertions(+), 22 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 256d31f7872b..178ceb153171 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -1,5 +1,5 @@ from typing import TYPE_CHECKING, Callable -from BaseClasses import Location, Region +from BaseClasses import Location, Region, Entrance from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups, Regions, SOHBossWarpEntranceNames from .Locations import SohLocation from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances, bake_target_group_lookup, EntranceRandomizationError @@ -47,7 +47,7 @@ # This is allowing us to brute force the problem of GER failing. May be a necessary evil as it doesn't do swap or automatic retries itself. -OOT_SOH_GER_RETRIES_AMOUNT: int = 1000 +OOT_SOH_GER_RETRIES_AMOUNT: int = 10 def get_target_groups(group: int) -> list[int]: type = group & SOHEntranceGroups.TYPE_MASK @@ -118,27 +118,34 @@ def get_target_groups_age_restrictive(group: int) -> list[int]: # Might need to return the ER Placement state at the end def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None, coupled: bool = True, ageRestricted: bool = False) -> None: + temp_entrances: list[Entrance] = list() for entranceEnum in entrances_to_shuffle: disconnect_entrance_for_randomization(world.multiworld.get_entrance( entranceEnum.value, world.player), one_way_target_name=entrance_matching[entranceEnum].value if entranceEnum in entrance_matching else None) if ageRestricted: target_group_lookup = bake_target_group_lookup(world, get_target_groups_age_restrictive) - elif world.options.mixed_entrances_pools: + elif False:#world.options.mixed_entrances_pools: target_group_lookup = bake_target_group_lookup(world, get_target_groups_mixed_entrance_pools) else: target_group_lookup = bake_target_group_lookup(world, get_target_groups) + for i in range(OOT_SOH_GER_RETRIES_AMOUNT): try: - randomize_entrances( - world, coupled, target_group_lookup, False, on_connect=on_connect) + er_state = randomize_entrances(world, coupled, target_group_lookup, False, on_connect=on_connect) + world.er_pairings += er_state.pairings + print(f"Took {i} attempts to get GER working.") break except EntranceRandomizationError as error: if i >= OOT_SOH_GER_RETRIES_AMOUNT - 1: raise EntranceRandomizationError(f"OOT SOH: failed GER after {OOT_SOH_GER_RETRIES_AMOUNT} " f"attempts. Final error here: \n\n{error}") - + # need to disconnect all entrances that are supposed to be shuffled + for entranceEnum in entrances_to_shuffle: + _exit: Entrance = world.multiworld.get_entrance(entranceEnum.value, world.player) + if (_exit.randomization_group in target_group_lookup and _exit.parent_region and _exit.connected_region and _exit.name not in world.er_pairings): + disconnect_entrance_for_randomization(_exit, one_way_target_name=entrance_matching[entranceEnum].value if entranceEnum in entrance_matching else None) # This should probably be double checked by someone who knows how to properly remove a location from a region and give it a new parent region diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index b43d9bcd96a7..a5dfb5c5f24c 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -910,20 +910,22 @@ class ShuffleDungeonEntrances(Choice): option_on_plus_ganon = 2 default = 0 - +#currently doesn't work class DecoupleEntrances(Toggle): """ Decouple entrances when shuffling them. This means that you are no longer guaranteed to end up back where you came from when you go back through an entrance. This also adds the one way entrance from Gerudo Valley to Lake Hylia in the pool of overworld entrances when they are shuffled. """ display_name = "Decouple Entrances" + visibility = Visibility.none - +#currently doesn't work class MixedEntrancePools(Toggle): """ Shuffle entrances into a mixed pool instead of separate ones. Has no effect on pools whose entrances aren't shuffled, and "Shuffle Boss Entrances" must be set to "Full" to include them. """ display_name = "Mixed Entrances Pools" + visibility = Visibility.none @dataclass diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index 0aa893fa01de..ed1ee72d8cec 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -67,6 +67,7 @@ class SohWorld(World): item_name_to_id = item_table item_name_groups = item_name_groups location_name_groups = location_name_groups + er_pairings: List[tuple[str, str]] = [] # Universal Tracker stuff, does not do anything in normal gen glitches_item_name = Items.GLITCHED @@ -180,20 +181,23 @@ def connect_entrances(self): entrances_to_shuffle = set() # Reverse decoupled option for randomize_entrances because it is asking if you wanted coupled # Update this when it is figured out why decoupled doesn't work with the current groupings - coupled = (not self.options.decouple_entrances) + coupled = True #(not self.options.decouple_entrances) # Boss Entrances - if self.options.shuffle_boss_entrances.value > 0: + if self.options.shuffle_boss_entrances: for entranceName in SOHBossEntranceNames: entrances_to_shuffle.add(entranceName) - - if self.options.shuffle_boss_entrances.value == 1: + if self.options.shuffle_boss_entrances == "age_restricted": randomize_entrances_soh(self, entrances_to_shuffle, ageRestricted=True) entrances_to_shuffle.clear() + else: + # Need this else here. Mixed entrances doesn't work + randomize_entrances_soh(self, entrances_to_shuffle) + entrances_to_shuffle.clear() # Dungeon Entrances - if self.options.shuffle_dungeon_entrances.value > 0: + if self.options.shuffle_dungeon_entrances: for entranceName in SOHDungeonExitNames: if entranceName != SOHDungeonExitNames.GANONS_CASTLE_DUNGEON_EXIT or self.options.shuffle_dungeon_entrances == 2: entrances_to_shuffle.add(entranceName) diff --git a/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py b/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py index 368da5d5a563..e962936e4b39 100644 --- a/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py +++ b/worlds/oot_soh/location_access/dungeons/bottom_of_the_well.py @@ -27,7 +27,7 @@ def set_region_rules(world: "SohWorld") -> None: bundle) and can_pass_enemy(bundle, Enemies.BIG_SKULLTULA)), # [Regions.BOTTOM_OF_THE_WELL_MQ_PERIMETER, lambda bundle: is_child(bundle), (Regions.KAK_WELL, lambda bundle: True, SOHDungeonExitNames.BOTTOM_OF_THE_WELL_DUNGEON_EXIT, - SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY) + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD_ONLY, EntranceType.TWO_WAY) ]) # Bottom of the Well Perimeter diff --git a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py index fe47bea35e29..58659bbeff36 100644 --- a/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py +++ b/worlds/oot_soh/location_access/dungeons/dodongos_cavern.py @@ -27,7 +27,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.DODONGOS_CAVERN_ENTRYWAY, world, [ (Regions.DODONGOS_CAVERN_BEGINNING, lambda bundle: True), (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True, SOHDungeonExitNames.DODONGOS_CAVERN_DUNGEON_EXIT, - SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.BOTH_AGE, EntranceType.TWO_WAY), + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY), ]) # Dodongos Cavern Beginning # Connections diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py index f4d4f6bb2c6b..28ca0de531f6 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py @@ -162,7 +162,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DMC_UPPER_NEARBY, lambda bundle: is_adult(bundle) and has_item(LocalEvents.DMC_BEAN_PLANTED, bundle)), (Regions.FIRE_TEMPLE_ENTRYWAY, lambda bundle: (is_child(bundle) and hearts(bundle) >= 3 and world.options.shuffle_dungeon_entrances.value > 0) or ( - is_adult(bundle) and fire_timer(bundle) >= 24), SOHDungeonEntranceNames.FIRE_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY), + is_adult(bundle) and fire_timer(bundle) >= 24), SOHDungeonEntranceNames.FIRE_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY), (Regions.DMC_DISTANT_PLATFORM, lambda bundle: (fire_timer(bundle) >= 48 or hearts(bundle) >= 2) and can_use(Items.DISTANT_SCARECROW, bundle)), ]) diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py index bdb3273d39fc..039a70944d16 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py @@ -67,7 +67,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: blast_or_smash(bundle) or (is_adult(bundle) and ((has_item(LocalEvents.DMT_BEAN_PLANTED, bundle) and has_item(Items.GORONS_BRACELET, bundle)) or (can_use(Items.HOVER_BOOTS, bundle) and can_do_trick(Tricks.DMT_CLIMB_HOVERS, bundle))))), (Regions.DODONGOS_CAVERN_ENTRYWAY, lambda bundle: has_explosives(bundle) or has_item(Items.GORONS_BRACELET, bundle) or is_adult( - bundle), SOHDungeonEntranceNames.DODONGOS_CAVERN_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.BOTH_AGE, EntranceType.TWO_WAY), + bundle), SOHDungeonEntranceNames.DODONGOS_CAVERN_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY), (Regions.DMT_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)) ]) diff --git a/worlds/oot_soh/location_access/overworld/desert_colossus.py b/worlds/oot_soh/location_access/overworld/desert_colossus.py index 3529554e12d9..5ef317b51b36 100644 --- a/worlds/oot_soh/location_access/overworld/desert_colossus.py +++ b/worlds/oot_soh/location_access/overworld/desert_colossus.py @@ -61,7 +61,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.COLOSSUS_GREAT_FAIRY_FOUNTAIN, lambda bundle: has_explosives(bundle)), (Regions.SPIRIT_TEMPLE_ENTRYWAY, lambda bundle: True, SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE, - SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.BOTH_AGE, EntranceType.TWO_WAY), + SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY), (Regions.WASTELAND_NEAR_COLOSSUS, lambda bundle: True), (Regions.COLOSSUS_GROTTO, lambda bundle: can_use( Items.SILVER_GAUNTLETS, bundle)) diff --git a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py index 9072bdc24467..3ef72087af84 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py @@ -97,7 +97,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.GF_TO_GTG, world, [ (Regions.GERUDO_TRAINING_GROUND_ENTRYWAY, lambda bundle: has_item(LocalEvents.GTG_GATE_OPEN, bundle) and (is_adult(bundle) or world.options.shuffle_dungeon_entrances > - 0), SOHDungeonEntranceNames.GERUDO_TRAINING_GROUND_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY), + 0), SOHDungeonEntranceNames.GERUDO_TRAINING_GROUND_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.TWO_WAY), (Regions.GF_OUTSIDE_GTG, lambda bundle: is_child(bundle) or has_item(Items.GERUDO_MEMBERSHIP_CARD, bundle)), (Regions.GF_JAIL_WINDOW, lambda bundle: can_use(Items.HOOKSHOT, bundle)), diff --git a/worlds/oot_soh/location_access/overworld/graveyard.py b/worlds/oot_soh/location_access/overworld/graveyard.py index ce99bee2abd9..0a7afacee769 100644 --- a/worlds/oot_soh/location_access/overworld/graveyard.py +++ b/worlds/oot_soh/location_access/overworld/graveyard.py @@ -201,5 +201,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.GRAVEYARD_WARP_PAD_REGION, world, [ (Regions.THE_GRAVEYARD, lambda bundle: True), (Regions.SHADOW_TEMPLE_ENTRYWAY, lambda bundle: can_use(Items.DINS_FIRE, bundle) or (can_do_trick(Tricks.GY_SHADOW_FIRE_ARROWS, bundle) and is_adult( - bundle) and can_use(Items.FIRE_ARROW, bundle)), SOHDungeonEntranceNames.SHADOW_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT, EntranceType.TWO_WAY) + bundle) and can_use(Items.FIRE_ARROW, bundle)), SOHDungeonEntranceNames.SHADOW_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY) ]) diff --git a/worlds/oot_soh/location_access/overworld/kakariko.py b/worlds/oot_soh/location_access/overworld/kakariko.py index 051935e2a320..07186fb09a84 100644 --- a/worlds/oot_soh/location_access/overworld/kakariko.py +++ b/worlds/oot_soh/location_access/overworld/kakariko.py @@ -432,5 +432,5 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.KAKARIKO_VILLAGE, lambda bundle: is_adult(bundle) or has_item(Items.BRONZE_SCALE, bundle) or has_item(Events.DRAIN_WELL, bundle)), (Regions.BOTTOM_OF_THE_WELL_ENTRYWAY, lambda bundle: is_child(bundle) or (has_item(Events.DRAIN_WELL, bundle) and world.options.shuffle_dungeon_entrances.value > - 0), SOHDungeonEntranceNames.BOTTOM_OF_THE_WELL_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY) + 0), SOHDungeonEntranceNames.BOTTOM_OF_THE_WELL_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY) ]) diff --git a/worlds/oot_soh/location_access/overworld/kokiri_forest.py b/worlds/oot_soh/location_access/overworld/kokiri_forest.py index c7203ca3b50a..4523c2ef08ff 100644 --- a/worlds/oot_soh/location_access/overworld/kokiri_forest.py +++ b/worlds/oot_soh/location_access/overworld/kokiri_forest.py @@ -212,7 +212,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.KF_OUTSIDE_DEKU_TREE, world, [ (Regions.DEKU_TREE_ENTRYWAY, lambda bundle: is_child(bundle) or (world.options.shuffle_dungeon_entrances.value > 0 and (world.options.closed_forest.value == 2 or has_item( - LocalEvents.MIDO_SWORD_AND_SHIELD, bundle))), SOHDungeonEntranceNames.DEKU_TREE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD, EntranceType.TWO_WAY), + LocalEvents.MIDO_SWORD_AND_SHIELD, bundle))), SOHDungeonEntranceNames.DEKU_TREE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY), (Regions.KOKIRI_FOREST, lambda bundle: (is_adult(bundle) and (can_pass_enemy(bundle, Enemies.BIG_SKULLTULA) or has_item(Events.FOREST_TEMPLE_COMPLETED, bundle))) From 64e68e5c1e79be93447e42e3de7b9efa7aa7ec3d Mon Sep 17 00:00:00 2001 From: mattman107 Date: Sat, 15 Nov 2025 14:12:46 -0500 Subject: [PATCH 13/22] Grotto Shuffle. --- worlds/oot_soh/EntranceShuffle.py | 2 +- worlds/oot_soh/Enums.py | 84 ++++++++++++++++++- worlds/oot_soh/LogicHelpers.py | 5 +- worlds/oot_soh/Options.py | 10 +++ worlds/oot_soh/__init__.py | 10 ++- .../overworld/castle_grounds.py | 4 +- .../overworld/death_mountain_crater.py | 8 +- .../overworld/death_mountain_trail.py | 8 +- .../overworld/desert_colossus.py | 4 +- .../overworld/gerudo_fortress.py | 4 +- .../overworld/gerudo_valley.py | 8 +- .../location_access/overworld/goron_city.py | 4 +- .../location_access/overworld/graveyard.py | 16 ++-- .../location_access/overworld/hyrule_field.py | 32 +++---- .../location_access/overworld/kakariko.py | 8 +- .../overworld/kokiri_forest.py | 4 +- .../location_access/overworld/lake_hylia.py | 4 +- .../overworld/lon_lon_ranch.py | 4 +- .../location_access/overworld/lost_woods.py | 14 ++-- .../overworld/sacred_forest_meadow.py | 12 +-- .../location_access/overworld/zoras_domain.py | 4 +- .../location_access/overworld/zoras_river.py | 12 +-- 22 files changed, 182 insertions(+), 79 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 178ceb153171..50d4d8166765 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -125,7 +125,7 @@ def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBoss if ageRestricted: target_group_lookup = bake_target_group_lookup(world, get_target_groups_age_restrictive) - elif False:#world.options.mixed_entrances_pools: + elif world.options.mixed_entrances_pools: target_group_lookup = bake_target_group_lookup(world, get_target_groups_mixed_entrance_pools) else: target_group_lookup = bake_target_group_lookup(world, get_target_groups) diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index 3cd98a3b36a7..eb0293b9bb3d 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -3941,4 +3941,86 @@ class SOHBossWarpExitNames(StrEnum): FIRE_TEMPLE_BOSS_WARP_EXIT = "Fire Temple Dungeon Boss Warp Exit" WATER_TEMPLE_BOSS_WARP_EXIT = "Water Temple Dungeon Boss Warp Exit" SHADOW_TEMPLE_BOSS_WARP_EXIT = "Shadow Temple Dungeon Boss Warp Exit" - SPIRIT_TEMPLE_BOSS_WARP_EXIT = "Spirit Temple Dungeon Boss Warp Exit" \ No newline at end of file + SPIRIT_TEMPLE_BOSS_WARP_EXIT = "Spirit Temple Dungeon Boss Warp Exit" + + +class SOHGrottoEntranceNames(StrEnum): + COLOSSUS_GROTTO_ENTRANCE = "Colossus Grotto Entrance" + LH_GROTTO_ENTRANCE = "LH Grotto Entrance" + ZR_OPEN_GROTTO_ENTRANCE = "ZR Open Grotto Entrance" + ZR_FAIRY_GROTTO_ENTRANCE = "ZR Fairy Grotto Entrance" + ZR_STORMS_GROTTO_ENTRANCE = "ZR Storms Grotto Entrance" + DMC_HAMMER_GROTTO_ENTRANCE = "DMC Hammer Grotto Entrance" + DMC_UPPER_GROTTO_ENTRANCE = "DMC Upper Grotto Entrance" + GC_GROTTO_ENTRANCE = "GC Grotto Entrance" + DMT_STORMS_GROTTO_ENTRANCE = "DMT Storms Grotto Entrance" + DMT_COW_GROTTO_ENTRANCE = "DMT Cow Grotto Entrance" + KAK_OPEN_GROTTO_ENTRANCE = "Kak Open Grotto Entrance" + KAK_REDEAD_GROTTO_ENTRANCE = "Kak Redead Grotto Entrance" + HC_STORMS_GROTTO_ENTRANCE = "HC Storms Grotto Entrance" + HF_TEKTITE_GROTTO_ENTRANCE = "HF Tektitie Grotto Entrance" + HF_NEAR_KAK_GROTTO_ENTRANCE = "HF Near Kak Grotto Entrance" + HF_FAIRY_GROTTO_ENTRANCE = "HF Fairy Grotto Entrance" + HF_NEAR_MARKET_GROTTO_ENTRANCE = "HF Near Market Grotto Entrance" + HF_COW_GROTTO_ENTRANCE = "HF Cow Grotto Entrance" + HF_INSIDE_FENCE_GROTTO_ENTRANCE = "HF Inside Fence Grotto Entrance" + HF_OPEN_GROTTO_ENTRANCE = "HF Open Grotto Entrance" + HF_SOUTHEAST_GROTTO_ENTRANCE = "HF Southeast Grotto Entrance" + LLR_GROTTO_ENTRANCE = "LLR Grotto Entrance" + SFM_WOLFOS_GROTTO_ENTRANCE = "SFM Wolfos Grotto Entrance" + SFM_STORMS_GROTTO_ENTRANCE = "SFM Storms Grotto Entrance" + SFM_FAIRY_GROTTO_ENTRANCE = "SFM Fairy Grotto Entrance" + LW_SCRUBS_GROTTO_ENTRANCE = "LW Scrubs Grotto Entrance" + LW_NEAR_SHORTCUTS_GROTTO_ENTRANCE = "LW Near Shortcuts Grotto Entrance" + KF_STORMS_GROTTO_ENTRANCE = "KF Storms Grotto Entrance" + ZD_STORMS_GROTTO_ENTRANCE = "ZD Storms Grotto Entrance" + GF_STORMS_GROTTO_ENTRANCE = "GF Storms Grotto Entrance" + GV_STORMS_GROTTO_ENTRANCE = "GV Storms Grotto Entrance" + GV_OCTOROK_GROTTO_ENTRANCE = "GV Oktorok Grotto Entrance" + DEKU_THEATER_ENTRANCE = "Deku Theater Entrance" + #Graves + GRAVEYARD_SHEILD_GRAVE_ENTRANCE = "Graveyard Shield Grave Entrance" + GRAVEYARD_COMPOSERS_GRAVE_ENTRANCE = "Graveyard Composers Grave Entrance" + GRAVEYARD_HEART_PIECE_GRAVE_ENTRANCE = "Graveyard Heart Piece Grave Entrance" + GRAVEYARD_DAMPES_GRAVE_ENTRANCE = "Graveyard Dampes Grave Entrance" + + +class SOHGrottoExitNames(StrEnum): + COLOSSUS_GROTTO_EXIT = "Colossus Grotto Exit" + LH_GROTTO_EXIT = "LH Grotto Exit" + ZR_OPEN_GROTTO_EXIT = "ZR Open Grotto Exit" + ZR_FAIRY_GROTTO_EXIT = "ZR Fairy Grotto Exit" + ZR_STORMS_GROTTO_EXIT = "ZR Storms Grotto Exit" + DMC_HAMMER_GROTTO_EXIT = "DMC Hammer Grotto Exit" + DMC_UPPER_GROTTO_EXIT = "DMC Upper Grotto Exit" + GC_GROTTO_EXIT = "GC Grotto Exit" + DMT_STORMS_GROTTO_EXIT = "DMT Storms Grotto Exit" + DMT_COW_GROTTO_EXIT = "DMT Cow Grotto Exit" + KAK_OPEN_GROTTO_EXIT = "Kak Open Grotto Exit" + KAK_REDEAD_GROTTO_EXIT = "Kak Redead Grotto Exit" + HC_STORMS_GROTTO_EXIT = "HC Storms Grotto Exit" + HF_TEKTITE_GROTTO_EXIT = "HF Tektitie Grotto Exit" + HF_NEAR_KAK_GROTTO_EXIT = "HF Near Kak Grotto Exit" + HF_FAIRY_GROTTO_EXIT = "HF Fairy Grotto Exit" + HF_NEAR_MARKET_GROTTO_EXIT = "HF Near Market Grotto Exit" + HF_COW_GROTTO_EXIT = "HF Cow Grotto Exit" + HF_INSIDE_FENCE_GROTTO_EXIT = "HF Inside Fence Grotto Exit" + HF_OPEN_GROTTO_EXIT = "HF Open Grotto Exit" + HF_SOUTHEAST_GROTTO_EXIT = "HF Southeast Grotto Exit" + LLR_GROTTO_EXIT = "LLR Grotto Exit" + SFM_WOLFOS_GROTTO_EXIT = "SFM Wolfos Grotto Exit" + SFM_STORMS_GROTTO_EXIT = "SFM Storms Grotto Exit" + SFM_FAIRY_GROTTO_EXIT = "SFM Fairy Grotto Exit" + LW_SCRUBS_GROTTO_EXIT = "LW Scrubs Grotto Exit" + LW_NEAR_SHORTCUTS_GROTTO_EXIT = "LW Near Shortcuts Grotto Exit" + KF_STORMS_GROTTO_EXIT = "KF Storms Grotto Exit" + ZD_STORMS_GROTTO_EXIT = "ZD Storms Grotto Exit" + GF_STORMS_GROTTO_EXIT = "GF Storms Grotto Exit" + GV_STORMS_GROTTO_EXIT = "GV Storms Grotto Exit" + GV_OCTOROK_GROTTO_EXIT = "GV Oktorok Grotto Exit" + DEKU_THEATER_EXIT = "Deku Theater Exit" + #Graves + GRAVEYARD_SHEILD_GRAVE_EXIT = "Graveyard Shield Grave Exit" + GRAVEYARD_COMPOSERS_GRAVE_EXIT = "Graveyard Composers Grave Exit" + GRAVEYARD_HEART_PIECE_GRAVE_EXIT = "Graveyard Heart Piece Grave Exit" + GRAVEYARD_DAMPES_GRAVE_EXIT = "Graveyard Dampes Grave Exit" \ No newline at end of file diff --git a/worlds/oot_soh/LogicHelpers.py b/worlds/oot_soh/LogicHelpers.py index 028fdb1d672d..3f88ae75f3bf 100644 --- a/worlds/oot_soh/LogicHelpers.py +++ b/worlds/oot_soh/LogicHelpers.py @@ -47,7 +47,7 @@ def locationRule(bundle): return True def connect_regions(parent_region: Regions, world: "SohWorld", - child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool], SOHBossEntranceNames | SOHDungeonExitNames | SOHBossWarpEntranceNames | SOHBossEntranceExitNames, int, EntranceType]]) -> None: + child_regions: list[tuple[Regions, Callable[[tuple[CollectionState, Regions, "SohWorld"]], bool], SOHBossEntranceNames | SOHDungeonExitNames | SOHBossWarpEntranceNames | SOHGrottoEntranceNames | SOHGrottoExitNames, int, EntranceType]]) -> None: for region in child_regions: regionName = region[0] entranceName = None @@ -63,6 +63,9 @@ def regionRule(bundle): return True entrance.randomization_group = region[3] if len(region) > 4: entrance.randomization_type = region[4] + else: + #Default to EntranceType.Two_Way + entrance.randomization_type = EntranceType.TWO_WAY def add_events(parent_region: Regions, world: "SohWorld", diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index a5dfb5c5f24c..373fbe6ec775 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -910,6 +910,14 @@ class ShuffleDungeonEntrances(Choice): option_on_plus_ganon = 2 default = 0 + +class ShuffleGrottoEntrances(Toggle): + """ + Shuffle the pool of grotto entrances, including all graves, small Fairy fountains and Deku Theatre. + """ + display_name = "Grotto Entrances Shuffle" + + #currently doesn't work class DecoupleEntrances(Toggle): """ @@ -1018,6 +1026,7 @@ class SohOptions(PerGameCommonOptions): enable_all_tricks: EnableAllTricks shuffle_dungeon_entrances: ShuffleDungeonEntrances shuffle_boss_entrances: ShuffleDungeonBossEntrances + shuffle_grotto_entrances: ShuffleGrottoEntrances decouple_entrances: DecoupleEntrances mixed_entrances_pools: MixedEntrancePools @@ -1052,6 +1061,7 @@ class SohOptions(PerGameCommonOptions): OptionGroup("Shuffle Entrances", [ ShuffleDungeonEntrances, ShuffleDungeonBossEntrances, + ShuffleGrottoEntrances, DecoupleEntrances, MixedEntrancePools # Overworld Entrances diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index ed1ee72d8cec..3d5648853e5e 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -192,10 +192,18 @@ def connect_entrances(self): randomize_entrances_soh(self, entrances_to_shuffle, ageRestricted=True) entrances_to_shuffle.clear() else: - # Need this else here. Mixed entrances doesn't work + # Need this else here. Mixed entrances doesn't work for entrances locked behind another yet. Boss entrances are behind dungeon entrances randomize_entrances_soh(self, entrances_to_shuffle) entrances_to_shuffle.clear() + # Grotto Entrances + if self.options.shuffle_grotto_entrances: + for entranceName in SOHGrottoExitNames: + entrances_to_shuffle.add(entranceName) + + for entranceName in SOHGrottoEntranceNames: + entrances_to_shuffle.add(entranceName) + # Dungeon Entrances if self.options.shuffle_dungeon_entrances: for entranceName in SOHDungeonExitNames: diff --git a/worlds/oot_soh/location_access/overworld/castle_grounds.py b/worlds/oot_soh/location_access/overworld/castle_grounds.py index 7aa533442184..dbb552d3049a 100644 --- a/worlds/oot_soh/location_access/overworld/castle_grounds.py +++ b/worlds/oot_soh/location_access/overworld/castle_grounds.py @@ -69,7 +69,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.HYRULE_CASTLE_GROUNDS, world, [ (Regions.CASTLE_GROUNDS, lambda bundle: True), (Regions.HC_GREAT_FAIRY_FOUNTAIN, lambda bundle: blast_or_smash(bundle)), - (Regions.HC_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)) + (Regions.HC_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle), SOHGrottoEntranceNames.HC_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD_ONLY) ]) if not world.options.skip_child_zelda: connect_regions(Regions.HYRULE_CASTLE_GROUNDS, world, [ @@ -109,7 +109,7 @@ def set_region_rules(world: "SohWorld") -> None: # Hyrule Castle Storms Grotto # Connections connect_regions(Regions.HC_STORMS_GROTTO, world, [ - (Regions.CASTLE_GROUNDS, lambda bundle: True), + (Regions.CASTLE_GROUNDS, lambda bundle: True, SOHGrottoExitNames.HC_STORMS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.HC_STORMS_GROTTO_BEHIND_WALLS, lambda bundle: can_break_mud_walls(bundle)), (Regions.HC_STORMS_SKULLTULA, lambda bundle: can_use( diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py index 28ca0de531f6..c4e38616e4f1 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py @@ -25,7 +25,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DMC_UPPER_LOCAL, lambda bundle: fire_timer(bundle) >= 48), (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: True), (Regions.DMC_UPPER_GROTTO, lambda bundle: blast_or_smash( - bundle) and (fire_timer(bundle) >= 8 or hearts(bundle) >= 3)), + bundle) and (fire_timer(bundle) >= 8 or hearts(bundle) >= 3), SOHGrottoEntranceNames.DMC_UPPER_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # Death Mountain Crater Upper Local @@ -87,7 +87,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DMC_GREAT_FAIRY_FOUNTAIN, lambda bundle: can_use(Items.MEGATON_HAMMER, bundle)), (Regions.DMC_HAMMER_GROTTO, lambda bundle: is_adult( - bundle) and can_use(Items.MEGATON_HAMMER, bundle)) + bundle) and can_use(Items.MEGATON_HAMMER, bundle), SOHGrottoEntranceNames.DMC_HAMMER_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY) ]) # Death Mountain Crater Lower Local @@ -213,7 +213,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.DMC_UPPER_GROTTO, world, [ - (Regions.DMC_UPPER_LOCAL, lambda bundle: True) + (Regions.DMC_UPPER_LOCAL, lambda bundle: True, SOHGrottoExitNames.DMC_UPPER_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD) ]) # Death Mountain Crater Hammer Grotto @@ -230,7 +230,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.DMC_HAMMER_GROTTO, world, [ - (Regions.DMC_LOWER_LOCAL, lambda bundle: True) + (Regions.DMC_LOWER_LOCAL, lambda bundle: True, SOHGrottoExitNames.DMC_HAMMER_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # Death Mountain Crater Distant Platform diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py index 039a70944d16..cf54ba6ce69c 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py @@ -68,7 +68,7 @@ def set_region_rules(world: "SohWorld") -> None: and has_item(Items.GORONS_BRACELET, bundle)) or (can_use(Items.HOVER_BOOTS, bundle) and can_do_trick(Tricks.DMT_CLIMB_HOVERS, bundle))))), (Regions.DODONGOS_CAVERN_ENTRYWAY, lambda bundle: has_explosives(bundle) or has_item(Items.GORONS_BRACELET, bundle) or is_adult( bundle), SOHDungeonEntranceNames.DODONGOS_CAVERN_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY), - (Regions.DMT_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)) + (Regions.DMT_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle), SOHGrottoEntranceNames.DMT_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # Death Mountain Summit @@ -98,7 +98,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True), (Regions.DMC_UPPER_LOCAL, lambda bundle: True), (Regions.DMT_OWL_FLIGHT, lambda bundle: is_child(bundle)), - (Regions.DMT_COW_GROTTO, lambda bundle: blast_or_smash(bundle)), + (Regions.DMT_COW_GROTTO, lambda bundle: blast_or_smash(bundle), SOHGrottoEntranceNames.DMT_COW_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.DMT_GREAT_FAIRY_FOUNTAIN, lambda bundle: blast_or_smash(bundle)) ]) @@ -133,7 +133,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.DMT_COW_GROTTO, world, [ - (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: True) + (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: True, SOHGrottoExitNames.DMT_COW_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # Death Mountain Trail Storms Grotto @@ -167,7 +167,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.DMT_STORMS_GROTTO, world, [ - (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True) + (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True, SOHGrottoExitNames.DMT_STORMS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD) ]) # Death Mountain Trail Great Fairy Fountain diff --git a/worlds/oot_soh/location_access/overworld/desert_colossus.py b/worlds/oot_soh/location_access/overworld/desert_colossus.py index 5ef317b51b36..ff9cf1a3a51c 100644 --- a/worlds/oot_soh/location_access/overworld/desert_colossus.py +++ b/worlds/oot_soh/location_access/overworld/desert_colossus.py @@ -64,7 +64,7 @@ def set_region_rules(world: "SohWorld") -> None: SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY), (Regions.WASTELAND_NEAR_COLOSSUS, lambda bundle: True), (Regions.COLOSSUS_GROTTO, lambda bundle: can_use( - Items.SILVER_GAUNTLETS, bundle)) + Items.SILVER_GAUNTLETS, bundle), SOHGrottoEntranceNames.COLOSSUS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY) ]) # Desert Colossus Oasis @@ -123,5 +123,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.COLOSSUS_GROTTO, world, [ - (Regions.DESERT_COLOSSUS, lambda bundle: True) + (Regions.DESERT_COLOSSUS, lambda bundle: True, SOHGrottoExitNames.COLOSSUS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py index 3ef72087af84..d560bd54e7f1 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py @@ -68,7 +68,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GF_TOP_OF_UPPER_VINES, lambda bundle: can_use(Items.LONGSHOT, bundle)), (Regions.GF_STORMS_GROTTO, lambda bundle: is_adult( - bundle) and can_open_storms_grotto(bundle)), + bundle) and can_open_storms_grotto(bundle), SOHGrottoEntranceNames.GF_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), ]) # GF Outside GTG @@ -356,5 +356,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GF_STORMS_GROTTO, world, [ - (Regions.GF_NEAR_GROTTO, lambda bundle: True), + (Regions.GF_NEAR_GROTTO, lambda bundle: True, SOHGrottoExitNames.GF_STORMS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) diff --git a/worlds/oot_soh/location_access/overworld/gerudo_valley.py b/worlds/oot_soh/location_access/overworld/gerudo_valley.py index c0339b28c7aa..caf1501aaca2 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_valley.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_valley.py @@ -102,7 +102,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GV_LOWER_STREAM, lambda bundle: has_item(Items.BRONZE_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle)), (Regions.GV_OCTOROK_GROTTO, lambda bundle: can_use( - Items.SILVER_GAUNTLETS, bundle)), + Items.SILVER_GAUNTLETS, bundle), SOHGrottoEntranceNames.GV_OCTOROK_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GV_CRATE_LEDGE, lambda bundle: can_use(Items.LONGSHOT, bundle)) ]) @@ -152,7 +152,7 @@ def set_region_rules(world: "SohWorld") -> None: Events.RESCUED_ALL_CARPENTERS, bundle)), (Regions.GV_CARPENTER_TENT, lambda bundle: is_adult(bundle)), (Regions.GV_STORMS_GROTTO, lambda bundle: is_adult( - bundle) and can_open_storms_grotto(bundle)), + bundle) and can_open_storms_grotto(bundle), SOHGrottoEntranceNames.GV_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GV_CRATE_LEDGE, lambda bundle: can_do_trick(Tricks.DAMAGE_BOOST_SIMPLE, bundle) and has_explosives(bundle)), ]) @@ -193,7 +193,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GV_OCTOROK_GROTTO, world, [ - (Regions.GV_GROTTO_LEDGE, lambda bundle: True), + (Regions.GV_GROTTO_LEDGE, lambda bundle: True, SOHGrottoExitNames.GV_OCTOROK_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # GV Storms Grotto @@ -208,5 +208,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GV_STORMS_GROTTO, world, [ - (Regions.GV_FORTRESS_SIDE, lambda bundle: True), + (Regions.GV_FORTRESS_SIDE, lambda bundle: True, SOHGrottoExitNames.GV_STORMS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) diff --git a/worlds/oot_soh/location_access/overworld/goron_city.py b/worlds/oot_soh/location_access/overworld/goron_city.py index 2f2f947b17fe..ed3f251968e2 100644 --- a/worlds/oot_soh/location_access/overworld/goron_city.py +++ b/worlds/oot_soh/location_access/overworld/goron_city.py @@ -139,7 +139,7 @@ def set_region_rules(world: "SohWorld") -> None: # Goron City Grotto Platform # Connections connect_regions(Regions.GC_GROTTO_PLATFORM, world, [ - (Regions.GC_GROTTO, lambda bundle: True), + (Regions.GC_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.GC_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GORON_CITY, lambda bundle: effective_health(bundle) > 2 or can_use_any([Items.GORON_TUNIC, Items.NAYRUS_LOVE], bundle) or ( (is_child(bundle) or can_use(Items.SONG_OF_TIME, bundle)) and can_use(Items.LONGSHOT, bundle))) ]) @@ -174,5 +174,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GC_GROTTO, world, [ - (Regions.GC_GROTTO_PLATFORM, lambda bundle: True) + (Regions.GC_GROTTO_PLATFORM, lambda bundle: True, SOHGrottoExitNames.GC_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/graveyard.py b/worlds/oot_soh/location_access/overworld/graveyard.py index 0a7afacee769..f25a05f0f6a5 100644 --- a/worlds/oot_soh/location_access/overworld/graveyard.py +++ b/worlds/oot_soh/location_access/overworld/graveyard.py @@ -70,12 +70,12 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.THE_GRAVEYARD, world, [ (Regions.GRAVEYARD_SHIELD_GRAVE, - lambda bundle: is_adult(bundle) or at_night(bundle)), + lambda bundle: is_adult(bundle) or at_night(bundle), SOHGrottoEntranceNames.GRAVEYARD_SHEILD_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GRAVEYARD_COMPOSERS_GRAVE, - lambda bundle: can_use(Items.ZELDAS_LULLABY, bundle)), + lambda bundle: can_use(Items.ZELDAS_LULLABY, bundle), SOHGrottoEntranceNames.GRAVEYARD_COMPOSERS_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.GRAVEYARD_HEART_PIECE_GRAVE, - lambda bundle: is_adult(bundle) or at_night(bundle)), - (Regions.GRAVEYARD_DAMPES_GRAVE, lambda bundle: is_adult(bundle)), + lambda bundle: is_adult(bundle) or at_night(bundle), SOHGrottoEntranceNames.GRAVEYARD_HEART_PIECE_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), + (Regions.GRAVEYARD_DAMPES_GRAVE, lambda bundle: is_adult(bundle), SOHGrottoEntranceNames.GRAVEYARD_DAMPES_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GRAVEYARD_DAMPES_HOUSE, lambda bundle: is_adult(bundle) and can_open_overworld_door(Items.DAMPES_HUT_KEY, bundle)), (Regions.KAKARIKO_VILLAGE, lambda bundle: True), @@ -89,7 +89,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GRAVEYARD_SHIELD_GRAVE, world, [ - (Regions.THE_GRAVEYARD, lambda bundle: True), + (Regions.THE_GRAVEYARD, lambda bundle: True, SOHGrottoExitNames.GRAVEYARD_SHEILD_GRAVE_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.GRAVEYARD_SHIELD_GRAVE_BACK, lambda bundle: can_break_mud_walls(bundle)) ]) @@ -119,7 +119,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GRAVEYARD_HEART_PIECE_GRAVE, world, [ - (Regions.THE_GRAVEYARD, lambda bundle: True) + (Regions.THE_GRAVEYARD, lambda bundle: True, SOHGrottoExitNames.GRAVEYARD_HEART_PIECE_GRAVE_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # The Graveyard Composers Grave @@ -134,7 +134,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GRAVEYARD_COMPOSERS_GRAVE, world, [ - (Regions.THE_GRAVEYARD, lambda bundle: True) + (Regions.THE_GRAVEYARD, lambda bundle: True, SOHGrottoExitNames.GRAVEYARD_COMPOSERS_GRAVE_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # The Graveyard Dampes Grave @@ -173,7 +173,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GRAVEYARD_DAMPES_GRAVE, world, [ - (Regions.THE_GRAVEYARD, lambda bundle: True), + (Regions.THE_GRAVEYARD, lambda bundle: True, SOHGrottoExitNames.GRAVEYARD_DAMPES_GRAVE_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT), (Regions.KAK_WINDMILL, lambda bundle: (is_adult(bundle) and can_use( Items.SONG_OF_TIME, bundle)) or (is_child(bundle) and can_ground_jump(bundle))) ]) diff --git a/worlds/oot_soh/location_access/overworld/hyrule_field.py b/worlds/oot_soh/location_access/overworld/hyrule_field.py index 155e10ce9b8a..c074a9a41143 100644 --- a/worlds/oot_soh/location_access/overworld/hyrule_field.py +++ b/worlds/oot_soh/location_access/overworld/hyrule_field.py @@ -180,16 +180,16 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.KAKARIKO_VILLAGE, lambda bundle: True), (Regions.ZR_FRONT, lambda bundle: True), (Regions.LON_LON_RANCH, lambda bundle: True), - (Regions.HF_SOUTHEAST_GROTTO, lambda bundle: (blast_or_smash(bundle))), - (Regions.HF_OPEN_GROTTO, lambda bundle: True), + (Regions.HF_SOUTHEAST_GROTTO, lambda bundle: (blast_or_smash(bundle)), SOHGrottoEntranceNames.HF_SOUTHEAST_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), + (Regions.HF_OPEN_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.HF_OPEN_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.HF_INSIDE_FENCE_GROTTO, lambda bundle: ( - can_open_bomb_grotto(bundle))), + can_open_bomb_grotto(bundle)), SOHGrottoEntranceNames.HF_INSIDE_FENCE_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.HF_COW_GROTTO, lambda bundle: ((can_use(Items.MEGATON_HAMMER, - bundle) or is_child(bundle)) and can_open_bomb_grotto(bundle))), - (Regions.HF_NEAR_MARKET_GROTTO, lambda bundle: (blast_or_smash(bundle))), - (Regions.HF_FAIRY_GROTTO, lambda bundle: (blast_or_smash(bundle))), - (Regions.HF_NEAR_KAK_GROTTO, lambda bundle: (can_open_bomb_grotto(bundle))), - (Regions.HF_TEKTITE_GROTTO, lambda bundle: (can_open_bomb_grotto(bundle))), + bundle) or is_child(bundle)) and can_open_bomb_grotto(bundle)), SOHGrottoEntranceNames.HF_COW_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), + (Regions.HF_NEAR_MARKET_GROTTO, lambda bundle: (blast_or_smash(bundle)), SOHGrottoEntranceNames.HF_NEAR_MARKET_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), + (Regions.HF_FAIRY_GROTTO, lambda bundle: (blast_or_smash(bundle)), SOHGrottoEntranceNames.HF_FAIRY_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), + (Regions.HF_NEAR_KAK_GROTTO, lambda bundle: (can_open_bomb_grotto(bundle)), SOHGrottoEntranceNames.HF_NEAR_KAK_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), + (Regions.HF_TEKTITE_GROTTO, lambda bundle: (can_open_bomb_grotto(bundle)), SOHGrottoEntranceNames.HF_TEKTITE_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # HF Southeast Grotto @@ -227,7 +227,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HF_SOUTHEAST_GROTTO, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True) + (Regions.HYRULE_FIELD, lambda bundle: True, SOHGrottoExitNames.HF_SOUTHEAST_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD) ]) # HF Open Grotto @@ -261,7 +261,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HF_OPEN_GROTTO, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True) + (Regions.HYRULE_FIELD, lambda bundle: True, SOHGrottoExitNames.HF_OPEN_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD) ]) # HF Inside Fence Grotto @@ -275,13 +275,13 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HF_INSIDE_FENCE_GROTTO, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True) + (Regions.HYRULE_FIELD, lambda bundle: True, SOHGrottoExitNames.HF_INSIDE_FENCE_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # HF Cow Grotto # Connections connect_regions(Regions.HF_COW_GROTTO, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHGrottoExitNames.HF_COW_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.HF_COW_GROTTO_BEHIND_WEBS, lambda bundle: (has_fire_source(bundle))) ]) @@ -350,7 +350,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HF_NEAR_MARKET_GROTTO, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True) + (Regions.HYRULE_FIELD, lambda bundle: True, SOHGrottoExitNames.HF_NEAR_MARKET_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD) ]) # HF Fairy Grotto @@ -372,7 +372,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HF_FAIRY_GROTTO, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True) + (Regions.HYRULE_FIELD, lambda bundle: True, SOHGrottoExitNames.HF_FAIRY_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # HF Near Kak Grotto @@ -383,7 +383,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HF_NEAR_KAK_GROTTO, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True) + (Regions.HYRULE_FIELD, lambda bundle: True, SOHGrottoExitNames.HF_NEAR_KAK_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # HF Tektite Grotto @@ -394,5 +394,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HF_TEKTITE_GROTTO, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True) + (Regions.HYRULE_FIELD, lambda bundle: True, SOHGrottoExitNames.HF_TEKTITE_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/kakariko.py b/worlds/oot_soh/location_access/overworld/kakariko.py index 07186fb09a84..53b5fdbc6747 100644 --- a/worlds/oot_soh/location_access/overworld/kakariko.py +++ b/worlds/oot_soh/location_access/overworld/kakariko.py @@ -144,7 +144,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.KAK_POTION_SHOP_FRONT, lambda bundle: (at_day(bundle) or is_child(bundle)) and can_open_overworld_door( Items.KAK_POTION_SHOP_KEY, bundle)), - (Regions.KAK_REDEAD_GROTTO, lambda bundle: can_open_bomb_grotto(bundle)), + (Regions.KAK_REDEAD_GROTTO, lambda bundle: can_open_bomb_grotto(bundle), SOHGrottoEntranceNames.KAK_REDEAD_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.KAK_IMPAS_LEDGE, lambda bundle: (is_child(bundle) and at_day(bundle)) or ( is_adult(bundle) and can_do_trick(Tricks.VISIBLE_COLLISION, bundle))), (Regions.KAK_WATCHTOWER, @@ -218,7 +218,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.KAK_BACKYARD, world, [ (Regions.KAKARIKO_VILLAGE, lambda bundle: True), - (Regions.KAK_OPEN_GROTTO, lambda bundle: True), + (Regions.KAK_OPEN_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.KAK_OPEN_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.KAK_GRANNYS_POTION_SHOP, lambda bundle: is_adult(bundle) and can_open_overworld_door(Items.GRANNYS_POTION_SHOP_KEY, bundle)), (Regions.KAK_POTION_SHOP_BACK, @@ -380,7 +380,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_REDEAD_GROTTO, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHGrottoExitNames.KAK_REDEAD_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # Kak Open Grotto @@ -414,7 +414,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_OPEN_GROTTO, world, [ - (Regions.KAK_BACKYARD, lambda bundle: True), + (Regions.KAK_BACKYARD, lambda bundle: True, SOHGrottoExitNames.KAK_OPEN_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD), ]) # Kak Behind Gate diff --git a/worlds/oot_soh/location_access/overworld/kokiri_forest.py b/worlds/oot_soh/location_access/overworld/kokiri_forest.py index 4523c2ef08ff..ad94313cead3 100644 --- a/worlds/oot_soh/location_access/overworld/kokiri_forest.py +++ b/worlds/oot_soh/location_access/overworld/kokiri_forest.py @@ -182,7 +182,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.LOST_WOODS, lambda bundle: True), (Regions.LW_BRIDGE_FROM_FOREST, lambda bundle: world.options.closed_forest.value >= 1 or is_adult(bundle) or has_item(Events.DEKU_TREE_COMPLETED, bundle)), - (Regions.KF_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)) + (Regions.KF_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle), SOHGrottoEntranceNames.KF_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # KF Outside Deku Tree @@ -331,5 +331,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KF_STORMS_GROTTO, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True) + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHGrottoExitNames.KF_STORMS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD) ]) diff --git a/worlds/oot_soh/location_access/overworld/lake_hylia.py b/worlds/oot_soh/location_access/overworld/lake_hylia.py index b28b903d89ec..9429a09a7a52 100644 --- a/worlds/oot_soh/location_access/overworld/lake_hylia.py +++ b/worlds/oot_soh/location_access/overworld/lake_hylia.py @@ -167,7 +167,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.LH_LAB, lambda bundle: can_open_overworld_door( Items.HYLIA_LAB_KEY, bundle)), (Regions.LH_FROM_WATER_TEMPLE, lambda bundle: True), - (Regions.LH_GROTTO, lambda bundle: True), + (Regions.LH_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.LH_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # LH from Shortcut @@ -333,5 +333,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LH_GROTTO, world, [ - (Regions.LAKE_HYLIA, lambda bundle: True) + (Regions.LAKE_HYLIA, lambda bundle: True, SOHGrottoExitNames.LH_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py index 9906fd9522e2..ceda3eb82413 100644 --- a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py +++ b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py @@ -58,7 +58,7 @@ def set_region_rules(world: "SohWorld") -> None: Items.STABLES_KEY, bundle)), (Regions.LLR_TOWER, lambda bundle: can_open_overworld_door( Items.BACK_TOWER_KEY, bundle)), - (Regions.LLR_GROTTO, lambda bundle: is_child(bundle)), + (Regions.LLR_GROTTO, lambda bundle: is_child(bundle), SOHGrottoEntranceNames.LLR_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD_ONLY), ]) # LLR Talons House @@ -116,5 +116,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LLR_GROTTO, world, [ - (Regions.LON_LON_RANCH, lambda bundle: True) + (Regions.LON_LON_RANCH, lambda bundle: True, SOHGrottoExitNames.LLR_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/lost_woods.py b/worlds/oot_soh/location_access/overworld/lost_woods.py index 7b78deeaf9b7..68fc12a9c47d 100644 --- a/worlds/oot_soh/location_access/overworld/lost_woods.py +++ b/worlds/oot_soh/location_access/overworld/lost_woods.py @@ -113,7 +113,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.LW_BEYOND_MIDO, lambda bundle: is_child(bundle) or can_use(Items.SARIAS_SONG, bundle) or can_do_trick(Tricks.LW_MIDO_BACKFLIP, bundle)), - (Regions.LW_NEAR_SHORTCUTS_GROTTO, lambda bundle: blast_or_smash(bundle)), + (Regions.LW_NEAR_SHORTCUTS_GROTTO, lambda bundle: blast_or_smash(bundle), SOHGrottoEntranceNames.LW_NEAR_SHORTCUTS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # LW Beyond Mido @@ -161,8 +161,8 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.LOST_WOODS, lambda bundle: is_child( bundle) or can_use(Items.SARIAS_SONG, bundle)), (Regions.SFM_ENTRYWAY, lambda bundle: True), - (Regions.DEKU_THEATER, lambda bundle: True), - (Regions.LW_SCRUBS_GROTTO, lambda bundle: blast_or_smash(bundle)), + (Regions.DEKU_THEATER, lambda bundle: True, SOHGrottoEntranceNames.DEKU_THEATER_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), + (Regions.LW_SCRUBS_GROTTO, lambda bundle: blast_or_smash(bundle), SOHGrottoEntranceNames.LW_SCRUBS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # LW Near Shortcuts Grotto @@ -201,7 +201,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LW_NEAR_SHORTCUTS_GROTTO, world, [ - (Regions.LOST_WOODS, lambda bundle: True), + (Regions.LOST_WOODS, lambda bundle: True, SOHGrottoExitNames.LW_NEAR_SHORTCUTS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD), ]) # Deku Theater @@ -214,7 +214,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.DEKU_THEATER, world, [ - (Regions.LOST_WOODS, lambda bundle: True), + (Regions.LOST_WOODS, lambda bundle: True, SOHGrottoExitNames.DEKU_THEATER_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD_ONLY), ]) # LW Scrubs Grotto @@ -229,8 +229,8 @@ def set_region_rules(world: "SohWorld") -> None: lambda bundle: can_use(Items.SUNS_SONG, bundle)), ]) # Connections - connect_regions(Regions.LW_BEYOND_MIDO, world, [ - (Regions.LW_BEYOND_MIDO, lambda bundle: True), + connect_regions(Regions.LW_SCRUBS_GROTTO, world, [ + (Regions.LW_BEYOND_MIDO, lambda bundle: True, SOHGrottoExitNames.LW_SCRUBS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # LW Bridge From Forest diff --git a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py index fe2becddd0f4..271eb306e573 100644 --- a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py +++ b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py @@ -16,7 +16,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.LW_BEYOND_MIDO, lambda bundle: True), (Regions.SACRED_FOREST_MEADOW, lambda bundle: is_adult( bundle) or can_kill_enemy(bundle, Enemies.WOLFOS)), - (Regions.SFM_WOLFOS_GROTTO, lambda bundle: can_open_bomb_grotto(bundle)), + (Regions.SFM_WOLFOS_GROTTO, lambda bundle: can_open_bomb_grotto(bundle), SOHGrottoEntranceNames.SFM_WOLFOS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # Sacred Forest Meadow @@ -50,8 +50,8 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.SFM_ENTRYWAY, lambda bundle: True), (Regions.FOREST_TEMPLE_ENTRYWAY, lambda bundle: can_use(Items.HOOKSHOT, bundle), SOHDungeonEntranceNames.FOREST_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ADULT_ONLY, EntranceType.TWO_WAY), - (Regions.SFM_FAIRY_GROTTO, lambda bundle: True), - (Regions.SFM_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)), + (Regions.SFM_FAIRY_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.SFM_FAIRY_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), + (Regions.SFM_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle), SOHGrottoEntranceNames.SFM_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # SFM Fairy Grotto @@ -73,7 +73,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.SFM_FAIRY_GROTTO, world, [ - (Regions.SACRED_FOREST_MEADOW, lambda bundle: True), + (Regions.SACRED_FOREST_MEADOW, lambda bundle: True, SOHGrottoExitNames.SFM_FAIRY_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # SFM Wolfos Grotto @@ -84,7 +84,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.SFM_WOLFOS_GROTTO, world, [ - (Regions.SACRED_FOREST_MEADOW, lambda bundle: True), + (Regions.SACRED_FOREST_MEADOW, lambda bundle: True, SOHGrottoExitNames.SFM_WOLFOS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # SFM Storms Grotto @@ -99,5 +99,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.SFM_STORMS_GROTTO, world, [ - (Regions.SACRED_FOREST_MEADOW, lambda bundle: True), + (Regions.SACRED_FOREST_MEADOW, lambda bundle: True, SOHGrottoExitNames.SFM_STORMS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) diff --git a/worlds/oot_soh/location_access/overworld/zoras_domain.py b/worlds/oot_soh/location_access/overworld/zoras_domain.py index 71b8f6675080..55fd6bbf8eaf 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_domain.py +++ b/worlds/oot_soh/location_access/overworld/zoras_domain.py @@ -98,7 +98,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.ZORAS_DOMAIN_ISLAND, world, [ (Regions.ZORAS_DOMAIN, lambda bundle: is_adult( bundle) or has_item(Items.BRONZE_SCALE, bundle)), - (Regions.ZD_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)), + (Regions.ZD_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle), SOHGrottoEntranceNames.ZD_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) # ZD Behind King Zora @@ -156,5 +156,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZD_STORMS_GROTTO, world, [ - (Regions.ZORAS_DOMAIN_ISLAND, lambda bundle: True), + (Regions.ZORAS_DOMAIN_ISLAND, lambda bundle: True, SOHGrottoExitNames.ZD_STORMS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) diff --git a/worlds/oot_soh/location_access/overworld/zoras_river.py b/worlds/oot_soh/location_access/overworld/zoras_river.py index 59b7e5ae605b..f1d9a08e765f 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_river.py +++ b/worlds/oot_soh/location_access/overworld/zoras_river.py @@ -154,12 +154,12 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.ZORA_RIVER, world, [ (Regions.ZR_FRONT, lambda bundle: True), - (Regions.ZR_OPEN_GROTTO, lambda bundle: True), + (Regions.ZR_OPEN_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.ZR_OPEN_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), # I am not sure that there's any scenario where blast or smash wouldn't apply to here, not sure why this needs here (which checks if the other age opened it, basically)? - (Regions.ZR_FAIRY_GROTTO, lambda bundle: blast_or_smash(bundle)), + (Regions.ZR_FAIRY_GROTTO, lambda bundle: blast_or_smash(bundle), SOHGrottoEntranceNames.ZR_FAIRY_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.LOST_WOODS, lambda bundle: has_item( Items.SILVER_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle)), - (Regions.ZR_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle)), + (Regions.ZR_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle), SOHGrottoEntranceNames.ZR_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.ZR_BEHIND_WATERFALL, lambda bundle: world.options.sleeping_waterfall.value == 1 or can_use(Items.ZELDAS_LULLABY, bundle) or (is_child(bundle) and @@ -220,7 +220,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZR_OPEN_GROTTO, world, [ - (Regions.ZORA_RIVER, lambda bundle: True) + (Regions.ZORA_RIVER, lambda bundle: True, SOHGrottoExitNames.ZR_OPEN_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD) ]) # ZR Fairy Grotto @@ -237,7 +237,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZR_FAIRY_GROTTO, world, [ - (Regions.ZORA_RIVER, lambda bundle: True) + (Regions.ZORA_RIVER, lambda bundle: True, SOHGrottoExitNames.ZR_FAIRY_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) # ZR Storms Grotto @@ -253,5 +253,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZR_STORMS_GROTTO, world, [ - (Regions.ZORA_RIVER, lambda bundle: True) + (Regions.ZORA_RIVER, lambda bundle: True, SOHGrottoExitNames.ZR_STORMS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) From a8151e975043626e011fdd13952f1d5212f2dd3e Mon Sep 17 00:00:00 2001 From: mattman107 Date: Sat, 15 Nov 2025 21:04:20 -0500 Subject: [PATCH 14/22] Add Warp Song and Owl Drop Shuffle --- worlds/oot_soh/EntranceShuffle.py | 56 +++++++++++++++++-- worlds/oot_soh/Options.py | 23 ++++++-- worlds/oot_soh/__init__.py | 10 +++- .../overworld/death_mountain_trail.py | 2 +- .../location_access/overworld/lake_hylia.py | 2 +- worlds/oot_soh/location_access/root.py | 12 ++-- 6 files changed, 86 insertions(+), 19 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 50d4d8166765..19741c8bae39 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -1,6 +1,6 @@ from typing import TYPE_CHECKING, Callable from BaseClasses import Location, Region, Entrance -from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups, Regions, SOHBossWarpEntranceNames +from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups, Regions, SOHBossWarpEntranceNames, SOHGrottoEntranceNames, SOHGrottoExitNames from .Locations import SohLocation from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances, bake_target_group_lookup, EntranceRandomizationError from entrance_rando import ERPlacementState, Entrance @@ -41,9 +41,9 @@ mixed_group_lookup = {group: [all for all in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, - SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO, SOHEntranceGroups.OWL_DROP, SOHEntranceGroups.WARP_SONG)] + SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO)] for group in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, - SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO, SOHEntranceGroups.OWL_DROP, SOHEntranceGroups.WARP_SONG)} + SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO)} # This is allowing us to brute force the problem of GER failing. May be a necessary evil as it doesn't do swap or automatic retries itself. @@ -116,9 +116,57 @@ def get_target_groups_age_restrictive(group: int) -> list[int]: return [pair_type | age for pair_type in default_group_lookup[type]] +# Special Randomization for one ways like Owl Drop and Warp Songs +def randomize_soh_one_way_entrances(world: "SohWorld") -> None: + if world.options.shuffle_owl_drop_entrances or world.options.shuffle_warp_song_entrances: + one_way_entrance_names = list() + one_way_exit_region_names = list() + + if world.options.shuffle_owl_drop_entrances: + one_way_entrance_names += [Regions.LH_OWL_FLIGHT, Regions.DMT_OWL_FLIGHT] + + if world.options.shuffle_warp_song_entrances: + # SOH Seems to put these at random places, except for glitchless. They enforce Graveyard, Crater, and Colossus Warp pads be assigned when glitchless. + one_way_entrance_names +=[Regions.MINUET_OF_FOREST_WARP, Regions.BOLERO_OF_FIRE_WARP, Regions.SERENADE_OF_WATER_WARP, Regions.NOCTURNE_OF_SHADOW_WARP, Regions.REQUIEM_OF_SPIRIT_WARP, Regions.PRELUDE_OF_LIGHT_WARP] + one_way_exit_region_names += [Regions.DMC_CENTRAL_LOCAL, Regions.DESERT_COLOSSUS, Regions.GRAVEYARD_WARP_PAD_REGION] + + # Remove the existing exit + for name in one_way_entrance_names: + entrance = world.get_entrance(str(name)) + entrance.connected_region.entrances.remove(entrance) + entrance.connected_region = None + + # Get enough entrances to connect up + # TODO This will need to be updated as we make more named entrances + all_named_entrances = list(SOHDungeonEntranceNames) + list(SOHDungeonExitNames) + list(SOHGrottoExitNames) + list(SOHGrottoEntranceNames) + world.random.shuffle(all_named_entrances) + for entrance_name in all_named_entrances: + if len(one_way_entrance_names) == len(one_way_exit_region_names): + break + + if entrance_name not in one_way_exit_region_names: + one_way_exit_region_names.append(entrance_name) + + # Randomize the the entrance name list and iterate through + world.random.shuffle(one_way_exit_region_names) + + index: int = 0 + for entrance_name in one_way_entrance_names: + entrance = world.get_entrance(str(entrance_name)) + + if one_way_exit_region_names[index] in all_named_entrances: + connected_region_name = world.get_entrance(str(one_way_exit_region_names[index])).parent_region.name + else: + connected_region_name = str(one_way_exit_region_names[index]) + + entrance.connected_region = world.get_region(connected_region_name) + entrance.connected_region.entrances.append(entrance) + + index += 1 + + # Might need to return the ER Placement state at the end def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None, coupled: bool = True, ageRestricted: bool = False) -> None: - temp_entrances: list[Entrance] = list() for entranceEnum in entrances_to_shuffle: disconnect_entrance_for_randomization(world.multiworld.get_entrance( entranceEnum.value, world.player), one_way_target_name=entrance_matching[entranceEnum].value if entranceEnum in entrance_matching else None) diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index 373fbe6ec775..c0a5a7b4fa2d 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -918,6 +918,20 @@ class ShuffleGrottoEntrances(Toggle): display_name = "Grotto Entrances Shuffle" +class ShuffleOwlDropEntrances(Toggle): + """ + Randomized where Kaepora Gaebora (the Owl) drops you at when you talk to him at Lake Hylia or at the top of Death Mountain Trail. + """ + display_name = " Shuffle Owl Drop Entrances" + + +class ShuffleWarpSongEntrances(Toggle): + """ + Randomized where each of the 6 warp songs leads to. + """ + display_name = "Shuffle Warp Song Entrances" + + #currently doesn't work class DecoupleEntrances(Toggle): """ @@ -927,7 +941,7 @@ class DecoupleEntrances(Toggle): display_name = "Decouple Entrances" visibility = Visibility.none -#currently doesn't work +#currently doesn't work with entrances that are behind other randomized entrances class MixedEntrancePools(Toggle): """ Shuffle entrances into a mixed pool instead of separate ones. Has no effect on pools whose entrances aren't shuffled, and "Shuffle Boss Entrances" must be set to "Full" to include them. @@ -1027,6 +1041,8 @@ class SohOptions(PerGameCommonOptions): shuffle_dungeon_entrances: ShuffleDungeonEntrances shuffle_boss_entrances: ShuffleDungeonBossEntrances shuffle_grotto_entrances: ShuffleGrottoEntrances + shuffle_warp_song_entrances: ShuffleWarpSongEntrances + shuffle_owl_drop_entrances: ShuffleOwlDropEntrances decouple_entrances: DecoupleEntrances mixed_entrances_pools: MixedEntrancePools @@ -1062,13 +1078,12 @@ class SohOptions(PerGameCommonOptions): ShuffleDungeonEntrances, ShuffleDungeonBossEntrances, ShuffleGrottoEntrances, + ShuffleWarpSongEntrances, + ShuffleOwlDropEntrances, DecoupleEntrances, MixedEntrancePools # Overworld Entrances # Interior Entrances - # Grotto Entrances - # Owl Drops - # Warp Songs # Overworld Spawns ]), OptionGroup("Shuffle Items", [ diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index 3d5648853e5e..4fcc625745e3 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -19,7 +19,7 @@ from settings import Group, Bool from Options import OptionError from .LogicHelpers import wallet_capacities -from .EntranceShuffle import randomize_entrances_soh, on_connect_soh_sheik_at_colossus, boss_indirect_condition_matching +from .EntranceShuffle import randomize_entrances_soh, on_connect_soh_sheik_at_colossus, randomize_soh_one_way_entrances from entrance_rando import bake_target_group_lookup import logging @@ -178,6 +178,9 @@ def set_rules(self) -> None: set_price_rules(self) def connect_entrances(self): + # Do quircky one ways separate from the rest + randomize_soh_one_way_entrances(self) + entrances_to_shuffle = set() # Reverse decoupled option for randomize_entrances because it is asking if you wanted coupled # Update this when it is figured out why decoupled doesn't work with the current groupings @@ -214,8 +217,9 @@ def connect_entrances(self): if entranceName != SOHDungeonEntranceNames.GANONS_CASTLE_DUNGEON_ENTRANCE or self.options.shuffle_dungeon_entrances == 2: entrances_to_shuffle.add(entranceName) - randomize_entrances_soh( - self, entrances_to_shuffle, on_connect_soh_sheik_at_colossus, coupled) + if len(entrances_to_shuffle) > 0: + randomize_entrances_soh( + self, entrances_to_shuffle, on_connect_soh_sheik_at_colossus, coupled) return super().connect_entrances() diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py index cf54ba6ce69c..e66a2138edba 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py @@ -105,7 +105,7 @@ def set_region_rules(world: "SohWorld") -> None: # Death Mountain Trail Owl Flight # Connections connect_regions(Regions.DMT_OWL_FLIGHT, world, [ - (Regions.KAK_IMPAS_ROOFTOP, lambda bundle: True) + (Regions.KAK_IMPAS_ROOFTOP, lambda bundle: True, Regions.DMT_OWL_FLIGHT) ]) # Death Mountain Trail Cow Grotto diff --git a/worlds/oot_soh/location_access/overworld/lake_hylia.py b/worlds/oot_soh/location_access/overworld/lake_hylia.py index 9429a09a7a52..ec704b4aa25a 100644 --- a/worlds/oot_soh/location_access/overworld/lake_hylia.py +++ b/worlds/oot_soh/location_access/overworld/lake_hylia.py @@ -208,7 +208,7 @@ def set_region_rules(world: "SohWorld") -> None: # LH Owl Flight # Connections connect_regions(Regions.LH_OWL_FLIGHT, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True), + (Regions.HYRULE_FIELD, lambda bundle: True, Regions.LH_OWL_FLIGHT), ]) # LH Lab diff --git a/worlds/oot_soh/location_access/root.py b/worlds/oot_soh/location_access/root.py index 67ef8069b80a..afd7d42dff34 100644 --- a/worlds/oot_soh/location_access/root.py +++ b/worlds/oot_soh/location_access/root.py @@ -78,40 +78,40 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.MINUET_OF_FOREST_WARP, world, [ (Regions.SACRED_FOREST_MEADOW, lambda bundle: can_use( - Items.MINUET_OF_FOREST, bundle)) + Items.MINUET_OF_FOREST, bundle), Regions.MINUET_OF_FOREST_WARP) ]) # Bolero of Fire Warp # Connections connect_regions(Regions.BOLERO_OF_FIRE_WARP, world, [ (Regions.DMC_CENTRAL_LOCAL, lambda bundle: can_use( - Items.BOLERO_OF_FIRE, bundle)) + Items.BOLERO_OF_FIRE, bundle), Regions.BOLERO_OF_FIRE_WARP) ]) # Serenade of Water Warp # Connections connect_regions(Regions.SERENADE_OF_WATER_WARP, world, [ (Regions.LAKE_HYLIA, lambda bundle: can_use( - Items.SERENADE_OF_WATER, bundle)) + Items.SERENADE_OF_WATER, bundle), Regions.SERENADE_OF_WATER_WARP) ]) # Requiem of Spirit Warp # Connections connect_regions(Regions.REQUIEM_OF_SPIRIT_WARP, world, [ (Regions.DESERT_COLOSSUS, lambda bundle: can_use( - Items.REQUIEM_OF_SPIRIT, bundle)) + Items.REQUIEM_OF_SPIRIT, bundle), Regions.REQUIEM_OF_SPIRIT_WARP) ]) # Nocturne of Shadow Warp # Connections connect_regions(Regions.NOCTURNE_OF_SHADOW_WARP, world, [ (Regions.GRAVEYARD_WARP_PAD_REGION, lambda bundle: can_use( - Items.NOCTURNE_OF_SHADOW, bundle)) + Items.NOCTURNE_OF_SHADOW, bundle), Regions.NOCTURNE_OF_SHADOW_WARP) ]) # Prelude of Light Warp # Connections connect_regions(Regions.PRELUDE_OF_LIGHT_WARP, world, [ (Regions.TEMPLE_OF_TIME, lambda bundle: can_use( - Items.PRELUDE_OF_LIGHT, bundle)) + Items.PRELUDE_OF_LIGHT, bundle), Regions.PRELUDE_OF_LIGHT_WARP) ]) From dca44591652b9599e12fe63e0ef370e44d3c5899 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Sun, 16 Nov 2025 12:52:54 -0500 Subject: [PATCH 15/22] Overworld Spawn Shuffle --- worlds/oot_soh/EntranceShuffle.py | 80 +++++++++++++++----------- worlds/oot_soh/Options.py | 13 ++++- worlds/oot_soh/location_access/root.py | 4 +- 3 files changed, 61 insertions(+), 36 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 19741c8bae39..e7d10df69847 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -6,6 +6,7 @@ from entrance_rando import ERPlacementState, Entrance from .LogicHelpers import rule_wrapper from worlds.generic.Rules import set_rule +from enum import StrEnum if TYPE_CHECKING: from . import SohWorld @@ -22,16 +23,6 @@ SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SPIRIT_TEMPLE_BOSS_EXIT, } -boss_indirect_condition_matching = { - SOHBossEntranceNames.DEKU_TREE_BOSS_ENTRANCE: (Regions.DEKU_TREE_BOSS_ROOM, SOHBossWarpEntranceNames.DEKU_TREE_BOSS_WARP_ENTRANCE), - SOHBossEntranceNames.DODONGOS_CAVERN_BOSS_ENTRANCE: (Regions.DODONGOS_CAVERN_BOSS_ROOM, SOHBossWarpEntranceNames.DODONGOS_CAVERN_BOSS_WARP_ENTRANCE), - SOHBossEntranceNames.JABU_JABUS_BOSS_ENTRANCE: (Regions.JABU_JABUS_BELLY_BOSS_ROOM, SOHBossWarpEntranceNames.JABU_JABUS_BOSS_WARP_ENTRANCE), - SOHBossEntranceNames.FOREST_TEMPLE_BOSS_ENTRANCE: (Regions.FOREST_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.FOREST_TEMPLE_BOSS_WARP_ENTRANCE), - SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE: (Regions.FIRE_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.FIRE_TEMPLE_BOSS_WARP_ENTRANCE), - SOHBossEntranceNames.WATER_TEMPLE_BOSS_ENTRANCE: (Regions.WATER_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.WATER_TEMPLE_BOSS_WARP_ENTRANCE), - SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE: (Regions.SHADOW_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.SHADOW_TEMPLE_BOSS_WARP_ENTRANCE), - SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: (Regions.SPIRIT_TEMPLE_BOSS_ROOM, SOHBossWarpEntranceNames.SPIRIT_TEMPLE_BOSS_WARP_ENTRANCE), -} default_group_lookup = { SOHEntranceGroups.DUNGEON_ENTRANCE: [SOHEntranceGroups.DUNGEON_ENTRANCE], @@ -118,9 +109,11 @@ def get_target_groups_age_restrictive(group: int) -> list[int]: # Special Randomization for one ways like Owl Drop and Warp Songs def randomize_soh_one_way_entrances(world: "SohWorld") -> None: - if world.options.shuffle_owl_drop_entrances or world.options.shuffle_warp_song_entrances: + if world.options.shuffle_owl_drop_entrances or world.options.shuffle_warp_song_entrances or world.options.shuffle_overworld_spawns: one_way_entrance_names = list() - one_way_exit_region_names = list() + one_way_entrance_exit_names = list() + # TODO This will need to be updated as we make more named entrances + all_named_entrances = list(SOHDungeonEntranceNames) + list(SOHDungeonExitNames) + list(SOHGrottoExitNames) + list(SOHGrottoEntranceNames) if world.options.shuffle_owl_drop_entrances: one_way_entrance_names += [Regions.LH_OWL_FLIGHT, Regions.DMT_OWL_FLIGHT] @@ -128,7 +121,7 @@ def randomize_soh_one_way_entrances(world: "SohWorld") -> None: if world.options.shuffle_warp_song_entrances: # SOH Seems to put these at random places, except for glitchless. They enforce Graveyard, Crater, and Colossus Warp pads be assigned when glitchless. one_way_entrance_names +=[Regions.MINUET_OF_FOREST_WARP, Regions.BOLERO_OF_FIRE_WARP, Regions.SERENADE_OF_WATER_WARP, Regions.NOCTURNE_OF_SHADOW_WARP, Regions.REQUIEM_OF_SPIRIT_WARP, Regions.PRELUDE_OF_LIGHT_WARP] - one_way_exit_region_names += [Regions.DMC_CENTRAL_LOCAL, Regions.DESERT_COLOSSUS, Regions.GRAVEYARD_WARP_PAD_REGION] + one_way_entrance_exit_names += [Regions.DMC_CENTRAL_LOCAL, Regions.DESERT_COLOSSUS, Regions.GRAVEYARD_WARP_PAD_REGION] # Remove the existing exit for name in one_way_entrance_names: @@ -137,32 +130,55 @@ def randomize_soh_one_way_entrances(world: "SohWorld") -> None: entrance.connected_region = None # Get enough entrances to connect up - # TODO This will need to be updated as we make more named entrances - all_named_entrances = list(SOHDungeonEntranceNames) + list(SOHDungeonExitNames) + list(SOHGrottoExitNames) + list(SOHGrottoEntranceNames) world.random.shuffle(all_named_entrances) for entrance_name in all_named_entrances: - if len(one_way_entrance_names) == len(one_way_exit_region_names): + if len(one_way_entrance_names) == len(one_way_entrance_exit_names): break - if entrance_name not in one_way_exit_region_names: - one_way_exit_region_names.append(entrance_name) + if entrance_name not in one_way_entrance_exit_names: + one_way_entrance_exit_names.append(entrance_name) + + if len(one_way_entrance_names) > 0: + # Randomize the the entrance name list + world.random.shuffle(one_way_entrance_exit_names) + # For Owl Drop/ Song Warps + soh_one_way_entrance_connections(world, one_way_entrance_names, one_way_entrance_exit_names, all_named_entrances) + + # Handle Overworld Spawns separately + if world.options.shuffle_overworld_spawns: + one_way_entrance_names = [Regions.CHILD_SPAWN, Regions.ADULT_SPAWN] + + # Remove special cases for child/adult spawns + # Problematic if they shuffle swim + if world.options.shuffle_swim: + all_named_entrances.remove(SOHDungeonEntranceNames.WATER_TEMPLE_DUNGEON_ENTRANCE) + all_named_entrances.remove(SOHDungeonExitNames.WATER_TEMPLE_DUNGEON_EXIT) + all_named_entrances.remove(SOHGrottoEntranceNames.ZD_STORMS_GROTTO_ENTRANCE) + all_named_entrances.remove(SOHGrottoExitNames.ZD_STORMS_GROTTO_EXIT) + + # Problematic because they have to brave lava to get out + all_named_entrances.remove(SOHGrottoEntranceNames.GC_GROTTO_ENTRANCE) + all_named_entrances.remove(SOHGrottoExitNames.GC_GROTTO_EXIT) + + world.random.shuffle(all_named_entrances) + + soh_one_way_entrance_connections(world, one_way_entrance_names, all_named_entrances, all_named_entrances) + + +def soh_one_way_entrance_connections(world: "SohWorld", entrance_names: list, exit_names: list, potential_entrance_names: list): + index: int = 0 + for entrance_name in entrance_names: + entrance = world.get_entrance(str(entrance_name)) - # Randomize the the entrance name list and iterate through - world.random.shuffle(one_way_exit_region_names) + if exit_names[index] in potential_entrance_names: + connected_region_name = world.get_entrance(str(exit_names[index])).parent_region.name + else: + connected_region_name = str(exit_names[index]) - index: int = 0 - for entrance_name in one_way_entrance_names: - entrance = world.get_entrance(str(entrance_name)) + entrance.connected_region = world.get_region(connected_region_name) + entrance.connected_region.entrances.append(entrance) - if one_way_exit_region_names[index] in all_named_entrances: - connected_region_name = world.get_entrance(str(one_way_exit_region_names[index])).parent_region.name - else: - connected_region_name = str(one_way_exit_region_names[index]) - - entrance.connected_region = world.get_region(connected_region_name) - entrance.connected_region.entrances.append(entrance) - - index += 1 + index += 1 # Might need to return the ER Placement state at the end diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index c0a5a7b4fa2d..18befff3eb10 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -922,16 +922,24 @@ class ShuffleOwlDropEntrances(Toggle): """ Randomized where Kaepora Gaebora (the Owl) drops you at when you talk to him at Lake Hylia or at the top of Death Mountain Trail. """ - display_name = " Shuffle Owl Drop Entrances" + display_name = " Shuffle Owl Drop Entrances" class ShuffleWarpSongEntrances(Toggle): """ Randomized where each of the 6 warp songs leads to. """ - display_name = "Shuffle Warp Song Entrances" + display_name = "Shuffle Warp Song Entrances" +class ShuffleOverworldSpawns(Toggle): + """ + Randomized where you start as Child or Adult when loading a save in the Overworld. This means you may not necessarily spawn inside Link's House or Temple of Time. + This stays consistent after saving and loading the game. + Keep in mind you man need to temporarily disable the "Remember Save Location" time saver to be able to use the spawn positions, especially if they are the only logical way to get to certain areas. + """ + display_name = "Shuffle Overworld Spawns" + #currently doesn't work class DecoupleEntrances(Toggle): """ @@ -1043,6 +1051,7 @@ class SohOptions(PerGameCommonOptions): shuffle_grotto_entrances: ShuffleGrottoEntrances shuffle_warp_song_entrances: ShuffleWarpSongEntrances shuffle_owl_drop_entrances: ShuffleOwlDropEntrances + shuffle_overworld_spawns: ShuffleOverworldSpawns decouple_entrances: DecoupleEntrances mixed_entrances_pools: MixedEntrancePools diff --git a/worlds/oot_soh/location_access/root.py b/worlds/oot_soh/location_access/root.py index afd7d42dff34..005f10e85af8 100644 --- a/worlds/oot_soh/location_access/root.py +++ b/worlds/oot_soh/location_access/root.py @@ -65,13 +65,13 @@ def set_region_rules(world: "SohWorld") -> None: # Child Spawn # Connections connect_regions(Regions.CHILD_SPAWN, world, [ - (Regions.KF_LINKS_HOUSE, lambda bundle: True) + (Regions.KF_LINKS_HOUSE, lambda bundle: True, Regions.CHILD_SPAWN) ]) # Adult Spawn # Connections connect_regions(Regions.ADULT_SPAWN, world, [ - (Regions.TEMPLE_OF_TIME, lambda bundle: True) + (Regions.TEMPLE_OF_TIME, lambda bundle: True, Regions.ADULT_SPAWN) ]) # Minuet of Forest Warp From 235bdd1005fae6704186a9260e4e9426705200c5 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Wed, 19 Nov 2025 09:10:00 -0500 Subject: [PATCH 16/22] Interior Entrances --- worlds/oot_soh/EntranceShuffle.py | 9 +++ worlds/oot_soh/Enums.py | 96 ++++++++++++++++++++++++++++++- worlds/oot_soh/Options.py | 21 ++++++- 3 files changed, 123 insertions(+), 3 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index e7d10df69847..306e1a4ec644 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -148,6 +148,12 @@ def randomize_soh_one_way_entrances(world: "SohWorld") -> None: if world.options.shuffle_overworld_spawns: one_way_entrance_names = [Regions.CHILD_SPAWN, Regions.ADULT_SPAWN] + # Remove the existing exit + for name in one_way_entrance_names: + entrance = world.get_entrance(str(name)) + entrance.connected_region.entrances.remove(entrance) + entrance.connected_region = None + # Remove special cases for child/adult spawns # Problematic if they shuffle swim if world.options.shuffle_swim: @@ -159,6 +165,9 @@ def randomize_soh_one_way_entrances(world: "SohWorld") -> None: # Problematic because they have to brave lava to get out all_named_entrances.remove(SOHGrottoEntranceNames.GC_GROTTO_ENTRANCE) all_named_entrances.remove(SOHGrottoExitNames.GC_GROTTO_EXIT) + # Can't cross bridge with nothing or as child + all_named_entrances.remove(SOHDungeonEntranceNames.FIRE_TEMPLE_DUNGEON_ENTRANCE) + all_named_entrances.remove(SOHDungeonExitNames.FIRE_TEMPLE_DUNGEON_EXIT) world.random.shuffle(all_named_entrances) diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index eb0293b9bb3d..9b28a6b87a96 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -4023,4 +4023,98 @@ class SOHGrottoExitNames(StrEnum): GRAVEYARD_SHEILD_GRAVE_EXIT = "Graveyard Shield Grave Exit" GRAVEYARD_COMPOSERS_GRAVE_EXIT = "Graveyard Composers Grave Exit" GRAVEYARD_HEART_PIECE_GRAVE_EXIT = "Graveyard Heart Piece Grave Exit" - GRAVEYARD_DAMPES_GRAVE_EXIT = "Graveyard Dampes Grave Exit" \ No newline at end of file + GRAVEYARD_DAMPES_GRAVE_EXIT = "Graveyard Dampes Grave Exit" + + +class SOHInteriorEntranceNames(StrEnum): + KF_MIDOS_HOUSE_ENTRANCE = "KF Midos House Entrance" + KF_SARIAS_HOUSE_ENTRANCE = "KF Sarias House Entrance" + KF_TWINS_HOUSE_ENTRANCE = "KF Twins House Entrance" + KF_KNOW_IT_ALL_HOUSE_ENTRANCE = "KF Know It All House Entrance" + KF_KOKIRI_SHOP_ENTRANCE = "KF Kokiri Shop Entrance" + LH_LAB_ENTRANCE = "LH Lab Entrance" + LH_FISHING_POND_ENTRANCE = "LF Fishing Pond Entrance" + GV_CARPENTER_TENT_ENTRANCE = "GV Carpenter Tent Entrance" + MARKET_GUARD_HOUSE_ENTRANCE = "Market Guard House Entrance" + MARKET_MASK_SHOP_ENTRANCE = "Market Mask Shop Entrance" + MARKET_BOMBCHU_BOWLING_ENTRANCE = "Market Bombchu Bowling Entrance" + MARKET_POTION_SHOP_ENTRANCE = "Market Potion Shop Entrance" + MARKET_TREASURE_CHEST_GAME_ENTRANCE = "Market Treasure Chest Game Entrance" + MARKET_BOMBCHU_SHOP_ENTRANCE = "Market Bombchu Shop Entrance" + MARKET_MAN_IN_GREEN_HOUSE_ENTRANCE = "Market Man In Green House Entrance" + KAK_CARPENTER_BOSS_HOUSE_ENTRANCE = "Kak Carpenter Boss House Entrance" + KAK_HOUSE_OF_SKULLTULA_ENTRANCE = "Kak House Of Skulltula Entrance" + KAK_IMPAS_HOUSE_ENTRANCE = "Kak Impas House Entrance" + KAK_IMPAS_HOUSE_BACK_ENTRANCE = "Kak Impas House Back Entrance" + KAK_ODD_POTION_BUILDING_ENTRANCE = "Kak Odd Potion Building Entrance" + GRAVEYARD_DAMPES_HOUSE_ENTRANCE = "Graveyard Dampes House Entrance" + GC_SHOP_ENTRANCE = "GC Shop Entrance" + ZD_SHOP_ENTRANCE = "ZD Shop Entrance" + LLR_TALONS_HOUSE_ENTRANCE = "LLR Talons House Entrance" + LLR_STABLES_ENTRANCE = "LLR Stables Entrance" + LLR_TOWER_ENTRANCE = "LLR Tower Entrance" + MARKET_BAZAAR_ENTRANCE = "Market Bazaar Entrance" + MARKET_SHOOTING_GALLERY_ENTRANCE = "Market Shooing Gallery Entrance" + KAK_BAZAAR_ENTRANCE = "Kak Bazaar Entrance" + KAK_SHOOTING_GALLERY_ENTRANCE = "Kak Shooting Gallery Entrance" + COLOSSUS_GREAT_FAIRY_FOUNTAIN_ENTRANCE = "Colossus Great Fairy Fountain Entrance" + HC_GREAT_FAIRY_FOUNTAIN_ENTRANCE = "HC Great Fairy Fountain Entrance" + OGC_GREAT_FAIRY_FOUNTAIN_ENTRANCE = "OGC Great Fairy Fountain Entrance" + DMC_GREAT_FAIRY_FOUNTAIN_ENTRANCE = "DMC Great Fairy Fountain Entrance" + DMT_GREAT_FAIRY_FOUNTAIN_ENTRANCE = "DMT Great Fairy Fountain Entrance" + ZF_GREAT_FAIRY_FOUNTAIN_ENTRANCE = "ZF Great Fairy Fountain Entrance" + + +class SOHInteriorExitNames(StrEnum): + KF_MIDOS_HOUSE_EXIT = "KF Midos House Exit" + KF_SARIAS_HOUSE_EXIT = "KF Sarias House Exit" + KF_TWINS_HOUSE_EXIT = "KF Twins House Exit" + KF_KNOW_IT_ALL_HOUSE_EXIT = "KF Know It All House Exit" + KF_KOKIRI_SHOP_EXIT = "KF Kokiri Shop Exit" + LH_LAB_EXIT = "LH Lab Exit" + LH_FISHING_POND_EXIT = "LF Fishing Pond Exit" + GV_CARPENTER_TENT_EXIT = "GV Carpenter Tent Exit" + MARKET_GUARD_HOUSE_EXIT = "Market Guard House Exit" + MARKET_MASK_SHOP_EXIT = "Market Mask Shop Exit" + MARKET_BOMBCHU_BOWLING_EXIT = "Market Bombchu Bowling Exit" + MARKET_POTION_SHOP_EXIT = "Market Potion Shop Exit" + MARKET_TREASURE_CHEST_GAME_EXIT = "Market Treasure Chest Game Exit" + MARKET_BOMBCHU_SHOP_EXIT = "Market Bombchu Shop Exit" + MARKET_MAN_IN_GREEN_HOUSE_EXIT = "Market Man In Green House Exit" + KAK_CARPENTER_BOSS_HOUSE_EXIT = "Kak Carpenter Boss House Exit" + KAK_HOUSE_OF_SKULLTULA_EXIT = "Kak House Of Skulltula Exit" + KAK_IMPAS_HOUSE_EXIT = "Kak Impas House Exit" + KAK_IMPAS_HOUSE_BACK_EXIT = "Kak Impas House Back Exit" + KAK_ODD_POTION_BUILDING_EXIT = "Kak Odd Potion Building Exit" + GRAVEYARD_DAMPES_HOUSE_EXIT = "Graveyard Dampes House Exit" + GC_SHOP_EXIT = "GC Shop Exit" + ZD_SHOP_EXIT = "ZD Shop Exit" + LLR_TALONS_HOUSE_EXIT = "LLR Talons House Exit" + LLR_STABLES_EXIT = "LLR Stables Exit" + LLR_TOWER_EXIT = "LLR Tower Exit" + MARKET_BAZAAR_EXIT = "Market Bazaar Exit" + MARKET_SHOOTING_GALLERY_EXIT = "Market Shooing Gallery Exit" + KAK_BAZAAR_EXIT = "Kak Bazaar Exit" + KAK_SHOOTING_GALLERY_EXIT = "Kak Shooting Gallery Exit" + COLOSSUS_GREAT_FAIRY_FOUNTAIN_EXIT = "Colossus Great Fairy Fountain Exit" + HC_GREAT_FAIRY_FOUNTAIN_EXIT = "HC Great Fairy Fountain Exit" + OGC_GREAT_FAIRY_FOUNTAIN_EXIT = "OGC Great Fairy Fountain Exit" + DMC_GREAT_FAIRY_FOUNTAIN_EXIT = "DMC Great Fairy Fountain Exit" + DMT_GREAT_FAIRY_FOUNTAIN_EXIT = "DMT Great Fairy Fountain Exit" + ZF_GREAT_FAIRY_FOUNTAIN_EXIT = "ZF Great Fairy Fountain Exit" + + +class SOHSpecialInteriorEntranceNames(StrEnum): + KF_LINKS_HOUSE_ENTRANCE = "KF Links House Entrance" + TEMPLE_OF_TIME_ENTRANCE = "Temple Of Time Entrance" + KAK_WINDMILL_ENTRANCE = "Kak Windmill Entrance" + KAK_POTION_SHOP_FRONT_ENTRANCE = "Kak Potion Shop Front Entrance" + KAK_POTION_SHOP_BACK_ENTRANCE = "Kak Potion Shop Back Entrance" + + +class SOHSpecialInteriorExitNames(StrEnum): + KF_LINKS_HOUSE_EXIT = "KF Links House Exit" + TEMPLE_OF_TIME_EXIT = "Temple Of Time Exit" + KAK_WINDMILL_EXIT = "Kak Windmill Exit" + KAK_POTION_SHOP_FRONT_EXIT = "Kak Potion Shop Front Exit" + KAK_POTION_SHOP_BACK_EXIT = "Kak Potion Shop Back Exit" \ No newline at end of file diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index 18befff3eb10..7e430281b3e2 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -932,6 +932,22 @@ class ShuffleWarpSongEntrances(Toggle): display_name = "Shuffle Warp Song Entrances" +class ShuffleInteriorEntrances(Choice): + """ + Shuffle the pool of interior entrances which contains most houses and all Great Fairies + All - An extended version of 'Simple' with some extra places: + - Windmill + - Link's House + - Temple of Time + - Kakariko Potion Shop + """ + display_name = "Shuffle Interior Entrances" + option_off = 0 + option_simple = 1 + option_all = 2 + default = 0 + + class ShuffleOverworldSpawns(Toggle): """ Randomized where you start as Child or Adult when loading a save in the Overworld. This means you may not necessarily spawn inside Link's House or Temple of Time. @@ -1052,6 +1068,7 @@ class SohOptions(PerGameCommonOptions): shuffle_warp_song_entrances: ShuffleWarpSongEntrances shuffle_owl_drop_entrances: ShuffleOwlDropEntrances shuffle_overworld_spawns: ShuffleOverworldSpawns + shuffle_interior_entrances: ShuffleInteriorEntrances decouple_entrances: DecoupleEntrances mixed_entrances_pools: MixedEntrancePools @@ -1086,14 +1103,14 @@ class SohOptions(PerGameCommonOptions): OptionGroup("Shuffle Entrances", [ ShuffleDungeonEntrances, ShuffleDungeonBossEntrances, + ShuffleInteriorEntrances, ShuffleGrottoEntrances, ShuffleWarpSongEntrances, ShuffleOwlDropEntrances, + ShuffleOverworldSpawns, DecoupleEntrances, MixedEntrancePools # Overworld Entrances - # Interior Entrances - # Overworld Spawns ]), OptionGroup("Shuffle Items", [ # Shuffle Songs -- idk if this or the other ones here will be an actual option here, delete if not From 775f9a36485d66c4a3370d9733f9bc8c83bc8266 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Mon, 24 Nov 2025 19:39:02 -0500 Subject: [PATCH 17/22] Put in Interior Entrances --- worlds/oot_soh/EntranceShuffle.py | 13 ++++-- worlds/oot_soh/Enums.py | 2 + worlds/oot_soh/Options.py | 3 +- worlds/oot_soh/__init__.py | 27 ++++++++++--- .../overworld/castle_grounds.py | 8 ++-- .../overworld/death_mountain_crater.py | 4 +- .../overworld/death_mountain_trail.py | 4 +- .../overworld/desert_colossus.py | 4 +- .../overworld/gerudo_valley.py | 4 +- .../location_access/overworld/goron_city.py | 4 +- .../location_access/overworld/graveyard.py | 4 +- .../location_access/overworld/kakariko.py | 40 +++++++++---------- .../overworld/kokiri_forest.py | 24 +++++------ .../location_access/overworld/lake_hylia.py | 8 ++-- .../overworld/lon_lon_ranch.py | 12 +++--- .../location_access/overworld/market.py | 36 ++++++++--------- .../overworld/temple_of_time.py | 4 +- .../location_access/overworld/zoras_domain.py | 4 +- .../overworld/zoras_fountain.py | 4 +- 19 files changed, 115 insertions(+), 94 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 306e1a4ec644..5de068169bc3 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -1,6 +1,6 @@ from typing import TYPE_CHECKING, Callable from BaseClasses import Location, Region, Entrance -from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups, Regions, SOHBossWarpEntranceNames, SOHGrottoEntranceNames, SOHGrottoExitNames +from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups, Regions, SOHBossWarpEntranceNames, SOHGrottoEntranceNames, SOHGrottoExitNames, SOHInteriorEntranceNames, SOHInteriorExitNames, SOHSpecialInteriorEntranceNames, SOHSpecialInteriorExitNames from .Locations import SohLocation from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances, bake_target_group_lookup, EntranceRandomizationError from entrance_rando import ERPlacementState, Entrance @@ -28,6 +28,7 @@ SOHEntranceGroups.DUNGEON_ENTRANCE: [SOHEntranceGroups.DUNGEON_ENTRANCE], SOHEntranceGroups.BOSS_ENTRANCE: [SOHEntranceGroups.BOSS_ENTRANCE], SOHEntranceGroups.GROTTO: [SOHEntranceGroups.GROTTO], + SOHEntranceGroups.INTERIOR: [SOHEntranceGroups.INTERIOR], } @@ -38,7 +39,7 @@ # This is allowing us to brute force the problem of GER failing. May be a necessary evil as it doesn't do swap or automatic retries itself. -OOT_SOH_GER_RETRIES_AMOUNT: int = 10 +OOT_SOH_GER_RETRIES_AMOUNT: int = 1000 def get_target_groups(group: int) -> list[int]: type = group & SOHEntranceGroups.TYPE_MASK @@ -113,7 +114,7 @@ def randomize_soh_one_way_entrances(world: "SohWorld") -> None: one_way_entrance_names = list() one_way_entrance_exit_names = list() # TODO This will need to be updated as we make more named entrances - all_named_entrances = list(SOHDungeonEntranceNames) + list(SOHDungeonExitNames) + list(SOHGrottoExitNames) + list(SOHGrottoEntranceNames) + all_named_entrances = list(SOHDungeonEntranceNames) + list(SOHDungeonExitNames) + list(SOHGrottoExitNames) + list(SOHGrottoEntranceNames) + list(SOHInteriorEntranceNames) + list(SOHInteriorExitNames) + list(SOHSpecialInteriorExitNames) + list(SOHSpecialInteriorEntranceNames) if world.options.shuffle_owl_drop_entrances: one_way_entrance_names += [Regions.LH_OWL_FLIGHT, Regions.DMT_OWL_FLIGHT] @@ -222,7 +223,11 @@ def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBoss # This should probably be double checked by someone who knows how to properly remove a location from a region and give it a new parent region -def on_connect_soh_sheik_at_colossus(er_state: ERPlacementState, placed_exits: list[Entrance], paired_entrances: list[Entrance]) -> bool: +def on_connect_soh(er_state: ERPlacementState, placed_exits: list[Entrance], paired_entrances: list[Entrance]) -> bool: + # Force a rescan of all reachable regions + er_state.collection_state._soh_stale[er_state.world.player] = True + + # Sheik at colossus logic fix if er_state.world.options.decouple_entrances and len(paired_entrances) >= 2 and paired_entrances[1].name == SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE: world: SohWorld = er_state.world def locationRule(bundle): return True diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index 02d3e5fc2ade..18ad0796f1d2 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -4118,6 +4118,8 @@ class SOHSpecialInteriorExitNames(StrEnum): KAK_WINDMILL_EXIT = "Kak Windmill Exit" KAK_POTION_SHOP_FRONT_EXIT = "Kak Potion Shop Front Exit" KAK_POTION_SHOP_BACK_EXIT = "Kak Potion Shop Back Exit" + + class TokenCounts(IntEnum): DUNGEON = 44 OVERWORLD = 56 diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index edfe1e732567..4aad72e3847f 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -972,13 +972,12 @@ class DecoupleEntrances(Toggle): display_name = "Decouple Entrances" visibility = Visibility.none -#currently doesn't work with entrances that are behind other randomized entrances + class MixedEntrancePools(Toggle): """ Shuffle entrances into a mixed pool instead of separate ones. Has no effect on pools whose entrances aren't shuffled, and "Shuffle Boss Entrances" must be set to "Full" to include them. """ display_name = "Mixed Entrances Pools" - visibility = Visibility.none @dataclass diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index 6f17f72e8696..8059b332bf24 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -19,7 +19,7 @@ from settings import Group, Bool from Options import OptionError from .LogicHelpers import wallet_capacities -from .EntranceShuffle import randomize_entrances_soh, on_connect_soh_sheik_at_colossus, randomize_soh_one_way_entrances +from .EntranceShuffle import randomize_entrances_soh, on_connect_soh, randomize_soh_one_way_entrances from entrance_rando import bake_target_group_lookup import logging @@ -249,10 +249,10 @@ def connect_entrances(self): if self.options.shuffle_boss_entrances == "age_restricted": randomize_entrances_soh(self, entrances_to_shuffle, ageRestricted=True) entrances_to_shuffle.clear() - else: - # Need this else here. Mixed entrances doesn't work for entrances locked behind another yet. Boss entrances are behind dungeon entrances - randomize_entrances_soh(self, entrances_to_shuffle) - entrances_to_shuffle.clear() + # else: + # # Need this else here. Mixed entrances doesn't work for entrances locked behind another yet. Boss entrances are behind dungeon entrances + # randomize_entrances_soh(self, entrances_to_shuffle) + # entrances_to_shuffle.clear() # Grotto Entrances if self.options.shuffle_grotto_entrances: @@ -262,6 +262,21 @@ def connect_entrances(self): for entranceName in SOHGrottoEntranceNames: entrances_to_shuffle.add(entranceName) + # Interior Entrances + if self.options.shuffle_interior_entrances: + if self.options.shuffle_interior_entrances == "all": + for entranceName in SOHSpecialInteriorExitNames: + entrances_to_shuffle.add(entranceName) + + for entranceName in SOHSpecialInteriorEntranceNames: + entrances_to_shuffle.add(entranceName) + + for entranceName in SOHInteriorExitNames: + entrances_to_shuffle.add(entranceName) + + for entranceName in SOHInteriorEntranceNames: + entrances_to_shuffle.add(entranceName) + # Dungeon Entrances if self.options.shuffle_dungeon_entrances: for entranceName in SOHDungeonExitNames: @@ -274,7 +289,7 @@ def connect_entrances(self): if len(entrances_to_shuffle) > 0: randomize_entrances_soh( - self, entrances_to_shuffle, on_connect_soh_sheik_at_colossus, coupled) + self, entrances_to_shuffle, on_connect_soh, coupled) return super().connect_entrances() diff --git a/worlds/oot_soh/location_access/overworld/castle_grounds.py b/worlds/oot_soh/location_access/overworld/castle_grounds.py index dbb552d3049a..c2efd6353afb 100644 --- a/worlds/oot_soh/location_access/overworld/castle_grounds.py +++ b/worlds/oot_soh/location_access/overworld/castle_grounds.py @@ -68,7 +68,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.HYRULE_CASTLE_GROUNDS, world, [ (Regions.CASTLE_GROUNDS, lambda bundle: True), - (Regions.HC_GREAT_FAIRY_FOUNTAIN, lambda bundle: blast_or_smash(bundle)), + (Regions.HC_GREAT_FAIRY_FOUNTAIN, lambda bundle: blast_or_smash(bundle), SOHInteriorEntranceNames.HC_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.HC_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle), SOHGrottoEntranceNames.HC_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD_ONLY) ]) if not world.options.skip_child_zelda: @@ -103,7 +103,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HC_GREAT_FAIRY_FOUNTAIN, world, [ - (Regions.CASTLE_GROUNDS, lambda bundle: True) + (Regions.CASTLE_GROUNDS, lambda bundle: True, SOHInteriorExitNames.HC_GREAT_FAIRY_FOUNTAIN_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Hyrule Castle Storms Grotto @@ -168,7 +168,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.GANONS_CASTLE_GROUNDS, world, [ (Regions.CASTLE_GROUNDS, lambda bundle: at_night(bundle)), (Regions.OGC_GREAT_FAIRY_FOUNTAIN, lambda bundle: can_use( - Items.GOLDEN_GAUNTLETS, bundle) and at_night(bundle)), + Items.GOLDEN_GAUNTLETS, bundle) and at_night(bundle), SOHInteriorEntranceNames.OGC_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.GANONS_CASTLE_LEDGE, lambda bundle: has_item( LocalEvents.HC_OGC_RAINBOW_BRIDGE_BUILT, bundle)) ]) @@ -181,7 +181,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.OGC_GREAT_FAIRY_FOUNTAIN, world, [ - (Regions.CASTLE_GROUNDS, lambda bundle: True) + (Regions.CASTLE_GROUNDS, lambda bundle: True, SOHInteriorExitNames.OGC_GREAT_FAIRY_FOUNTAIN_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Deviation from Ship, but makes ER easier diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py index c4e38616e4f1..3baed4678419 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py @@ -85,7 +85,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DMC_LOWER_LOCAL, lambda bundle: fire_timer(bundle) >= 48), (Regions.GC_DARUNIAS_CHAMBER, lambda bundle: True), (Regions.DMC_GREAT_FAIRY_FOUNTAIN, - lambda bundle: can_use(Items.MEGATON_HAMMER, bundle)), + lambda bundle: can_use(Items.MEGATON_HAMMER, bundle), SOHInteriorEntranceNames.DMC_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.DMC_HAMMER_GROTTO, lambda bundle: is_adult( bundle) and can_use(Items.MEGATON_HAMMER, bundle), SOHGrottoEntranceNames.DMC_HAMMER_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY) ]) @@ -175,7 +175,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.DMC_GREAT_FAIRY_FOUNTAIN, world, [ - (Regions.DMC_LOWER_LOCAL, lambda bundle: True) + (Regions.DMC_LOWER_LOCAL, lambda bundle: True, SOHInteriorExitNames.DMC_GREAT_FAIRY_FOUNTAIN_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Death Mountain Crater Upper Grotto diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py index e66a2138edba..e8b8c9d9f711 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py @@ -99,7 +99,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DMC_UPPER_LOCAL, lambda bundle: True), (Regions.DMT_OWL_FLIGHT, lambda bundle: is_child(bundle)), (Regions.DMT_COW_GROTTO, lambda bundle: blast_or_smash(bundle), SOHGrottoEntranceNames.DMT_COW_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), - (Regions.DMT_GREAT_FAIRY_FOUNTAIN, lambda bundle: blast_or_smash(bundle)) + (Regions.DMT_GREAT_FAIRY_FOUNTAIN, lambda bundle: blast_or_smash(bundle), SOHInteriorEntranceNames.DMT_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Death Mountain Trail Owl Flight @@ -178,5 +178,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.DMT_GREAT_FAIRY_FOUNTAIN, world, [ - (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: True) + (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: True, SOHInteriorExitNames.DMT_GREAT_FAIRY_FOUNTAIN_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/desert_colossus.py b/worlds/oot_soh/location_access/overworld/desert_colossus.py index ff9cf1a3a51c..e51dc75d48a6 100644 --- a/worlds/oot_soh/location_access/overworld/desert_colossus.py +++ b/worlds/oot_soh/location_access/overworld/desert_colossus.py @@ -59,7 +59,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.DESERT_COLOSSUS_OASIS, lambda bundle: can_use(Items.SONG_OF_STORMS, bundle) and ( has_item(Items.BRONZE_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle))), (Regions.COLOSSUS_GREAT_FAIRY_FOUNTAIN, - lambda bundle: has_explosives(bundle)), + lambda bundle: has_explosives(bundle), SOHInteriorEntranceNames.COLOSSUS_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.SPIRIT_TEMPLE_ENTRYWAY, lambda bundle: True, SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY), (Regions.WASTELAND_NEAR_COLOSSUS, lambda bundle: True), @@ -108,7 +108,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.COLOSSUS_GREAT_FAIRY_FOUNTAIN, world, [ - (Regions.DESERT_COLOSSUS, lambda bundle: True) + (Regions.DESERT_COLOSSUS, lambda bundle: True, SOHInteriorExitNames.COLOSSUS_GREAT_FAIRY_FOUNTAIN_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Desert Colossus Great Fairy Fountain diff --git a/worlds/oot_soh/location_access/overworld/gerudo_valley.py b/worlds/oot_soh/location_access/overworld/gerudo_valley.py index caf1501aaca2..1f952b1026fc 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_valley.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_valley.py @@ -150,7 +150,7 @@ def set_region_rules(world: "SohWorld") -> None: lambda bundle: is_child(bundle) or can_use(Items.EPONA, bundle) or can_use(Items.LONGSHOT, bundle) or world.options.fortress_carpenters.value == 2 or has_item( Events.RESCUED_ALL_CARPENTERS, bundle)), - (Regions.GV_CARPENTER_TENT, lambda bundle: is_adult(bundle)), + (Regions.GV_CARPENTER_TENT, lambda bundle: is_adult(bundle), SOHInteriorEntranceNames.GV_CARPENTER_TENT_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.GV_STORMS_GROTTO, lambda bundle: is_adult( bundle) and can_open_storms_grotto(bundle), SOHGrottoEntranceNames.GV_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GV_CRATE_LEDGE, @@ -160,7 +160,7 @@ def set_region_rules(world: "SohWorld") -> None: # GV Carpenter Tent # Connections connect_regions(Regions.GV_CARPENTER_TENT, world, [ - (Regions.GV_FORTRESS_SIDE, lambda bundle: True), + (Regions.GV_FORTRESS_SIDE, lambda bundle: True, SOHInteriorExitNames.GV_CARPENTER_TENT_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), ]) # GV Octorok Grotto diff --git a/worlds/oot_soh/location_access/overworld/goron_city.py b/worlds/oot_soh/location_access/overworld/goron_city.py index ed3f251968e2..47624081d369 100644 --- a/worlds/oot_soh/location_access/overworld/goron_city.py +++ b/worlds/oot_soh/location_access/overworld/goron_city.py @@ -82,7 +82,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GC_WOODS_WARP, lambda bundle: has_item( LocalEvents.GC_WOODS_WARP_OPEN, bundle)), (Regions.GC_SHOP, lambda bundle: (is_adult(bundle) and has_item(LocalEvents.GC_STOP_ROLLING_GORON_AS_ADULT, bundle)) or (is_child(bundle) and ( - blast_or_smash(bundle) or has_item(Items.GORONS_BRACELET, bundle) or has_item(LocalEvents.GC_CHILD_FIRE_LIT, bundle) or can_use(Items.FAIRY_BOW, bundle)))), + blast_or_smash(bundle) or has_item(Items.GORONS_BRACELET, bundle) or has_item(LocalEvents.GC_CHILD_FIRE_LIT, bundle) or can_use(Items.FAIRY_BOW, bundle))), SOHInteriorEntranceNames.GC_SHOP_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.GC_DARUNIAS_CHAMBER, lambda bundle: (is_adult(bundle) and has_item(LocalEvents.GC_STOP_ROLLING_GORON_AS_ADULT, bundle)) or (is_child(bundle) and has_item(LocalEvents.GC_DARUNIAS_DOOR_OPENED_AS_CHILD, bundle))), (Regions.GC_GROTTO_PLATFORM, lambda bundle: is_adult(bundle) and ((can_use(Items.SONG_OF_TIME, bundle) and ((effective_health(bundle) > 2) or can_use(Items.GORON_TUNIC, bundle) or can_use(Items.LONGSHOT, bundle) or can_use(Items.NAYRUS_LOVE, bundle))) or (effective_health( @@ -158,7 +158,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GC_SHOP, world, [ - (Regions.GORON_CITY, lambda bundle: True) + (Regions.GORON_CITY, lambda bundle: True, SOHInteriorExitNames.GC_SHOP_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Goron City Grotto diff --git a/worlds/oot_soh/location_access/overworld/graveyard.py b/worlds/oot_soh/location_access/overworld/graveyard.py index f25a05f0f6a5..6b90806af4c2 100644 --- a/worlds/oot_soh/location_access/overworld/graveyard.py +++ b/worlds/oot_soh/location_access/overworld/graveyard.py @@ -77,7 +77,7 @@ def set_region_rules(world: "SohWorld") -> None: lambda bundle: is_adult(bundle) or at_night(bundle), SOHGrottoEntranceNames.GRAVEYARD_HEART_PIECE_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.GRAVEYARD_DAMPES_GRAVE, lambda bundle: is_adult(bundle), SOHGrottoEntranceNames.GRAVEYARD_DAMPES_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GRAVEYARD_DAMPES_HOUSE, lambda bundle: is_adult(bundle) - and can_open_overworld_door(Items.DAMPES_HUT_KEY, bundle)), + and can_open_overworld_door(Items.DAMPES_HUT_KEY, bundle), SOHInteriorEntranceNames.GRAVEYARD_DAMPES_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.KAKARIKO_VILLAGE, lambda bundle: True), (Regions.GRAVEYARD_WARP_PAD_REGION, lambda bundle: False) ]) @@ -181,7 +181,7 @@ def set_region_rules(world: "SohWorld") -> None: # The Graveyard Dampes House # Connections connect_regions(Regions.GRAVEYARD_DAMPES_HOUSE, world, [ - (Regions.THE_GRAVEYARD, lambda bundle: True) + (Regions.THE_GRAVEYARD, lambda bundle: True, SOHInteriorExitNames.GRAVEYARD_DAMPES_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # The Graveyard Warp Pad Region diff --git a/worlds/oot_soh/location_access/overworld/kakariko.py b/worlds/oot_soh/location_access/overworld/kakariko.py index 53b5fdbc6747..f8cca3256b55 100644 --- a/worlds/oot_soh/location_access/overworld/kakariko.py +++ b/worlds/oot_soh/location_access/overworld/kakariko.py @@ -124,18 +124,18 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.KAKARIKO_VILLAGE, world, [ (Regions.HYRULE_FIELD, lambda bundle: True), (Regions.KAK_CARPENTER_BOSS_HOUSE, - lambda bundle: can_open_overworld_door(Items.BOSS_HOUSE_KEY, bundle)), + lambda bundle: can_open_overworld_door(Items.BOSS_HOUSE_KEY, bundle), SOHInteriorEntranceNames.KAK_CARPENTER_BOSS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_HOUSE_OF_SKULLTULA, lambda bundle: can_open_overworld_door( - Items.SKULLTULA_HOUSE_KEY, bundle)), + Items.SKULLTULA_HOUSE_KEY, bundle), SOHInteriorEntranceNames.KAK_HOUSE_OF_SKULLTULA_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_IMPAS_HOUSE, lambda bundle: can_open_overworld_door( - Items.IMPAS_HOUSE_KEY, bundle)), + Items.IMPAS_HOUSE_KEY, bundle), SOHInteriorEntranceNames.KAK_IMPAS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_WINDMILL, lambda bundle: can_open_overworld_door( - Items.WINDMILL_KEY, bundle)), + Items.WINDMILL_KEY, bundle), SOHSpecialInteriorEntranceNames.KAK_WINDMILL_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_BAZAAR, - lambda bundle: is_adult(bundle) and at_day(bundle) and can_open_overworld_door(Items.KAK_BAZAAR_KEY, bundle)), + lambda bundle: is_adult(bundle) and at_day(bundle) and can_open_overworld_door(Items.KAK_BAZAAR_KEY, bundle), SOHInteriorEntranceNames.KAK_BAZAAR_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.KAK_SHOOTING_GALLERY, lambda bundle: is_adult(bundle) and at_day(bundle) and can_open_overworld_door(Items.KAK_SHOOTING_GALLERY_KEY, - bundle)), + bundle), SOHInteriorEntranceNames.KAK_SHOOTING_GALLERY_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.KAK_WELL, lambda bundle: is_adult(bundle) or has_item(Events.DRAIN_WELL, bundle) or can_use(Items.IRON_BOOTS, bundle) or ( @@ -143,7 +143,7 @@ def set_region_rules(world: "SohWorld") -> None: bundle) and has_item(Items.BRONZE_SCALE, bundle) and can_jump_slash(bundle))), (Regions.KAK_POTION_SHOP_FRONT, lambda bundle: (at_day(bundle) or is_child(bundle)) and can_open_overworld_door( - Items.KAK_POTION_SHOP_KEY, bundle)), + Items.KAK_POTION_SHOP_KEY, bundle), SOHSpecialInteriorEntranceNames.KAK_POTION_SHOP_FRONT_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_REDEAD_GROTTO, lambda bundle: can_open_bomb_grotto(bundle), SOHGrottoEntranceNames.KAK_REDEAD_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.KAK_IMPAS_LEDGE, lambda bundle: (is_child(bundle) and at_day(bundle)) or ( is_adult(bundle) and can_do_trick(Tricks.VISIBLE_COLLISION, bundle))), @@ -166,7 +166,7 @@ def set_region_rules(world: "SohWorld") -> None: # Kak Impas Ledge # Connections connect_regions(Regions.KAK_IMPAS_LEDGE, world, [ - (Regions.KAK_IMPAS_HOUSE_BACK, lambda bundle: True), + (Regions.KAK_IMPAS_HOUSE_BACK, lambda bundle: True, SOHInteriorEntranceNames.KAK_IMPAS_HOUSE_BACK_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.KAKARIKO_VILLAGE, lambda bundle: True), ]) @@ -220,10 +220,10 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.KAKARIKO_VILLAGE, lambda bundle: True), (Regions.KAK_OPEN_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.KAK_OPEN_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.KAK_GRANNYS_POTION_SHOP, - lambda bundle: is_adult(bundle) and can_open_overworld_door(Items.GRANNYS_POTION_SHOP_KEY, bundle)), + lambda bundle: is_adult(bundle) and can_open_overworld_door(Items.GRANNYS_POTION_SHOP_KEY, bundle), SOHInteriorEntranceNames.KAK_ODD_POTION_BUILDING_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.KAK_POTION_SHOP_BACK, lambda bundle: is_adult(bundle) and at_day(bundle) and can_open_overworld_door(Items.KAK_POTION_SHOP_KEY, - bundle)), + bundle), SOHSpecialInteriorEntranceNames.KAK_POTION_SHOP_BACK_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), ]) # Kak Carpenter Boss House @@ -235,7 +235,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_CARPENTER_BOSS_HOUSE, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHInteriorExitNames.KAK_CARPENTER_BOSS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT), ]) # Kak House of Skulltula @@ -256,13 +256,13 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_HOUSE_OF_SKULLTULA, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHInteriorExitNames.KAK_HOUSE_OF_SKULLTULA_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), ]) # Kak Impas House # Connections connect_regions(Regions.KAK_IMPAS_HOUSE, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHInteriorExitNames.KAK_IMPAS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_COW_CAGE, lambda bundle: can_play_song(Items.EPONAS_SONG, bundle)) ]) @@ -273,7 +273,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_IMPAS_HOUSE_BACK, world, [ - (Regions.KAK_IMPAS_LEDGE, lambda bundle: True), + (Regions.KAK_IMPAS_LEDGE, lambda bundle: True, SOHInteriorExitNames.KAK_IMPAS_HOUSE_BACK_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_COW_CAGE, lambda bundle: can_play_song(Items.EPONAS_SONG, bundle)), ]) @@ -302,7 +302,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_WINDMILL, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHSpecialInteriorExitNames.KAK_WINDMILL_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.BOTH_AGE), ]) # Kak Bazaar @@ -318,7 +318,7 @@ def set_region_rules(world: "SohWorld") -> None: (Locations.KAK_BAZAAR_ITEM8, lambda bundle: True), ]) connect_regions(Regions.KAK_BAZAAR, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHInteriorExitNames.KAK_BAZAAR_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), ]) # Kak Shooting Gallery @@ -329,7 +329,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_SHOOTING_GALLERY, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHInteriorExitNames.KAK_SHOOTING_GALLERY_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), ]) # Kak Potion Shop Front @@ -346,7 +346,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_POTION_SHOP_FRONT, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHSpecialInteriorExitNames.KAK_POTION_SHOP_FRONT_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_POTION_SHOP_BACK, lambda bundle: is_adult(bundle)), ]) @@ -354,7 +354,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.KAK_POTION_SHOP_BACK, world, [ (Regions.KAK_POTION_SHOP_FRONT, lambda bundle: True), - (Regions.KAK_BACKYARD, lambda bundle: is_adult(bundle)), + (Regions.KAK_BACKYARD, lambda bundle: is_adult(bundle), SOHSpecialInteriorExitNames.KAK_POTION_SHOP_BACK_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), ]) # Kak Granny's Potion Shop @@ -368,7 +368,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_GRANNYS_POTION_SHOP, world, [ - (Regions.KAK_BACKYARD, lambda bundle: True) + (Regions.KAK_BACKYARD, lambda bundle: True, SOHInteriorExitNames.KAK_ODD_POTION_BUILDING_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY) ]) # Kak Redead Grotto diff --git a/worlds/oot_soh/location_access/overworld/kokiri_forest.py b/worlds/oot_soh/location_access/overworld/kokiri_forest.py index ad94313cead3..fd0c07a3b393 100644 --- a/worlds/oot_soh/location_access/overworld/kokiri_forest.py +++ b/worlds/oot_soh/location_access/overworld/kokiri_forest.py @@ -167,12 +167,12 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KOKIRI_FOREST, world, [ - (Regions.KF_LINKS_HOUSE, lambda bundle: True), - (Regions.KF_MIDOS_HOUSE, lambda bundle: True), - (Regions.KF_SARIAS_HOUSE, lambda bundle: True), - (Regions.KF_HOUSE_OF_TWINS, lambda bundle: True), - (Regions.KF_KNOW_IT_ALL_HOUSE, lambda bundle: True), - (Regions.KF_KOKIRI_SHOP, lambda bundle: True), + (Regions.KF_LINKS_HOUSE, lambda bundle: True, SOHSpecialInteriorEntranceNames.KF_LINKS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), + (Regions.KF_MIDOS_HOUSE, lambda bundle: True, SOHInteriorEntranceNames.KF_MIDOS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), + (Regions.KF_SARIAS_HOUSE, lambda bundle: True, SOHInteriorEntranceNames.KF_SARIAS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), + (Regions.KF_HOUSE_OF_TWINS, lambda bundle: True, SOHInteriorEntranceNames.KF_TWINS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), + (Regions.KF_KNOW_IT_ALL_HOUSE, lambda bundle: True, SOHInteriorEntranceNames.KF_KNOW_IT_ALL_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), + (Regions.KF_KOKIRI_SHOP, lambda bundle: True, SOHInteriorEntranceNames.KF_KOKIRI_SHOP_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KF_OUTSIDE_DEKU_TREE, lambda bundle: (is_adult(bundle) and (can_pass_enemy(bundle, Enemies.BIG_SKULLTULA) or has_item(Events.FOREST_TEMPLE_COMPLETED, bundle))) @@ -230,7 +230,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KF_LINKS_HOUSE, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True) + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHSpecialInteriorExitNames.KF_LINKS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # KF Mido's House @@ -243,7 +243,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KF_MIDOS_HOUSE, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True) + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHInteriorExitNames.KF_MIDOS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # KF Saria's House @@ -256,7 +256,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KF_SARIAS_HOUSE, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True) + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHInteriorExitNames.KF_SARIAS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # KF House of Twins @@ -268,7 +268,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KF_HOUSE_OF_TWINS, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True) + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHInteriorExitNames.KF_TWINS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # KF Know it All House @@ -280,7 +280,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KF_KNOW_IT_ALL_HOUSE, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True) + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHInteriorExitNames.KF_KNOW_IT_ALL_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # KF Kokiri Shop @@ -297,7 +297,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KF_KOKIRI_SHOP, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True) + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHInteriorExitNames.KF_KOKIRI_SHOP_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # KF Storms Grotto diff --git a/worlds/oot_soh/location_access/overworld/lake_hylia.py b/worlds/oot_soh/location_access/overworld/lake_hylia.py index ec704b4aa25a..3c0ec5f33205 100644 --- a/worlds/oot_soh/location_access/overworld/lake_hylia.py +++ b/worlds/oot_soh/location_access/overworld/lake_hylia.py @@ -165,7 +165,7 @@ def set_region_rules(world: "SohWorld") -> None: and (can_use(Items.SCARECROW, bundle) or has_item(LocalEvents.LH_BEAN_PLANTED, bundle)))), (Regions.LH_LAB, lambda bundle: can_open_overworld_door( - Items.HYLIA_LAB_KEY, bundle)), + Items.HYLIA_LAB_KEY, bundle), SOHInteriorEntranceNames.LH_LAB_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.LH_FROM_WATER_TEMPLE, lambda bundle: True), (Regions.LH_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.LH_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) @@ -202,7 +202,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.LH_FISHING_ISLAND, world, [ (Regions.LAKE_HYLIA, lambda bundle: has_item(Items.BRONZE_SCALE, bundle)), (Regions.LH_FISHING_HOLE, lambda bundle: can_open_overworld_door( - Items.FISHING_HOLE_KEY, bundle)), + Items.FISHING_HOLE_KEY, bundle), SOHInteriorEntranceNames.LH_FISHING_POND_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), ]) # LH Owl Flight @@ -234,7 +234,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LH_LAB, world, [ - (Regions.LAKE_HYLIA, lambda bundle: True), + (Regions.LAKE_HYLIA, lambda bundle: True, SOHInteriorExitNames.LH_LAB_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT), ]) # LH Fishing HOLE @@ -316,7 +316,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LH_FISHING_HOLE, world, [ - (Regions.LH_FISHING_ISLAND, lambda bundle: True), + (Regions.LH_FISHING_ISLAND, lambda bundle: True, SOHInteriorExitNames.LH_FISHING_POND_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.BOTH_AGE), ]) # LH Grotto diff --git a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py index ceda3eb82413..797f48b18fce 100644 --- a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py +++ b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py @@ -53,11 +53,11 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.LON_LON_RANCH, world, [ (Regions.HYRULE_FIELD, lambda bundle: True), (Regions.LLR_TALONS_HOUSE, lambda bundle: can_open_overworld_door( - Items.TALONS_HOUSE_KEY, bundle)), + Items.TALONS_HOUSE_KEY, bundle), SOHInteriorEntranceNames.LLR_TALONS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.LLR_STABLES, lambda bundle: can_open_overworld_door( - Items.STABLES_KEY, bundle)), + Items.STABLES_KEY, bundle), SOHInteriorEntranceNames.LLR_STABLES_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.LLR_TOWER, lambda bundle: can_open_overworld_door( - Items.BACK_TOWER_KEY, bundle)), + Items.BACK_TOWER_KEY, bundle), SOHInteriorEntranceNames.LLR_TOWER_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.LLR_GROTTO, lambda bundle: is_child(bundle), SOHGrottoEntranceNames.LLR_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.CHILD_ONLY), ]) @@ -72,7 +72,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LLR_TALONS_HOUSE, world, [ - (Regions.LON_LON_RANCH, lambda bundle: True) + (Regions.LON_LON_RANCH, lambda bundle: True, SOHInteriorExitNames.LLR_TALONS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # LLR Stables @@ -85,7 +85,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LLR_STABLES, world, [ - (Regions.LON_LON_RANCH, lambda bundle: True) + (Regions.LON_LON_RANCH, lambda bundle: True, SOHInteriorExitNames.LLR_STABLES_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # LLR Tower @@ -99,7 +99,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LLR_TOWER, world, [ - (Regions.LON_LON_RANCH, lambda bundle: True) + (Regions.LON_LON_RANCH, lambda bundle: True, SOHInteriorExitNames.LLR_TOWER_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY) ]) # LLR Grotto diff --git a/worlds/oot_soh/location_access/overworld/market.py b/worlds/oot_soh/location_access/overworld/market.py index 50dc336489a9..fea70f06d0d3 100644 --- a/worlds/oot_soh/location_access/overworld/market.py +++ b/worlds/oot_soh/location_access/overworld/market.py @@ -22,7 +22,7 @@ def set_region_rules(world: "SohWorld") -> None: is_adult(bundle) or at_day(bundle))), (Regions.MARKET, lambda bundle: True), (Regions.MARKET_GUARD_HOUSE, lambda bundle: can_open_overworld_door( - Items.GUARD_HOUSE_KEY, bundle)) + Items.GUARD_HOUSE_KEY, bundle), SOHInteriorEntranceNames.MARKET_GUARD_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Market @@ -59,17 +59,17 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.TOT_ENTRANCE, lambda bundle: True), (Regions.CASTLE_GROUNDS, lambda bundle: True), (Regions.MARKET_BAZAAR, lambda bundle: (is_child(bundle) and at_day( - bundle) and can_open_overworld_door(Items.MARKET_BAZAAR_KEY, bundle))), + bundle) and can_open_overworld_door(Items.MARKET_BAZAAR_KEY, bundle)), SOHInteriorEntranceNames.MARKET_BAZAAR_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.MARKET_MASK_SHOP, lambda bundle: (is_child(bundle) and at_day( - bundle) and can_open_overworld_door(Items.MASK_SHOP_KEY, bundle))), + bundle) and can_open_overworld_door(Items.MASK_SHOP_KEY, bundle)), SOHInteriorEntranceNames.MARKET_MASK_SHOP_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.MARKET_SHOOTING_GALLERY, lambda bundle: (is_child(bundle) and at_day( - bundle) and can_open_overworld_door(Items.MARKET_SHOOTING_GALLERY_KEY, bundle))), + bundle) and can_open_overworld_door(Items.MARKET_SHOOTING_GALLERY_KEY, bundle)), SOHInteriorEntranceNames.MARKET_SHOOTING_GALLERY_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.MARKET_BOMBCHU_BOWLING, lambda bundle: (is_child(bundle) - and can_open_overworld_door(Items.BOMBCHU_BOWLING_KEY, bundle))), + and can_open_overworld_door(Items.BOMBCHU_BOWLING_KEY, bundle)), SOHInteriorEntranceNames.MARKET_BOMBCHU_BOWLING_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.MARKET_TREASURE_CHEST_GAME, lambda bundle: (is_child(bundle) and at_night( - bundle) and can_open_overworld_door(Items.TREASURE_CHEST_GAME_BUILDING_KEY, bundle))), + bundle) and can_open_overworld_door(Items.TREASURE_CHEST_GAME_BUILDING_KEY, bundle)), SOHInteriorEntranceNames.MARKET_TREASURE_CHEST_GAME_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.MARKET_POTION_SHOP, lambda bundle: (is_child(bundle) and at_day( - bundle) and can_open_overworld_door(Items.MARKET_POTION_SHOP_KEY, bundle))), + bundle) and can_open_overworld_door(Items.MARKET_POTION_SHOP_KEY, bundle)), SOHInteriorEntranceNames.MARKET_POTION_SHOP_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.MARKET_BACK_ALLEY, lambda bundle: is_child(bundle)) ]) @@ -78,11 +78,11 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.MARKET_BACK_ALLEY, world, [ (Regions.MARKET, lambda bundle: True), (Regions.MARKET_BOMBCHU_SHOP, lambda bundle: (at_night(bundle) - and can_open_overworld_door(Items.BOMBCHU_SHOP_KEY, bundle))), + and can_open_overworld_door(Items.BOMBCHU_SHOP_KEY, bundle)), SOHInteriorEntranceNames.MARKET_BOMBCHU_SHOP_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.MARKET_DOG_LADY_HOUSE, lambda bundle: ( can_open_overworld_door(Items.RICHARDS_HOUSE_KEY, bundle))), (Regions.MARKET_MAN_IN_GREEN_HOUSE, lambda bundle: (at_night(bundle) - and can_open_overworld_door(Items.ALLEY_HOUSE_KEY, bundle))) + and can_open_overworld_door(Items.ALLEY_HOUSE_KEY, bundle)), SOHInteriorEntranceNames.MARKET_MAN_IN_GREEN_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY) ]) # Market Guard House @@ -221,7 +221,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_GUARD_HOUSE, world, [ - (Regions.MARKET_ENTRANCE, lambda bundle: True) + (Regions.MARKET_ENTRANCE, lambda bundle: True, SOHInteriorExitNames.MARKET_GUARD_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.BOTH_AGE) ]) # Market Bazaar @@ -238,7 +238,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_BAZAAR, world, [ - (Regions.MARKET, lambda bundle: True) + (Regions.MARKET, lambda bundle: True, SOHInteriorExitNames.MARKET_BAZAAR_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Market Mask Shop @@ -257,7 +257,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_MASK_SHOP, world, [ - (Regions.MARKET, lambda bundle: True) + (Regions.MARKET, lambda bundle: True, SOHInteriorExitNames.MARKET_MASK_SHOP_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Market Shooting Gallery @@ -268,7 +268,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_SHOOTING_GALLERY, world, [ - (Regions.MARKET, lambda bundle: True) + (Regions.MARKET, lambda bundle: True, SOHInteriorExitNames.MARKET_SHOOTING_GALLERY_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY) ]) # Market Bombchu Bowling @@ -286,7 +286,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_BOMBCHU_BOWLING, world, [ - (Regions.MARKET, lambda bundle: True) + (Regions.MARKET, lambda bundle: True, SOHInteriorExitNames.MARKET_BOMBCHU_BOWLING_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Market Potion Shop @@ -303,7 +303,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_POTION_SHOP, world, [ - (Regions.MARKET, lambda bundle: True) + (Regions.MARKET, lambda bundle: True, SOHInteriorExitNames.MARKET_POTION_SHOP_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Market Treasure Chest Game @@ -314,7 +314,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_TREASURE_CHEST_GAME, world, [ - (Regions.MARKET, lambda bundle: True) + (Regions.MARKET, lambda bundle: True, SOHInteriorExitNames.MARKET_TREASURE_CHEST_GAME_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Market Bombchu Shop @@ -331,7 +331,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_BOMBCHU_SHOP, world, [ - (Regions.MARKET_BACK_ALLEY, lambda bundle: True) + (Regions.MARKET_BACK_ALLEY, lambda bundle: True, SOHInteriorExitNames.MARKET_BOMBCHU_SHOP_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Market Dog Lady House @@ -359,5 +359,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_MAN_IN_GREEN_HOUSE, world, [ - (Regions.MARKET_BACK_ALLEY, lambda bundle: True) + (Regions.MARKET_BACK_ALLEY, lambda bundle: True, SOHInteriorExitNames.MARKET_MAN_IN_GREEN_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/temple_of_time.py b/worlds/oot_soh/location_access/overworld/temple_of_time.py index c3eee32e28da..486b8e04043a 100644 --- a/worlds/oot_soh/location_access/overworld/temple_of_time.py +++ b/worlds/oot_soh/location_access/overworld/temple_of_time.py @@ -38,7 +38,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.TOT_ENTRANCE, world, [ (Regions.MARKET, lambda bundle: True), - (Regions.TEMPLE_OF_TIME, lambda bundle: True) + (Regions.TEMPLE_OF_TIME, lambda bundle: True, SOHSpecialInteriorEntranceNames.TEMPLE_OF_TIME_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Temple of Time @@ -49,7 +49,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.TEMPLE_OF_TIME, world, [ - (Regions.TOT_ENTRANCE, lambda bundle: True), + (Regions.TOT_ENTRANCE, lambda bundle: True, SOHSpecialInteriorExitNames.TEMPLE_OF_TIME_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.BOTH_AGE), (Regions.BEYOND_DOOR_OF_TIME, lambda bundle: world.options.door_of_time == "open" or (can_use(Items.SONG_OF_TIME, bundle) and diff --git a/worlds/oot_soh/location_access/overworld/zoras_domain.py b/worlds/oot_soh/location_access/overworld/zoras_domain.py index 55fd6bbf8eaf..85f084819337 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_domain.py +++ b/worlds/oot_soh/location_access/overworld/zoras_domain.py @@ -89,7 +89,7 @@ def set_region_rules(world: "SohWorld") -> None: lambda bundle: has_item(Events.DELIVER_LETTER, bundle) or world.options.zoras_fountain.value == 2 or ( world.options.zoras_fountain.value == 1 and is_adult(bundle)) or ( can_do_trick(Tricks.ZD_KING_ZORA_SKIP, bundle) and is_adult(bundle))), - (Regions.ZD_SHOP, lambda bundle: is_child(bundle) or blue_fire(bundle)), + (Regions.ZD_SHOP, lambda bundle: is_child(bundle) or blue_fire(bundle), SOHInteriorEntranceNames.ZD_SHOP_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.ZORAS_DOMAIN_ISLAND, lambda bundle: True), ]) @@ -134,7 +134,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZD_SHOP, world, [ - (Regions.ZORAS_DOMAIN, lambda bundle: True), + (Regions.ZORAS_DOMAIN, lambda bundle: True, SOHInteriorExitNames.ZD_SHOP_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), ]) # ZD Storms Grotto diff --git a/worlds/oot_soh/location_access/overworld/zoras_fountain.py b/worlds/oot_soh/location_access/overworld/zoras_fountain.py index 7c7cda0a6cf9..1b687b84ae30 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_fountain.py +++ b/worlds/oot_soh/location_access/overworld/zoras_fountain.py @@ -55,7 +55,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.JABU_JABUS_BELLY_ENTRYWAY, lambda bundle: is_child(bundle) and (can_use(Items.BOTTLE_WITH_FISH, bundle) or world.options.jabu_jabu.value == 1), SOHDungeonEntranceNames.JABU_JABUS_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.CHILD_ONLY, EntranceType.TWO_WAY), (Regions.ZF_GREAT_FAIRY_FOUNTAIN, lambda bundle: has_explosives(bundle) or (can_do_trick( - Tricks.ZF_GREAT_FAIRY_WITHOUT_EXPLOSIVES, bundle) and can_use(Items.MEGATON_HAMMER, bundle) and can_use(Items.SILVER_GAUNTLETS, bundle))) + Tricks.ZF_GREAT_FAIRY_WITHOUT_EXPLOSIVES, bundle) and can_use(Items.MEGATON_HAMMER, bundle) and can_use(Items.SILVER_GAUNTLETS, bundle)), SOHInteriorEntranceNames.ZF_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) # Zora's Fountains Icebergs @@ -170,5 +170,5 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZF_GREAT_FAIRY_FOUNTAIN, world, [ - (Regions.ZORAS_FOUNTAIN, lambda bundle: True) + (Regions.ZORAS_FOUNTAIN, lambda bundle: True, SOHInteriorExitNames.ZF_GREAT_FAIRY_FOUNTAIN_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) From 0f043842dc1a4b7dcb3e7d731c5a235d7d2865e8 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Tue, 25 Nov 2025 16:57:03 -0500 Subject: [PATCH 18/22] More interior changes. At the point where the entrance from dampes grave to windmill is a problem. Sometimes the GER will force two "exits" together that don't lead to anywhere else. --- worlds/oot_soh/EntranceShuffle.py | 9 +++++---- worlds/oot_soh/Enums.py | 2 +- worlds/oot_soh/__init__.py | 1 - worlds/oot_soh/location_access/overworld/graveyard.py | 2 +- worlds/oot_soh/location_access/overworld/kakariko.py | 2 +- .../oot_soh/location_access/overworld/kokiri_forest.py | 2 +- .../oot_soh/location_access/overworld/lon_lon_ranch.py | 4 ++-- worlds/oot_soh/location_access/overworld/market.py | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 5de068169bc3..8c36f309454f 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -20,7 +20,7 @@ SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.FIRE_TEMPLE_BOSS_EXIT, SOHBossEntranceNames.WATER_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.WATER_TEMPLE_BOSS_EXIT, SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SHADOW_TEMPLE_BOSS_EXIT, - SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SPIRIT_TEMPLE_BOSS_EXIT, + SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SPIRIT_TEMPLE_BOSS_EXIT } @@ -39,7 +39,7 @@ # This is allowing us to brute force the problem of GER failing. May be a necessary evil as it doesn't do swap or automatic retries itself. -OOT_SOH_GER_RETRIES_AMOUNT: int = 1000 +OOT_SOH_GER_RETRIES_AMOUNT: int = 50 def get_target_groups(group: int) -> list[int]: type = group & SOHEntranceGroups.TYPE_MASK @@ -192,7 +192,7 @@ def soh_one_way_entrance_connections(world: "SohWorld", entrance_names: list, ex # Might need to return the ER Placement state at the end -def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None, coupled: bool = True, ageRestricted: bool = False) -> None: +def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames | SOHInteriorEntranceNames | SOHInteriorExitNames | SOHSpecialInteriorEntranceNames | SOHSpecialInteriorExitNames], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None, coupled: bool = True, ageRestricted: bool = False) -> None: for entranceEnum in entrances_to_shuffle: disconnect_entrance_for_randomization(world.multiworld.get_entrance( entranceEnum.value, world.player), one_way_target_name=entrance_matching[entranceEnum].value if entranceEnum in entrance_matching else None) @@ -209,7 +209,8 @@ def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBoss try: er_state = randomize_entrances(world, coupled, target_group_lookup, False, on_connect=on_connect) world.er_pairings += er_state.pairings - print(f"Took {i} attempts to get GER working.") + # print(world.er_pairings) + # print(f"Took {i} attempts to get GER working.") break except EntranceRandomizationError as error: if i >= OOT_SOH_GER_RETRIES_AMOUNT - 1: diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index 18ad0796f1d2..fe4f89172f77 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -4119,7 +4119,7 @@ class SOHSpecialInteriorExitNames(StrEnum): KAK_POTION_SHOP_FRONT_EXIT = "Kak Potion Shop Front Exit" KAK_POTION_SHOP_BACK_EXIT = "Kak Potion Shop Back Exit" - + class TokenCounts(IntEnum): DUNGEON = 44 OVERWORLD = 56 diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index 8059b332bf24..d644963b586d 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -20,7 +20,6 @@ from Options import OptionError from .LogicHelpers import wallet_capacities from .EntranceShuffle import randomize_entrances_soh, on_connect_soh, randomize_soh_one_way_entrances -from entrance_rando import bake_target_group_lookup import logging logger = logging.getLogger("SOH_OOT") diff --git a/worlds/oot_soh/location_access/overworld/graveyard.py b/worlds/oot_soh/location_access/overworld/graveyard.py index 6b90806af4c2..cb8562e97d21 100644 --- a/worlds/oot_soh/location_access/overworld/graveyard.py +++ b/worlds/oot_soh/location_access/overworld/graveyard.py @@ -74,7 +74,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GRAVEYARD_COMPOSERS_GRAVE, lambda bundle: can_use(Items.ZELDAS_LULLABY, bundle), SOHGrottoEntranceNames.GRAVEYARD_COMPOSERS_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.GRAVEYARD_HEART_PIECE_GRAVE, - lambda bundle: is_adult(bundle) or at_night(bundle), SOHGrottoEntranceNames.GRAVEYARD_HEART_PIECE_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), + lambda bundle: is_adult(bundle) or at_night(bundle), SOHGrottoEntranceNames.GRAVEYARD_HEART_PIECE_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GRAVEYARD_DAMPES_GRAVE, lambda bundle: is_adult(bundle), SOHGrottoEntranceNames.GRAVEYARD_DAMPES_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GRAVEYARD_DAMPES_HOUSE, lambda bundle: is_adult(bundle) and can_open_overworld_door(Items.DAMPES_HUT_KEY, bundle), SOHInteriorEntranceNames.GRAVEYARD_DAMPES_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), diff --git a/worlds/oot_soh/location_access/overworld/kakariko.py b/worlds/oot_soh/location_access/overworld/kakariko.py index f8cca3256b55..81ba0bd8505a 100644 --- a/worlds/oot_soh/location_access/overworld/kakariko.py +++ b/worlds/oot_soh/location_access/overworld/kakariko.py @@ -346,7 +346,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_POTION_SHOP_FRONT, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHSpecialInteriorExitNames.KAK_POTION_SHOP_FRONT_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHSpecialInteriorExitNames.KAK_POTION_SHOP_FRONT_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT), (Regions.KAK_POTION_SHOP_BACK, lambda bundle: is_adult(bundle)), ]) diff --git a/worlds/oot_soh/location_access/overworld/kokiri_forest.py b/worlds/oot_soh/location_access/overworld/kokiri_forest.py index fd0c07a3b393..772172dc4e11 100644 --- a/worlds/oot_soh/location_access/overworld/kokiri_forest.py +++ b/worlds/oot_soh/location_access/overworld/kokiri_forest.py @@ -230,7 +230,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KF_LINKS_HOUSE, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True, SOHSpecialInteriorExitNames.KF_LINKS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHSpecialInteriorExitNames.KF_LINKS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.BOTH_AGE) ]) # KF Mido's House diff --git a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py index 797f48b18fce..a059f0374cae 100644 --- a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py +++ b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py @@ -72,7 +72,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LLR_TALONS_HOUSE, world, [ - (Regions.LON_LON_RANCH, lambda bundle: True, SOHInteriorExitNames.LLR_TALONS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) + (Regions.LON_LON_RANCH, lambda bundle: True, SOHInteriorExitNames.LLR_TALONS_HOUSE_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD) ]) # LLR Stables @@ -99,7 +99,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LLR_TOWER, world, [ - (Regions.LON_LON_RANCH, lambda bundle: True, SOHInteriorExitNames.LLR_TOWER_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY) + (Regions.LON_LON_RANCH, lambda bundle: True, SOHInteriorExitNames.LLR_TOWER_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD) ]) # LLR Grotto diff --git a/worlds/oot_soh/location_access/overworld/market.py b/worlds/oot_soh/location_access/overworld/market.py index fea70f06d0d3..e74ca0f725a6 100644 --- a/worlds/oot_soh/location_access/overworld/market.py +++ b/worlds/oot_soh/location_access/overworld/market.py @@ -268,7 +268,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET_SHOOTING_GALLERY, world, [ - (Regions.MARKET, lambda bundle: True, SOHInteriorExitNames.MARKET_SHOOTING_GALLERY_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY) + (Regions.MARKET, lambda bundle: True, SOHInteriorExitNames.MARKET_SHOOTING_GALLERY_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD) ]) # Market Bombchu Bowling From e725682ab175e380f3510da21f5c0ef4f711f9de Mon Sep 17 00:00:00 2001 From: mattman107 Date: Tue, 25 Nov 2025 18:03:05 -0500 Subject: [PATCH 19/22] Fix some misc issues with interior entrances. Still hit or miss on a solo rando, but multiworld allows it to work way better. --- worlds/oot_soh/EntranceShuffle.py | 2 +- worlds/oot_soh/__init__.py | 4 ++++ worlds/oot_soh/location_access/overworld/graveyard.py | 10 ++++++++-- worlds/oot_soh/location_access/overworld/kakariko.py | 2 +- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 8c36f309454f..a35a9ec6249a 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -39,7 +39,7 @@ # This is allowing us to brute force the problem of GER failing. May be a necessary evil as it doesn't do swap or automatic retries itself. -OOT_SOH_GER_RETRIES_AMOUNT: int = 50 +OOT_SOH_GER_RETRIES_AMOUNT: int = 10 def get_target_groups(group: int) -> list[int]: type = group & SOHEntranceGroups.TYPE_MASK diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index d644963b586d..de9946c98cc4 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -20,6 +20,7 @@ from Options import OptionError from .LogicHelpers import wallet_capacities from .EntranceShuffle import randomize_entrances_soh, on_connect_soh, randomize_soh_one_way_entrances +from .location_access.overworld.graveyard import connect_dampes_grave_windmill import logging logger = logging.getLogger("SOH_OOT") @@ -290,6 +291,9 @@ def connect_entrances(self): randomize_entrances_soh( self, entrances_to_shuffle, on_connect_soh, coupled) + # Connect Dampes After randomization so GER doesn't get any funny ideas + connect_dampes_grave_windmill(self) + return super().connect_entrances() def collect(self, state: CollectionState, item: Item) -> bool: diff --git a/worlds/oot_soh/location_access/overworld/graveyard.py b/worlds/oot_soh/location_access/overworld/graveyard.py index cb8562e97d21..4ade497ab4bb 100644 --- a/worlds/oot_soh/location_access/overworld/graveyard.py +++ b/worlds/oot_soh/location_access/overworld/graveyard.py @@ -174,8 +174,9 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.GRAVEYARD_DAMPES_GRAVE, world, [ (Regions.THE_GRAVEYARD, lambda bundle: True, SOHGrottoExitNames.GRAVEYARD_DAMPES_GRAVE_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT), - (Regions.KAK_WINDMILL, lambda bundle: (is_adult(bundle) and can_use( - Items.SONG_OF_TIME, bundle)) or (is_child(bundle) and can_ground_jump(bundle))) + # Doing this connection in __init__ connect_entrances for ER reasons + # (Regions.KAK_WINDMILL, lambda bundle: (is_adult(bundle) and can_use( + # Items.SONG_OF_TIME, bundle)) or (is_child(bundle) and can_ground_jump(bundle))) ]) # The Graveyard Dampes House @@ -203,3 +204,8 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.SHADOW_TEMPLE_ENTRYWAY, lambda bundle: can_use(Items.DINS_FIRE, bundle) or (can_do_trick(Tricks.GY_SHADOW_FIRE_ARROWS, bundle) and is_adult( bundle) and can_use(Items.FIRE_ARROW, bundle)), SOHDungeonEntranceNames.SHADOW_TEMPLE_DUNGEON_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY) ]) + +def connect_dampes_grave_windmill(world: "SohWorld"): + connect_regions(Regions.GRAVEYARD_DAMPES_GRAVE, world, [ + (Regions.KAK_WINDMILL, lambda bundle: (is_adult(bundle) and can_use(Items.SONG_OF_TIME, bundle)) or (is_child(bundle) and can_ground_jump(bundle))) + ]) \ No newline at end of file diff --git a/worlds/oot_soh/location_access/overworld/kakariko.py b/worlds/oot_soh/location_access/overworld/kakariko.py index 81ba0bd8505a..b6e70d33aab4 100644 --- a/worlds/oot_soh/location_access/overworld/kakariko.py +++ b/worlds/oot_soh/location_access/overworld/kakariko.py @@ -346,7 +346,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAK_POTION_SHOP_FRONT, world, [ - (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHSpecialInteriorExitNames.KAK_POTION_SHOP_FRONT_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHSpecialInteriorExitNames.KAK_POTION_SHOP_FRONT_EXIT, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.KAK_POTION_SHOP_BACK, lambda bundle: is_adult(bundle)), ]) From 7cc3a59ae2020e4d616c7c0fdb77b88156d91d7a Mon Sep 17 00:00:00 2001 From: mattman107 Date: Tue, 25 Nov 2025 23:24:27 -0500 Subject: [PATCH 20/22] Thieves Hideout entrances --- worlds/oot_soh/EntranceShuffle.py | 14 +-- worlds/oot_soh/Enums.py | 93 ++++++++++++++++++- worlds/oot_soh/Options.py | 24 ++++- worlds/oot_soh/__init__.py | 15 ++- .../overworld/gerudo_fortress.py | 25 ++--- .../overworld/thieves_hideout.py | 27 +++--- 6 files changed, 161 insertions(+), 37 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index a35a9ec6249a..0f936addb8c5 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -1,6 +1,6 @@ from typing import TYPE_CHECKING, Callable from BaseClasses import Location, Region, Entrance -from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups, Regions, SOHBossWarpEntranceNames, SOHGrottoEntranceNames, SOHGrottoExitNames, SOHInteriorEntranceNames, SOHInteriorExitNames, SOHSpecialInteriorEntranceNames, SOHSpecialInteriorExitNames +from .Enums import SOHBossEntranceExitNames, SOHBossEntranceNames, SOHDungeonExitNames, SOHDungeonEntranceNames, Locations, SOHEntranceGroups, Regions, SOHBossWarpEntranceNames, SOHGrottoEntranceNames, SOHGrottoExitNames, SOHInteriorEntranceNames, SOHInteriorExitNames, SOHSpecialInteriorEntranceNames, SOHSpecialInteriorExitNames, SOHThievesHideoutEntranceNames, SOHOverworldEntranceNames from .Locations import SohLocation from entrance_rando import disconnect_entrance_for_randomization, randomize_entrances, bake_target_group_lookup, EntranceRandomizationError from entrance_rando import ERPlacementState, Entrance @@ -29,13 +29,15 @@ SOHEntranceGroups.BOSS_ENTRANCE: [SOHEntranceGroups.BOSS_ENTRANCE], SOHEntranceGroups.GROTTO: [SOHEntranceGroups.GROTTO], SOHEntranceGroups.INTERIOR: [SOHEntranceGroups.INTERIOR], + SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE: [SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE], + SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE: [SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE] } -mixed_group_lookup = {group: [all for all in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, - SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO)] - for group in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, - SOHEntranceGroups.THEIVES_HIDEOUT_ENTRANCE, SOHEntranceGroups.GROTTO)} +mixed_group_lookup = {group: [all for all in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, + SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, SOHEntranceGroups.GROTTO)] + for group in (SOHEntranceGroups.OTHER, SOHEntranceGroups.BOSS_ENTRANCE, SOHEntranceGroups.DUNGEON_ENTRANCE, + SOHEntranceGroups.OVERWORLD, SOHEntranceGroups.INTERIOR, SOHEntranceGroups.GROTTO)} # This is allowing us to brute force the problem of GER failing. May be a necessary evil as it doesn't do swap or automatic retries itself. @@ -192,7 +194,7 @@ def soh_one_way_entrance_connections(world: "SohWorld", entrance_names: list, ex # Might need to return the ER Placement state at the end -def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames | SOHInteriorEntranceNames | SOHInteriorExitNames | SOHSpecialInteriorEntranceNames | SOHSpecialInteriorExitNames], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None, coupled: bool = True, ageRestricted: bool = False) -> None: +def randomize_entrances_soh(world: "SohWorld", entrances_to_shuffle: set[SOHBossEntranceNames | SOHDungeonEntranceNames | SOHDungeonExitNames | SOHInteriorEntranceNames | SOHInteriorExitNames | SOHSpecialInteriorEntranceNames | SOHSpecialInteriorExitNames | SOHThievesHideoutEntranceNames], on_connect: Callable[[ERPlacementState, list[Entrance], list[Entrance]], bool | None] | None = None, coupled: bool = True, ageRestricted: bool = False) -> None: for entranceEnum in entrances_to_shuffle: disconnect_entrance_for_randomization(world.multiworld.get_entrance( entranceEnum.value, world.player), one_way_target_name=entrance_matching[entranceEnum].value if entranceEnum in entrance_matching else None) diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index fe4f89172f77..56c07c38c1d9 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -3855,10 +3855,11 @@ class SOHEntranceGroups(IntEnum): BOSS_ENTRANCE = 2 OVERWORLD = 3 INTERIOR = 4 - THEIVES_HIDEOUT_ENTRANCE = 5 - GROTTO = 6 - OWL_DROP = 7 - WARP_SONG = 8 + THIEVES_HIDEOUT_ENTRANCE = 5 + GERUDO_FORTRESS_ENTRANCE = 6 + GROTTO = 7 + OWL_DROP = 8 + WARP_SONG = 9 # Age Accessible ANY_AGE = 1 << 4 CHILD = 2 << 4 @@ -4120,6 +4121,90 @@ class SOHSpecialInteriorExitNames(StrEnum): KAK_POTION_SHOP_BACK_EXIT = "Kak Potion Shop Back Exit" +class SOHOverworldEntranceNames(StrEnum): + LOST_WOODS_BRIDGE_EAST_EXIT = "Lost Woods Bridge East Exit" + KOKIRI_FOREST_LOWER_EXIT = "Kokiri Forest Lower Exit" + LOST_WOODS_SOUTH_EXIT = "Lost Woods South Exit" + KOKIRI_FOREST_UPPER_EXIT = "Kokiri Forest Upper Exit" + GORON_CITY_TUNNEL_SHORTCUT = "Goron City Tunnel Shortcut" + LOST_WOODS_TUNNEL_SHORTCUT = "Lost Woods Tunnel Shortcut" + ZORAS_RIVER_UNDERWATER_SHORTCUT = "Zoras River Underwater Shortcut" + LOST_WOODS_UNDERWATER_SHORTCUT = "Lost Woods Underwater Shortcut" + SACRED_FOREST_MEADOW_SOUTH_EXIT = "Sacred Forst Meadow South Exit" + LOST_WOODS_NORTH_EXIT = "Lost Woods North Exit" + HYRULE_FIELD_WOODED_EXIT = "Hyrule Field Wooded Exit" + LOST_WOODS_BRIDGE_WEST_EXIT = "Lost Woods Bridge West Exit" + LAKE_HYLIA_NORTH_EXIT = "Lake Hylia North Exit" + HYRULE_FIELD_FENCE_EXIT = "Hyrule Field Fence Exit" + GERUDO_VALLEY_EAST_EXIT = "Gerudo Valley East Exit" + HYRULE_FIELD_ROCKY_PATH = "Hyrule Field Rocky Path" + MARKET_ENTRANCE_NEAR_GUARD_EXIT = "Market Entrance Near Guard Exit" + HYRULE_FIELD_ON_BRIDGE_SPAWN = "Hyrule Field On Bridge Spawn" + KAKARIKO_VILLAGE_FRONT_GATE = "Kakariko Village Front Gate" + HYRULE_FIELD_STAIRS_EXIT = "Hyrule Field Stairs Exit" + ZORAS_RIVER_WEST_EXIT = "Zoras River West Exit" + HYRULE_FIELD_RIVER_EXIT = "Hyrule Field River Exit" + LON_LON_RANCH_ENTRANCE = "Lon Lon Ranch Entrance" + HYRULE_FIELD_CENTER_EXIT = "Hyrule Field Center Exit" + ZORAS_DOMAIN_UNDERWATER_SHORTCUT = "Zoras Domain Underwater Shortcut" + LAKE_HYLIA_UNDERWATER_SHORTCUT = "Lakey Hylia Underwater Shortcut" + GERUDOS_FORTRESS_EAST_EXIT = "Gerudos Fortress East Exit" + GERUDO_VALLEY_WEST_EXIT = "Gerudo Valley West Exit" + HAUNTED_WASTELAND_EAST_EXIT = "Haunted Wasteland East Exit" + GERUDOS_FORTRESS_GATE_EXIT = "Gerudos Fortress Gate Exit" + DESERT_COLOSSUS_EAST_EXIT = "Desert Colossus East Exit" + HAUNTED_WASTELAND_WEST_EXIT = "Haunted Wasteland West Exit" + MARKET_SOUTH_EXIT = "Market South Exit" + MARKET_ENTRANCE_NORTH_EXIT = "Market Entrance North Exit" + CASTLE_GROUNDS_SOUTH_EXIT = "Castle Grounds South Exit" + MARKET_DAY_CASTLE_EXIT = "Market Day Castle Exit" + TEMPLE_OF_TIME_EXTERIOR_DAY_GOSSIP_STONE_EXIT = "Temple of Time Exterior Day Gossip Stone Exit" + MARKET_DAY_TEMPLE_EXIT = "Market Day Temple Exit" + GRAVEYARD_ENTRANCE = "Graveyard Entrance" + KAKARIKO_VILLAGE_SOUTHEAST_EXIT = "Kakariko Village Southeast Exit" + DEATH_MOUNTAIN_TRAIL_BOTTOM_EXIT = "Death Mountain Trail Bottom Exit" + KAKARIKO_VILLAGE_GUARD_GATE = "Kakariko Village Guard Gate" + GORON_CITY_UPPER_EXIT = "Goron City Upper Exit" + DEATH_MOUNTAIN_TRAIL_GC_EXIT = "Death Mountain Trail GC Exit" + DEATH_MOUNTAIN_CRATER_GC_EXIT = "Death Mountain Crater GC Exit" + GORON_CITY_DARUNIA_ROOM_EXIT = "Goron City Darunia Room Exit" + DEATH_MOUNTAIN_CRATER_UPPER_EXIT = "Death Mountain Crater Upper Exit" + DEATH_MOUNTAIN_TRAIL_SUMMIT_EXIT = "Death Mountain Trail Summit Exit" + ZORAS_DOMAIN_ENTRANCE = "Zoras Domain Entrance" + ZORAS_RIVER_WATERFALL_EXIT = "Zoras River Waterfall Exit" + ZORAS_FOUNTAIN_TUNNEL_EXIT = "Zoras Fountain Tunnel Exit" + ZORAS_DOMAIN_KING_ZORA_EXIT = "Zoras Domain King Zora Exit" + + +class SOHThievesHideoutEntranceNames(StrEnum): + THIEVES_HIDEOUT_0 = "Thieves Hideout 0" + GERUDOS_FORTRESS_1 = "Gerudos Fortress 1" + THIEVES_HIDEOUT_1 = "Thieves Hideout 1" + GERUDOS_FORTRESS_2 = "Gerudos Fortress 2" + THIEVES_HIDEOUT_2 = "Thieves Hideout 2" + GERUDOS_FORTRESS_3 = "Gerudos Fortress 3" + THIEVES_HIDEOUT_3 = "Thieves Hideout 3" + GERUDOS_FORTRESS_4 = "Gerudos Fortress 4" + THIEVES_HIDEOUT_4 = "Thieves Hideout 4" + GERUDOS_FORTRESS_5 = "Gerudos Fortress 5" + THIEVES_HIDEOUT_5 = "Thieves Hideout 5" + GERUDOS_FORTRESS_6 = "Gerudos Fortress 6" + THIEVES_HIDEOUT_6 = "Thieves Hideout 6" + GERUDOS_FORTRESS_7 = "Gerudos Fortress 7" + THIEVES_HIDEOUT_7 = "Thieves Hideout 7" + GERUDOS_FORTRESS_8 = "Gerudos Fortress 8" + THIEVES_HIDEOUT_8 = "Thieves Hideout 8" + GERUDOS_FORTRESS_9 = "Gerudos Fortress 9" + THIEVES_HIDEOUT_9 = "Thieves Hideout 9" + GERUDOS_FORTRESS_10 = "Gerudos Fortress 10" + THIEVES_HIDEOUT_10 = "Thieves Hideout 10" + GERUDOS_FORTRESS_11 = "Gerudos Fortress 11" + THIEVES_HIDEOUT_11 = "Thieves Hideout 11" + GERUDOS_FORTRESS_12 = "Gerudos Fortress 12" + THIEVES_HIDEOUT_12 = "Thieves Hideout 12" + GERUDOS_FORTRESS_13 = "Gerudos Fortress 13" + + class TokenCounts(IntEnum): DUNGEON = 44 OVERWORLD = 56 diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index 4aad72e3847f..81359f47892d 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -901,6 +901,18 @@ class ShuffleDungeonBossEntrances(Choice): default = 0 +class ShuffleOverworldEntrances(Toggle): + """ + Shuffle the pool of Overworld Entrances, which corresponds to almost all loading zones between overworld areas. + + Some Entrances are unshuffled to avoid issues: + - Hyrule Castle Courtyard and Garden Entrance + - Both Market and Back Alley Entrances + - Gerudo Valley to Lake Hylia (unless entrances are decoupled) + """ + display_name = "Shuffle Overworld Entrances" + + class ShuffleDungeonEntrances(Choice): """ Shuffle the pool of dungeon entrances, including Bottom of the Well, Ice Cavern and Gerudo Training Ground. @@ -918,6 +930,13 @@ class ShuffleDungeonEntrances(Choice): default = 0 +class ShuffleTheivesHideoutEntrances(Toggle): + """ + Shuffle the pool of entrances between Gerudo Fortress & Theives' Hideout + """ + display_name = "Shuffle Theives' Hideout Entrances" + + class ShuffleGrottoEntrances(Toggle): """ Shuffle the pool of grotto entrances, including all graves, small Fairy fountains and Deku Theatre. @@ -1070,6 +1089,8 @@ class SohOptions(PerGameCommonOptions): enable_all_tricks: EnableAllTricks shuffle_dungeon_entrances: ShuffleDungeonEntrances shuffle_boss_entrances: ShuffleDungeonBossEntrances + shuffle_overworld_entances: ShuffleOverworldEntrances + shuffle_theives_hideout_entrances: ShuffleTheivesHideoutEntrances shuffle_grotto_entrances: ShuffleGrottoEntrances shuffle_warp_song_entrances: ShuffleWarpSongEntrances shuffle_owl_drop_entrances: ShuffleOwlDropEntrances @@ -1109,14 +1130,15 @@ class SohOptions(PerGameCommonOptions): OptionGroup("Shuffle Entrances", [ ShuffleDungeonEntrances, ShuffleDungeonBossEntrances, + ShuffleOverworldEntrances, ShuffleInteriorEntrances, + ShuffleTheivesHideoutEntrances, ShuffleGrottoEntrances, ShuffleWarpSongEntrances, ShuffleOwlDropEntrances, ShuffleOverworldSpawns, DecoupleEntrances, MixedEntrancePools - # Overworld Entrances ]), OptionGroup("Shuffle Items", [ # Shuffle Songs -- idk if this or the other ones here will be an actual option here, delete if not diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index de9946c98cc4..35db1d0fafa9 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -3,7 +3,7 @@ from typing import Any, List, ClassVar -from BaseClasses import CollectionState, Item, Tutorial, ItemClassification +from BaseClasses import CollectionState, Item, Tutorial, ItemClassification, Entrance from worlds.AutoWorld import WebWorld, World from .Items import SohItem, item_data_table, item_table, item_name_groups, progressive_items from .Locations import location_table, location_name_groups, token_amounts @@ -241,6 +241,19 @@ def connect_entrances(self): # Update this when it is figured out why decoupled doesn't work with the current groupings coupled = True #(not self.options.decouple_entrances) + if self.options.shuffle_theives_hideout_entrances: + # Make Temp Entrance to GF_ABOVE_JAIL to appease GER + temp_entrance: Entrance = self.get_region(Regions.ROOT.value).connect(self.get_region(Regions.GF_ABOVE_JAIL.value), "Temp GF_ABOVE_JAIL Entrance", None) + + for entranceName in SOHThievesHideoutEntranceNames: + entrances_to_shuffle.add(entranceName) + randomize_entrances_soh(self, entrances_to_shuffle) + entrances_to_shuffle.clear() + + # Clean up Temp Entrance + temp_entrance.connected_region.entrances.remove(temp_entrance) + temp_entrance.connected_region = None + # Boss Entrances if self.options.shuffle_boss_entrances: for entranceName in SOHBossEntranceNames: diff --git a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py index d560bd54e7f1..0d21edf1be42 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py @@ -34,7 +34,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.GERUDO_FORTRESS_OUTSKIRTS, world, [ (Regions.GV_FORTRESS_SIDE, lambda bundle: True), - (Regions.THIEVES_HIDEOUT_1_TORCH_CELL, lambda bundle: True), + (Regions.THIEVES_HIDEOUT_1_TORCH_CELL, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_0, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GF_OUTSIDE_GATE, lambda bundle: has_item( LocalEvents.GF_GATE_OPEN, bundle)), (Regions.GF_NEAR_GROTTO, lambda bundle: is_child(bundle) @@ -58,9 +58,9 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GF_NEAR_GROTTO, world, [ - (Regions.THIEVES_HIDEOUT_1_TORCH_CELL, lambda bundle: True), - (Regions.THIEVES_HIDEOUT_STEEP_SLOPE_CELL, lambda bundle: True), - (Regions.THIEVES_HIDEOUT_KITCHEN_CORRIDOR, lambda bundle: True), + (Regions.THIEVES_HIDEOUT_1_TORCH_CELL, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_1, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), + (Regions.THIEVES_HIDEOUT_STEEP_SLOPE_CELL, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_4, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), + (Regions.THIEVES_HIDEOUT_KITCHEN_CORRIDOR, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_2, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True), (Regions.GF_JAIL_WINDOW, lambda bundle: can_use(Items.HOOKSHOT, bundle)), (Regions.GF_OUTSIDE_GTG, lambda bundle: is_child(bundle) @@ -117,8 +117,8 @@ def set_region_rules(world: "SohWorld") -> None: # GF Above GTG # Connections connect_regions(Regions.GF_ABOVE_GTG, world, [ - (Regions.THIEVES_HIDEOUT_DOUBLE_CELL, lambda bundle: True), - (Regions.THIEVES_HIDEOUT_KITCHEN_CORRIDOR, lambda bundle: True), + (Regions.THIEVES_HIDEOUT_DOUBLE_CELL, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_6, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), + (Regions.THIEVES_HIDEOUT_KITCHEN_CORRIDOR, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_3, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GF_JAIL_WINDOW, lambda bundle: can_use(Items.HOOKSHOT, bundle)), (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True), (Regions.GF_NEAR_GROTTO, lambda bundle: True), @@ -131,7 +131,7 @@ def set_region_rules(world: "SohWorld") -> None: # GF Bottom of Lower Vines # Connections connect_regions(Regions.GF_BOTTOM_OF_LOWER_VINES, world, [ - (Regions.THIEVES_HIDEOUT_STEEP_SLOPE_CELL, lambda bundle: True), + (Regions.THIEVES_HIDEOUT_STEEP_SLOPE_CELL, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_5, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GF_NEAR_GROTTO, lambda bundle: True), (Regions.GF_TOP_OF_LOWER_VINES, lambda bundle: True), (Regions.GF_ABOVE_GTG, lambda bundle: True), @@ -142,8 +142,8 @@ def set_region_rules(world: "SohWorld") -> None: # GF Top of Lower Vines # Connections connect_regions(Regions.GF_TOP_OF_LOWER_VINES, world, [ - (Regions.THIEVES_HIDEOUT_KITCHEN_TOP, lambda bundle: True), - (Regions.THIEVES_HIDEOUT_DOUBLE_CELL, lambda bundle: True), + (Regions.THIEVES_HIDEOUT_KITCHEN_TOP, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_8, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), + (Regions.THIEVES_HIDEOUT_DOUBLE_CELL, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_7, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GF_ABOVE_GTG, lambda bundle: True), (Regions.GF_BOTTOM_OF_LOWER_VINES, lambda bundle: True), (Regions.GF_BOTTOM_OF_UPPER_VINES, lambda bundle: is_adult( @@ -153,7 +153,7 @@ def set_region_rules(world: "SohWorld") -> None: # GF Near GS # Connections connect_regions(Regions.GF_NEAR_GS, world, [ - (Regions.THIEVES_HIDEOUT_KITCHEN_TOP, lambda bundle: True), + (Regions.THIEVES_HIDEOUT_KITCHEN_TOP, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_9, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GF_BOTTOM_OF_LOWER_VINES, lambda bundle: True), (Regions.GF_TOP_OF_LOWER_VINES, lambda bundle: True), (Regions.GF_SLOPED_ROOF, lambda bundle: is_adult( @@ -243,7 +243,7 @@ def set_region_rules(world: "SohWorld") -> None: # GF Below GS # Connections connect_regions(Regions.GF_BELOW_GS, world, [ - (Regions.THIEVES_HIDEOUT_DEAD_END_CELL, lambda bundle: True), + (Regions.THIEVES_HIDEOUT_DEAD_END_CELL, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_12, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GF_BOTTOM_OF_LOWER_VINES, lambda bundle: True), (Regions.GF_GS_KILL_ZONE, lambda bundle: is_adult(bundle) and can_get_enemy_drop(bundle, Enemies.GOLD_SKULLTULA, @@ -254,7 +254,7 @@ def set_region_rules(world: "SohWorld") -> None: # GF Below Chest # Connections connect_regions(Regions.GF_BELOW_CHEST, world, [ - (Regions.THIEVES_HIDEOUT_BREAK_ROOM, lambda bundle: True), + (Regions.THIEVES_HIDEOUT_BREAK_ROOM, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_10, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True), ]) @@ -270,6 +270,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GF_NEAR_CHEST, lambda bundle: can_use(Items.LONGSHOT, bundle)), (Regions.GF_BELOW_CHEST, lambda bundle: take_damage(bundle)), (Regions.GF_JAIL_WINDOW, lambda bundle: can_use(Items.HOOKSHOT, bundle)), + (Regions.THIEVES_HIDEOUT_BREAK_ROOM_CORRIDOR, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_11, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)) ]) # GF Jail Window diff --git a/worlds/oot_soh/location_access/overworld/thieves_hideout.py b/worlds/oot_soh/location_access/overworld/thieves_hideout.py index b4ce44e58ce7..1660b0c6a44e 100644 --- a/worlds/oot_soh/location_access/overworld/thieves_hideout.py +++ b/worlds/oot_soh/location_access/overworld/thieves_hideout.py @@ -39,8 +39,8 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.THIEVES_HIDEOUT_1_TORCH_CELL, world, [ - (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True), - (Regions.GF_NEAR_GROTTO, lambda bundle: True), + (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_1, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), + (Regions.GF_NEAR_GROTTO, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_2, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), (Regions.THIEVES_HIDEOUT_RESCUE_CARPENTERS, lambda bundle: True) ]) @@ -72,8 +72,9 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.THIEVES_HIDEOUT_DOUBLE_CELL, world, [ - (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True), - (Regions.GF_NEAR_GROTTO, lambda bundle: True), + (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_7, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), + (Regions.GF_ABOVE_GTG, lambda bundle: True), + (Regions.GF_TOP_OF_LOWER_VINES, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_8, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), (Regions.THIEVES_HIDEOUT_RESCUE_CARPENTERS, lambda bundle: True) ]) @@ -92,7 +93,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.THIEVES_HIDEOUT_DEAD_END_CELL, world, [ - (Regions.GF_BELOW_GS, lambda bundle: True), + (Regions.GF_BELOW_GS, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_13, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), (Regions.THIEVES_HIDEOUT_RESCUE_CARPENTERS, lambda bundle: True) ]) @@ -112,8 +113,8 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.THIEVES_HIDEOUT_STEEP_SLOPE_CELL, world, [ - (Regions.GF_ABOVE_GTG, lambda bundle: True), - (Regions.GF_TOP_OF_LOWER_VINES, lambda bundle: True), + (Regions.GF_ABOVE_GTG, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_5, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), + (Regions.GF_TOP_OF_LOWER_VINES, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_6, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), (Regions.THIEVES_HIDEOUT_RESCUE_CARPENTERS, lambda bundle: True) ]) @@ -153,8 +154,8 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.THIEVES_HIDEOUT_KITCHEN_CORRIDOR, world, [ - (Regions.GF_NEAR_GROTTO, lambda bundle: True), - (Regions.GF_ABOVE_GTG, lambda bundle: True), + (Regions.GF_NEAR_GROTTO, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_3, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), + (Regions.GF_ABOVE_GTG, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_4, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), (Regions.THIEVES_HIDEOUT_KITCHEN_BOTTOM, lambda bundle: can_pass_enemy(bundle, Enemies.GERUDO_GUARD)) ]) @@ -184,9 +185,9 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.THIEVES_HIDEOUT_KITCHEN_POTS, lambda bundle: can_use(Items.BOOMERANG, bundle)), (Regions.GF_NEAR_GS, - lambda bundle: can_pass_enemy(bundle, Enemies.GERUDO_GUARD) or can_use(Items.HOVER_BOOTS, bundle)), + lambda bundle: can_pass_enemy(bundle, Enemies.GERUDO_GUARD) or can_use(Items.HOVER_BOOTS, bundle), SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_10, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), (Regions.GF_TOP_OF_LOWER_VINES, - lambda bundle: can_pass_enemy(bundle, Enemies.GERUDO_GUARD) or can_use(Items.HOVER_BOOTS, bundle)) + lambda bundle: can_pass_enemy(bundle, Enemies.GERUDO_GUARD) or can_use(Items.HOVER_BOOTS, bundle), SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_9, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)) ]) # Thieves Hideout Kitchen Pots @@ -227,7 +228,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.THIEVES_HIDEOUT_BREAK_ROOM, world, [ (Regions.GF_BELOW_CHEST, lambda bundle: can_pass_enemy( - bundle, Enemies.GERUDO_GUARD)), + bundle, Enemies.GERUDO_GUARD), SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_11, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)), (Regions.THIEVES_HIDEOUT_BREAK_ROOM_CORRIDOR, lambda bundle: can_use(Items.HOOKSHOT, bundle)) ]) @@ -237,5 +238,5 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.THIEVES_HIDEOUT_BREAK_ROOM_CORRIDOR, world, [ (Regions.THIEVES_HIDEOUT_BREAK_ROOM, lambda bundle: can_use(Items.HOOKSHOT, bundle)), - (Regions.GF_ABOVE_JAIL, lambda bundle: True) + (Regions.GF_ABOVE_JAIL, lambda bundle: True, SOHThievesHideoutEntranceNames.GERUDOS_FORTRESS_12, int(SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE)) ]) From bfbb06943d726e2f9271fe8cf11ea126473f8706 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Wed, 26 Nov 2025 17:08:07 -0500 Subject: [PATCH 21/22] Define Overworld Entrances --- worlds/oot_soh/EntranceShuffle.py | 6 ++++-- worlds/oot_soh/Enums.py | 4 +++- worlds/oot_soh/Options.py | 2 +- worlds/oot_soh/__init__.py | 16 ++++++++++++---- .../location_access/overworld/castle_grounds.py | 2 +- .../overworld/death_mountain_crater.py | 4 ++-- .../overworld/death_mountain_trail.py | 6 +++--- .../location_access/overworld/desert_colossus.py | 2 +- .../location_access/overworld/gerudo_fortress.py | 4 ++-- .../location_access/overworld/gerudo_valley.py | 6 +++--- .../location_access/overworld/goron_city.py | 6 +++--- .../location_access/overworld/graveyard.py | 2 +- .../overworld/haunted_wasteland.py | 4 ++-- .../location_access/overworld/hyrule_field.py | 14 +++++++------- .../location_access/overworld/kakariko.py | 6 +++--- .../location_access/overworld/kokiri_forest.py | 4 ++-- .../location_access/overworld/lake_hylia.py | 4 ++-- .../location_access/overworld/lon_lon_ranch.py | 2 +- .../location_access/overworld/lost_woods.py | 12 ++++++------ .../oot_soh/location_access/overworld/market.py | 10 +++++----- .../overworld/sacred_forest_meadow.py | 2 +- .../location_access/overworld/temple_of_time.py | 2 +- .../location_access/overworld/zoras_domain.py | 6 +++--- .../location_access/overworld/zoras_fountain.py | 2 +- .../location_access/overworld/zoras_river.py | 6 +++--- 25 files changed, 73 insertions(+), 61 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 0f936addb8c5..2d8cfa605e4d 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -20,7 +20,8 @@ SOHBossEntranceNames.FIRE_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.FIRE_TEMPLE_BOSS_EXIT, SOHBossEntranceNames.WATER_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.WATER_TEMPLE_BOSS_EXIT, SOHBossEntranceNames.SHADOW_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SHADOW_TEMPLE_BOSS_EXIT, - SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SPIRIT_TEMPLE_BOSS_EXIT + SOHBossEntranceNames.SPIRIT_TEMPLE_BOSS_ENTRANCE: SOHBossEntranceExitNames.SPIRIT_TEMPLE_BOSS_EXIT, + SOHOverworldEntranceNames.LAKE_HYLIA_RIVER_ENTRANCE: SOHOverworldEntranceNames.LAKE_HYLIA_RIVER_EXIT } @@ -30,7 +31,8 @@ SOHEntranceGroups.GROTTO: [SOHEntranceGroups.GROTTO], SOHEntranceGroups.INTERIOR: [SOHEntranceGroups.INTERIOR], SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE: [SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE], - SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE: [SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE] + SOHEntranceGroups.GERUDO_FORTRESS_ENTRANCE: [SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE], + SOHEntranceGroups.OVERWORLD: [SOHEntranceGroups.OVERWORLD] } diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index 56c07c38c1d9..693afadd393a 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -4173,7 +4173,9 @@ class SOHOverworldEntranceNames(StrEnum): ZORAS_DOMAIN_ENTRANCE = "Zoras Domain Entrance" ZORAS_RIVER_WATERFALL_EXIT = "Zoras River Waterfall Exit" ZORAS_FOUNTAIN_TUNNEL_EXIT = "Zoras Fountain Tunnel Exit" - ZORAS_DOMAIN_KING_ZORA_EXIT = "Zoras Domain King Zora Exit" + ZORAS_DOMAIN_KING_ZORA_EXIT = "Zoras Domain King Zora Exit" + LAKE_HYLIA_RIVER_EXIT = "Lake Hylia River Exit" + LAKE_HYLIA_RIVER_ENTRANCE = "Lake Hylia River Entrance" class SOHThievesHideoutEntranceNames(StrEnum): diff --git a/worlds/oot_soh/Options.py b/worlds/oot_soh/Options.py index 81359f47892d..8b6da3a04ae9 100644 --- a/worlds/oot_soh/Options.py +++ b/worlds/oot_soh/Options.py @@ -1089,7 +1089,7 @@ class SohOptions(PerGameCommonOptions): enable_all_tricks: EnableAllTricks shuffle_dungeon_entrances: ShuffleDungeonEntrances shuffle_boss_entrances: ShuffleDungeonBossEntrances - shuffle_overworld_entances: ShuffleOverworldEntrances + shuffle_overworld_entrances: ShuffleOverworldEntrances shuffle_theives_hideout_entrances: ShuffleTheivesHideoutEntrances shuffle_grotto_entrances: ShuffleGrottoEntrances shuffle_warp_song_entrances: ShuffleWarpSongEntrances diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index 35db1d0fafa9..ef7e54af13d7 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -262,10 +262,18 @@ def connect_entrances(self): if self.options.shuffle_boss_entrances == "age_restricted": randomize_entrances_soh(self, entrances_to_shuffle, ageRestricted=True) entrances_to_shuffle.clear() - # else: - # # Need this else here. Mixed entrances doesn't work for entrances locked behind another yet. Boss entrances are behind dungeon entrances - # randomize_entrances_soh(self, entrances_to_shuffle) - # entrances_to_shuffle.clear() + + # Overworld Entrances + if self.options.shuffle_overworld_entrances: + for entranceName in SOHOverworldEntranceNames: + if not self.options.decouple_entrances and entranceName == SOHOverworldEntranceNames.LAKE_HYLIA_RIVER_ENTRANCE: + continue + + # ignore our one way exit here + if entranceName == SOHOverworldEntranceNames.LAKE_HYLIA_RIVER_EXIT: + continue + + entrances_to_shuffle.add(entranceName) # Grotto Entrances if self.options.shuffle_grotto_entrances: diff --git a/worlds/oot_soh/location_access/overworld/castle_grounds.py b/worlds/oot_soh/location_access/overworld/castle_grounds.py index c2efd6353afb..fb5f834d5e05 100644 --- a/worlds/oot_soh/location_access/overworld/castle_grounds.py +++ b/worlds/oot_soh/location_access/overworld/castle_grounds.py @@ -23,7 +23,7 @@ def set_region_rules(world: "SohWorld") -> None: # Castle Grounds # Connections connect_regions(Regions.CASTLE_GROUNDS, world, [ - (Regions.MARKET, lambda bundle: True), + (Regions.MARKET, lambda bundle: True, SOHOverworldEntranceNames.CASTLE_GROUNDS_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.HYRULE_CASTLE_GROUNDS, lambda bundle: is_child(bundle)), (Regions.GANONS_CASTLE_GROUNDS, lambda bundle: is_adult(bundle)) ]) diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py index 3baed4678419..02652d9c3acf 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py @@ -23,7 +23,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.DMC_UPPER_NEARBY, world, [ (Regions.DMC_UPPER_LOCAL, lambda bundle: fire_timer(bundle) >= 48), - (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: True), + (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_CRATER_UPPER_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.DMC_UPPER_GROTTO, lambda bundle: blast_or_smash( bundle) and (fire_timer(bundle) >= 8 or hearts(bundle) >= 3), SOHGrottoEntranceNames.DMC_UPPER_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) @@ -83,7 +83,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.DMC_LOWER_NEARBY, world, [ (Regions.DMC_LOWER_LOCAL, lambda bundle: fire_timer(bundle) >= 48), - (Regions.GC_DARUNIAS_CHAMBER, lambda bundle: True), + (Regions.GC_DARUNIAS_CHAMBER, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_TRAIL_GC_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.DMC_GREAT_FAIRY_FOUNTAIN, lambda bundle: can_use(Items.MEGATON_HAMMER, bundle), SOHInteriorEntranceNames.DMC_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.DMC_HAMMER_GROTTO, lambda bundle: is_adult( diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py index e8b8c9d9f711..3591b2ecd823 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py @@ -62,8 +62,8 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.DEATH_MOUNTAIN_TRAIL, world, [ - (Regions.KAK_BEHIND_GATE, lambda bundle: True), - (Regions.GORON_CITY, lambda bundle: True), + (Regions.KAK_BEHIND_GATE, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_TRAIL_BOTTOM_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.GORON_CITY, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_CRATER_GC_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: blast_or_smash(bundle) or (is_adult(bundle) and ((has_item(LocalEvents.DMT_BEAN_PLANTED, bundle) and has_item(Items.GORONS_BRACELET, bundle)) or (can_use(Items.HOVER_BOOTS, bundle) and can_do_trick(Tricks.DMT_CLIMB_HOVERS, bundle))))), (Regions.DODONGOS_CAVERN_ENTRYWAY, lambda bundle: has_explosives(bundle) or has_item(Items.GORONS_BRACELET, bundle) or is_adult( @@ -96,7 +96,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.DEATH_MOUNTAIN_SUMMIT, world, [ (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True), - (Regions.DMC_UPPER_LOCAL, lambda bundle: True), + (Regions.DMC_UPPER_LOCAL, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_TRAIL_SUMMIT_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.DMT_OWL_FLIGHT, lambda bundle: is_child(bundle)), (Regions.DMT_COW_GROTTO, lambda bundle: blast_or_smash(bundle), SOHGrottoEntranceNames.DMT_COW_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.DMT_GREAT_FAIRY_FOUNTAIN, lambda bundle: blast_or_smash(bundle), SOHInteriorEntranceNames.DMT_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) diff --git a/worlds/oot_soh/location_access/overworld/desert_colossus.py b/worlds/oot_soh/location_access/overworld/desert_colossus.py index e51dc75d48a6..549b69857d77 100644 --- a/worlds/oot_soh/location_access/overworld/desert_colossus.py +++ b/worlds/oot_soh/location_access/overworld/desert_colossus.py @@ -62,7 +62,7 @@ def set_region_rules(world: "SohWorld") -> None: lambda bundle: has_explosives(bundle), SOHInteriorEntranceNames.COLOSSUS_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.SPIRIT_TEMPLE_ENTRYWAY, lambda bundle: True, SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY), - (Regions.WASTELAND_NEAR_COLOSSUS, lambda bundle: True), + (Regions.WASTELAND_NEAR_COLOSSUS, lambda bundle: True, SOHOverworldEntranceNames.DESERT_COLOSSUS_EAST_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.COLOSSUS_GROTTO, lambda bundle: can_use( Items.SILVER_GAUNTLETS, bundle), SOHGrottoEntranceNames.COLOSSUS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY) ]) diff --git a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py index 0d21edf1be42..aa2791a25d81 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py @@ -33,7 +33,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GERUDO_FORTRESS_OUTSKIRTS, world, [ - (Regions.GV_FORTRESS_SIDE, lambda bundle: True), + (Regions.GV_FORTRESS_SIDE, lambda bundle: True, SOHOverworldEntranceNames.GERUDOS_FORTRESS_EAST_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.THIEVES_HIDEOUT_1_TORCH_CELL, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_0, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GF_OUTSIDE_GATE, lambda bundle: has_item( LocalEvents.GF_GATE_OPEN, bundle)), @@ -335,7 +335,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.GF_OUTSIDE_GATE, world, [ (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: has_item( LocalEvents.GF_GATE_OPEN, bundle)), - (Regions.WASTELAND_NEAR_FORTRESS, lambda bundle: True), + (Regions.WASTELAND_NEAR_FORTRESS, lambda bundle: True, SOHOverworldEntranceNames.GERUDOS_FORTRESS_GATE_EXIT, SOHEntranceGroups.OVERWORLD), ]) # GF Storms Grotto diff --git a/worlds/oot_soh/location_access/overworld/gerudo_valley.py b/worlds/oot_soh/location_access/overworld/gerudo_valley.py index 1f952b1026fc..a02357ce5952 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_valley.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_valley.py @@ -35,7 +35,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connection connect_regions(Regions.GERUDO_VALLEY, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.GERUDO_VALLEY_EAST_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.GV_UPPER_STREAM, lambda bundle: is_child(bundle) or has_item(Items.BRONZE_SCALE, bundle) or take_damage(bundle)), (Regions.GV_CRATE_LEDGE, lambda bundle: is_child( @@ -44,7 +44,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GV_FORTRESS_SIDE, lambda bundle: (is_adult(bundle) and ( can_use(Items.EPONA, bundle) or can_use(Items.LONGSHOT, bundle) or world.options.fortress_carpenters.value == 2 or has_item( - Events.RESCUED_ALL_CARPENTERS, bundle))) or (is_child(bundle) and can_use(Items.HOOKSHOT, bundle))), + Events.RESCUED_ALL_CARPENTERS, bundle))) or (is_child(bundle) and can_use(Items.HOOKSHOT, bundle)), SOHOverworldEntranceNames.GERUDO_VALLEY_WEST_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.GV_LOWER_STREAM, lambda bundle: is_child(bundle)) ]) @@ -91,7 +91,7 @@ def set_region_rules(world: "SohWorld") -> None: # GV Lower Stream # Connections connect_regions(Regions.GV_LOWER_STREAM, world, [ - (Regions.LAKE_HYLIA, lambda bundle: True) + (Regions.LAKE_HYLIA, lambda bundle: True, SOHOverworldEntranceNames.LAKE_HYLIA_RIVER_ENTRANCE, SOHEntranceGroups.OVERWORLD, EntranceType.ONE_WAY) ]) # GV Grotto Ledge diff --git a/worlds/oot_soh/location_access/overworld/goron_city.py b/worlds/oot_soh/location_access/overworld/goron_city.py index 47624081d369..c49e4390b092 100644 --- a/worlds/oot_soh/location_access/overworld/goron_city.py +++ b/worlds/oot_soh/location_access/overworld/goron_city.py @@ -76,7 +76,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GORON_CITY, world, [ - (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True), + (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True, SOHOverworldEntranceNames.GORON_CITY_UPPER_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.GC_MEDIGORON, lambda bundle: can_break_mud_walls( bundle) or has_item(Items.GORONS_BRACELET, bundle)), (Regions.GC_WOODS_WARP, lambda bundle: has_item( @@ -113,7 +113,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.GC_WOODS_WARP, world, [ (Regions.GORON_CITY, lambda bundle: has_item( LocalEvents.GC_WOODS_WARP_OPEN, bundle)), - (Regions.LOST_WOODS, lambda bundle: True) + (Regions.LOST_WOODS, lambda bundle: True, SOHOverworldEntranceNames.GORON_CITY_TUNNEL_SHORTCUT, SOHEntranceGroups.OVERWORLD) ]) # Goron City Darunias Chamber @@ -133,7 +133,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.GC_DARUNIAS_CHAMBER, world, [ (Regions.GORON_CITY, lambda bundle: True), - (Regions.DMC_LOWER_LOCAL, lambda bundle: is_adult(bundle)) + (Regions.DMC_LOWER_LOCAL, lambda bundle: is_adult(bundle), SOHOverworldEntranceNames.GORON_CITY_DARUNIA_ROOM_EXIT, SOHEntranceGroups.OVERWORLD) ]) # Goron City Grotto Platform diff --git a/worlds/oot_soh/location_access/overworld/graveyard.py b/worlds/oot_soh/location_access/overworld/graveyard.py index 4ade497ab4bb..6a8334689a3d 100644 --- a/worlds/oot_soh/location_access/overworld/graveyard.py +++ b/worlds/oot_soh/location_access/overworld/graveyard.py @@ -78,7 +78,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GRAVEYARD_DAMPES_GRAVE, lambda bundle: is_adult(bundle), SOHGrottoEntranceNames.GRAVEYARD_DAMPES_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GRAVEYARD_DAMPES_HOUSE, lambda bundle: is_adult(bundle) and can_open_overworld_door(Items.DAMPES_HUT_KEY, bundle), SOHInteriorEntranceNames.GRAVEYARD_DAMPES_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHOverworldEntranceNames.GRAVEYARD_ENTRANCE, SOHEntranceGroups.OVERWORLD), (Regions.GRAVEYARD_WARP_PAD_REGION, lambda bundle: False) ]) diff --git a/worlds/oot_soh/location_access/overworld/haunted_wasteland.py b/worlds/oot_soh/location_access/overworld/haunted_wasteland.py index a5e43c823dc9..79c9e0888d82 100644 --- a/worlds/oot_soh/location_access/overworld/haunted_wasteland.py +++ b/worlds/oot_soh/location_access/overworld/haunted_wasteland.py @@ -19,7 +19,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.WASTELAND_NEAR_FORTRESS, world, [ - (Regions.GF_OUTSIDE_GATE, lambda bundle: True), + (Regions.GF_OUTSIDE_GATE, lambda bundle: True, SOHOverworldEntranceNames.HAUNTED_WASTELAND_EAST_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.HAUNTED_WASTELAND, lambda bundle: can_use_any( [Items.HOVER_BOOTS, Items.LONGSHOT], bundle) or can_do_trick(Tricks.HW_CROSSING, bundle)) ]) @@ -70,7 +70,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.WASTELAND_NEAR_COLOSSUS, world, [ - (Regions.DESERT_COLOSSUS, lambda bundle: True), + (Regions.DESERT_COLOSSUS, lambda bundle: True, SOHOverworldEntranceNames.HAUNTED_WASTELAND_WEST_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.HAUNTED_WASTELAND, lambda bundle: can_do_trick( Tricks.HW_REVERSE, bundle)) ]) diff --git a/worlds/oot_soh/location_access/overworld/hyrule_field.py b/worlds/oot_soh/location_access/overworld/hyrule_field.py index c074a9a41143..761f92a9bf7c 100644 --- a/worlds/oot_soh/location_access/overworld/hyrule_field.py +++ b/worlds/oot_soh/location_access/overworld/hyrule_field.py @@ -173,13 +173,13 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HYRULE_FIELD, world, [ - (Regions.LW_BRIDGE, lambda bundle: True), - (Regions.LAKE_HYLIA, lambda bundle: True), - (Regions.GERUDO_VALLEY, lambda bundle: True), - (Regions.MARKET_ENTRANCE, lambda bundle: True), - (Regions.KAKARIKO_VILLAGE, lambda bundle: True), - (Regions.ZR_FRONT, lambda bundle: True), - (Regions.LON_LON_RANCH, lambda bundle: True), + (Regions.LW_BRIDGE, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_WOODED_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.LAKE_HYLIA, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_FENCE_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.GERUDO_VALLEY, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_ROCKY_PATH, SOHEntranceGroups.OVERWORLD), + (Regions.MARKET_ENTRANCE, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_ON_BRIDGE_SPAWN, SOHEntranceGroups.OVERWORLD), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_STAIRS_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.ZR_FRONT, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_RIVER_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.LON_LON_RANCH, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_CENTER_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.HF_SOUTHEAST_GROTTO, lambda bundle: (blast_or_smash(bundle)), SOHGrottoEntranceNames.HF_SOUTHEAST_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.HF_OPEN_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.HF_OPEN_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.HF_INSIDE_FENCE_GROTTO, lambda bundle: ( diff --git a/worlds/oot_soh/location_access/overworld/kakariko.py b/worlds/oot_soh/location_access/overworld/kakariko.py index b6e70d33aab4..88d8b1f61cac 100644 --- a/worlds/oot_soh/location_access/overworld/kakariko.py +++ b/worlds/oot_soh/location_access/overworld/kakariko.py @@ -122,7 +122,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAKARIKO_VILLAGE, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.KAKARIKO_VILLAGE_FRONT_GATE, SOHEntranceGroups.OVERWORLD), (Regions.KAK_CARPENTER_BOSS_HOUSE, lambda bundle: can_open_overworld_door(Items.BOSS_HOUSE_KEY, bundle), SOHInteriorEntranceNames.KAK_CARPENTER_BOSS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_HOUSE_OF_SKULLTULA, lambda bundle: can_open_overworld_door( @@ -157,7 +157,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.KAK_IMPAS_ROOFTOP, lambda bundle: can_use(Items.HOOKSHOT, bundle) or can_do_trick(Tricks.KAK_ROOFTOP_GS, bundle) and can_use( Items.HOVER_BOOTS, bundle)), - (Regions.THE_GRAVEYARD, lambda bundle: True), + (Regions.THE_GRAVEYARD, lambda bundle: True, SOHOverworldEntranceNames.KAKARIKO_VILLAGE_SOUTHEAST_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.KAK_BEHIND_GATE, lambda bundle: is_adult(bundle) or has_item(Events.KAKARIKO_GATE_OPEN, bundle)), (Regions.KAK_BACKYARD, lambda bundle: is_adult(bundle) or at_day(bundle)), @@ -423,7 +423,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.KAKARIKO_VILLAGE, lambda bundle: is_adult(bundle) or has_item(Events.KAKARIKO_GATE_OPEN, bundle) or can_do_trick( Tricks.VISIBLE_COLLISION, bundle)), - (Regions.DEATH_MOUNTAIN, lambda bundle: True) + (Regions.DEATH_MOUNTAIN, lambda bundle: True, SOHOverworldEntranceNames.KAKARIKO_VILLAGE_GUARD_GATE, SOHEntranceGroups.OVERWORLD) ]) # Kak Well diff --git a/worlds/oot_soh/location_access/overworld/kokiri_forest.py b/worlds/oot_soh/location_access/overworld/kokiri_forest.py index 772172dc4e11..08efcc7b322f 100644 --- a/worlds/oot_soh/location_access/overworld/kokiri_forest.py +++ b/worlds/oot_soh/location_access/overworld/kokiri_forest.py @@ -179,9 +179,9 @@ def set_region_rules(world: "SohWorld") -> None: or (is_child(bundle) and has_item(LocalEvents.MIDO_SWORD_AND_SHIELD, bundle)) # Todo, maybe create a helper for handling settings or world.options.closed_forest.value == 2), - (Regions.LOST_WOODS, lambda bundle: True), + (Regions.LOST_WOODS, lambda bundle: True, SOHOverworldEntranceNames.KOKIRI_FOREST_UPPER_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.LW_BRIDGE_FROM_FOREST, lambda bundle: world.options.closed_forest.value >= 1 or is_adult(bundle) or - has_item(Events.DEKU_TREE_COMPLETED, bundle)), + has_item(Events.DEKU_TREE_COMPLETED, bundle), SOHOverworldEntranceNames.KOKIRI_FOREST_LOWER_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.KF_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle), SOHGrottoEntranceNames.KF_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/lake_hylia.py b/worlds/oot_soh/location_access/overworld/lake_hylia.py index 3c0ec5f33205..bf8365042a12 100644 --- a/worlds/oot_soh/location_access/overworld/lake_hylia.py +++ b/worlds/oot_soh/location_access/overworld/lake_hylia.py @@ -155,7 +155,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LAKE_HYLIA, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.LAKE_HYLIA_NORTH_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.LH_FROM_SHORTCUT, lambda bundle: True), (Regions.LH_OWL_FLIGHT, lambda bundle: is_child(bundle)), (Regions.LH_FISHING_ISLAND, lambda bundle: ((is_child(bundle) @@ -179,7 +179,7 @@ def set_region_rules(world: "SohWorld") -> None: can_use(Items.IRON_BOOTS, bundle)), (Regions.ZORAS_DOMAIN, lambda bundle: is_child(bundle) and (has_item(Items.SILVER_SCALE, bundle) or - can_use(Items.IRON_BOOTS, bundle))), + can_use(Items.IRON_BOOTS, bundle)), SOHOverworldEntranceNames.LAKE_HYLIA_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD), ]) # LH from Water Temple diff --git a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py index a059f0374cae..99b79160daad 100644 --- a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py +++ b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py @@ -51,7 +51,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LON_LON_RANCH, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.LON_LON_RANCH_ENTRANCE, SOHEntranceGroups.OVERWORLD), (Regions.LLR_TALONS_HOUSE, lambda bundle: can_open_overworld_door( Items.TALONS_HOUSE_KEY, bundle), SOHInteriorEntranceNames.LLR_TALONS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.LLR_STABLES, lambda bundle: can_open_overworld_door( diff --git a/worlds/oot_soh/location_access/overworld/lost_woods.py b/worlds/oot_soh/location_access/overworld/lost_woods.py index 68fc12a9c47d..c6d237545c02 100644 --- a/worlds/oot_soh/location_access/overworld/lost_woods.py +++ b/worlds/oot_soh/location_access/overworld/lost_woods.py @@ -27,7 +27,7 @@ def set_region_rules(world: "SohWorld") -> None: # LW Forest Exit # Connections connect_regions(Regions.LW_FOREST_EXIT, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True), + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD), ]) # Lost Woods @@ -101,7 +101,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.LOST_WOODS, world, [ (Regions.LW_FOREST_EXIT, lambda bundle: True), - (Regions.GC_WOODS_WARP, lambda bundle: True), + (Regions.GC_WOODS_WARP, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_TUNNEL_SHORTCUT, SOHEntranceGroups.OVERWORLD), (Regions.LW_BRIDGE, lambda bundle: (is_adult(bundle) and ( has_item(LocalEvents.LW_BRIDGE_BEAN_PLANTED, bundle) or can_do_trick(Tricks.LW_BRIDGE, bundle))) or can_use(Items.HOVER_BOOTS, bundle) or can_use( @@ -109,7 +109,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.ZR_FROM_SHORTCUT, lambda bundle: has_item(Items.SILVER_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle) or (can_do_trick( Tricks.LOST_WOOD_NAVI_DIVE, bundle) and is_child(bundle) and has_item(Items.BRONZE_SCALE, - bundle) and can_jump_slash(bundle))), + bundle) and can_jump_slash(bundle)), SOHOverworldEntranceNames.LOST_WOODS_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD), (Regions.LW_BEYOND_MIDO, lambda bundle: is_child(bundle) or can_use(Items.SARIAS_SONG, bundle) or can_do_trick(Tricks.LW_MIDO_BACKFLIP, bundle)), @@ -160,7 +160,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.LW_FOREST_EXIT, lambda bundle: True), (Regions.LOST_WOODS, lambda bundle: is_child( bundle) or can_use(Items.SARIAS_SONG, bundle)), - (Regions.SFM_ENTRYWAY, lambda bundle: True), + (Regions.SFM_ENTRYWAY, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_NORTH_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.DEKU_THEATER, lambda bundle: True, SOHGrottoEntranceNames.DEKU_THEATER_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.LW_SCRUBS_GROTTO, lambda bundle: blast_or_smash(bundle), SOHGrottoEntranceNames.LW_SCRUBS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) @@ -246,7 +246,7 @@ def set_region_rules(world: "SohWorld") -> None: # LW Bridge # Connections connect_regions(Regions.LW_BRIDGE, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True), - (Regions.HYRULE_FIELD, lambda bundle: True), + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_BRIDGE_EAST_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_BRIDGE_WEST_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.LOST_WOODS, lambda bundle: can_use(Items.LONGSHOT, bundle)) ]) diff --git a/worlds/oot_soh/location_access/overworld/market.py b/worlds/oot_soh/location_access/overworld/market.py index e74ca0f725a6..9e5e82c6b736 100644 --- a/worlds/oot_soh/location_access/overworld/market.py +++ b/worlds/oot_soh/location_access/overworld/market.py @@ -19,8 +19,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.MARKET_ENTRANCE, world, [ (Regions.HYRULE_FIELD, lambda bundle: ( - is_adult(bundle) or at_day(bundle))), - (Regions.MARKET, lambda bundle: True), + is_adult(bundle) or at_day(bundle)), SOHOverworldEntranceNames.MARKET_ENTRANCE_NEAR_GUARD_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.MARKET, lambda bundle: True, SOHOverworldEntranceNames.MARKET_ENTRANCE_NORTH_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.MARKET_GUARD_HOUSE, lambda bundle: can_open_overworld_door( Items.GUARD_HOUSE_KEY, bundle), SOHInteriorEntranceNames.MARKET_GUARD_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) @@ -55,9 +55,9 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET, world, [ - (Regions.MARKET_ENTRANCE, lambda bundle: True), - (Regions.TOT_ENTRANCE, lambda bundle: True), - (Regions.CASTLE_GROUNDS, lambda bundle: True), + (Regions.MARKET_ENTRANCE, lambda bundle: True, SOHOverworldEntranceNames.MARKET_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.TOT_ENTRANCE, lambda bundle: True, SOHOverworldEntranceNames.MARKET_DAY_TEMPLE_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.CASTLE_GROUNDS, lambda bundle: True, SOHOverworldEntranceNames.MARKET_DAY_CASTLE_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.MARKET_BAZAAR, lambda bundle: (is_child(bundle) and at_day( bundle) and can_open_overworld_door(Items.MARKET_BAZAAR_KEY, bundle)), SOHInteriorEntranceNames.MARKET_BAZAAR_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.MARKET_MASK_SHOP, lambda bundle: (is_child(bundle) and at_day( diff --git a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py index 271eb306e573..7c6e9cd157c2 100644 --- a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py +++ b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py @@ -13,7 +13,7 @@ def set_region_rules(world: "SohWorld") -> None: # SFM Entryway # Connections connect_regions(Regions.SFM_ENTRYWAY, world, [ - (Regions.LW_BEYOND_MIDO, lambda bundle: True), + (Regions.LW_BEYOND_MIDO, lambda bundle: True, SOHOverworldEntranceNames.SACRED_FOREST_MEADOW_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.SACRED_FOREST_MEADOW, lambda bundle: is_adult( bundle) or can_kill_enemy(bundle, Enemies.WOLFOS)), (Regions.SFM_WOLFOS_GROTTO, lambda bundle: can_open_bomb_grotto(bundle), SOHGrottoEntranceNames.SFM_WOLFOS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), diff --git a/worlds/oot_soh/location_access/overworld/temple_of_time.py b/worlds/oot_soh/location_access/overworld/temple_of_time.py index 486b8e04043a..1b42f50ad1ec 100644 --- a/worlds/oot_soh/location_access/overworld/temple_of_time.py +++ b/worlds/oot_soh/location_access/overworld/temple_of_time.py @@ -37,7 +37,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.TOT_ENTRANCE, world, [ - (Regions.MARKET, lambda bundle: True), + (Regions.MARKET, lambda bundle: True, SOHOverworldEntranceNames.TEMPLE_OF_TIME_EXTERIOR_DAY_GOSSIP_STONE_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.TEMPLE_OF_TIME, lambda bundle: True, SOHSpecialInteriorEntranceNames.TEMPLE_OF_TIME_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/zoras_domain.py b/worlds/oot_soh/location_access/overworld/zoras_domain.py index 85f084819337..79982410eb92 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_domain.py +++ b/worlds/oot_soh/location_access/overworld/zoras_domain.py @@ -82,9 +82,9 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZORAS_DOMAIN, world, [ - (Regions.ZR_BEHIND_WATERFALL, lambda bundle: True), + (Regions.ZR_BEHIND_WATERFALL, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_DOMAIN_ENTRANCE, SOHEntranceGroups.OVERWORLD), (Regions.LH_FROM_SHORTCUT, lambda bundle: is_child(bundle) and ( - has_item(Items.SILVER_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle))), + has_item(Items.SILVER_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle)), SOHOverworldEntranceNames.ZORAS_DOMAIN_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD), (Regions.ZD_BEHIND_KING_ZORA, lambda bundle: has_item(Events.DELIVER_LETTER, bundle) or world.options.zoras_fountain.value == 2 or ( world.options.zoras_fountain.value == 1 and is_adult(bundle)) or ( @@ -117,7 +117,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.ZORAS_DOMAIN, lambda bundle: has_item(Events.DELIVER_LETTER, bundle) or world.options.zoras_fountain.value == 2 or ( world.options.zoras_fountain.value == 1 and is_adult(bundle))), - (Regions.ZORAS_FOUNTAIN, lambda bundle: True), + (Regions.ZORAS_FOUNTAIN, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_DOMAIN_KING_ZORA_EXIT, SOHEntranceGroups.OVERWORLD), ]) # ZD Shop diff --git a/worlds/oot_soh/location_access/overworld/zoras_fountain.py b/worlds/oot_soh/location_access/overworld/zoras_fountain.py index 1b687b84ae30..e0e66994dc02 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_fountain.py +++ b/worlds/oot_soh/location_access/overworld/zoras_fountain.py @@ -45,7 +45,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZORAS_FOUNTAIN, world, [ - (Regions.ZD_BEHIND_KING_ZORA, lambda bundle: True), + (Regions.ZD_BEHIND_KING_ZORA, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_FOUNTAIN_TUNNEL_EXIT, SOHEntranceGroups.OVERWORLD), (Regions.ZF_ICEBERGS, lambda bundle: is_adult(bundle)), (Regions.ZF_LAKEBED, lambda bundle: can_use(Items.IRON_BOOTS, bundle)), (Regions.ZF_HIDDEN_CAVE, lambda bundle: can_use( diff --git a/worlds/oot_soh/location_access/overworld/zoras_river.py b/worlds/oot_soh/location_access/overworld/zoras_river.py index 287985eeb286..b45e5bdb1f73 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_river.py +++ b/worlds/oot_soh/location_access/overworld/zoras_river.py @@ -53,7 +53,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.ZR_FRONT, world, [ (Regions.ZORA_RIVER, lambda bundle: is_adult( bundle) or blast_or_smash(bundle)), - (Regions.HYRULE_FIELD, lambda bundle: True) + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_RIVER_WEST_EXIT, SOHEntranceGroups.OVERWORLD) ]) # Zora River @@ -166,7 +166,7 @@ def set_region_rules(world: "SohWorld") -> None: can_do_trick(Tricks.ZR_CUCCO, bundle)) or (is_adult(bundle) and can_use(Items.HOVER_BOOTS, bundle) and - can_do_trick(Tricks.ZR_HOVERS, bundle))) + can_do_trick(Tricks.ZR_HOVERS, bundle)), SOHOverworldEntranceNames.ZORAS_RIVER_WATERFALL_EXIT, SOHEntranceGroups.OVERWORLD) ]) # Events @@ -178,7 +178,7 @@ def set_region_rules(world: "SohWorld") -> None: has_item(Items.BOTTLE_WITH_FAIRY, bundle) or has_item(Items.BRONZE_SCALE, bundle)), (Regions.LOST_WOODS, lambda bundle: has_item(Items.SILVER_SCALE, bundle) or - can_use(Items.IRON_BOOTS, bundle)) + can_use(Items.IRON_BOOTS, bundle), SOHOverworldEntranceNames.ZORAS_RIVER_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD) ]) From 9b431e66f8704f11839fb52190c3785db0c4adb0 Mon Sep 17 00:00:00 2001 From: mattman107 Date: Thu, 27 Nov 2025 13:38:11 -0500 Subject: [PATCH 22/22] Finish initial overworld entrances --- worlds/oot_soh/EntranceShuffle.py | 2 +- worlds/oot_soh/Enums.py | 2 +- worlds/oot_soh/__init__.py | 2 +- .../overworld/castle_grounds.py | 2 +- .../overworld/death_mountain_crater.py | 4 +-- .../overworld/death_mountain_trail.py | 6 ++-- .../overworld/desert_colossus.py | 2 +- .../overworld/gerudo_fortress.py | 4 +-- .../overworld/gerudo_valley.py | 8 ++--- .../location_access/overworld/goron_city.py | 6 ++-- .../location_access/overworld/graveyard.py | 2 +- .../overworld/haunted_wasteland.py | 4 +-- .../location_access/overworld/hyrule_field.py | 14 ++++---- .../location_access/overworld/kakariko.py | 6 ++-- .../overworld/kokiri_forest.py | 4 +-- .../location_access/overworld/lake_hylia.py | 4 +-- .../overworld/lon_lon_ranch.py | 2 +- .../location_access/overworld/lost_woods.py | 32 +++++++++++-------- .../location_access/overworld/market.py | 10 +++--- .../overworld/sacred_forest_meadow.py | 2 +- .../overworld/temple_of_time.py | 2 +- .../location_access/overworld/zoras_domain.py | 6 ++-- .../overworld/zoras_fountain.py | 2 +- .../location_access/overworld/zoras_river.py | 6 ++-- 24 files changed, 69 insertions(+), 65 deletions(-) diff --git a/worlds/oot_soh/EntranceShuffle.py b/worlds/oot_soh/EntranceShuffle.py index 2d8cfa605e4d..1d4f170e7225 100644 --- a/worlds/oot_soh/EntranceShuffle.py +++ b/worlds/oot_soh/EntranceShuffle.py @@ -118,7 +118,7 @@ def randomize_soh_one_way_entrances(world: "SohWorld") -> None: one_way_entrance_names = list() one_way_entrance_exit_names = list() # TODO This will need to be updated as we make more named entrances - all_named_entrances = list(SOHDungeonEntranceNames) + list(SOHDungeonExitNames) + list(SOHGrottoExitNames) + list(SOHGrottoEntranceNames) + list(SOHInteriorEntranceNames) + list(SOHInteriorExitNames) + list(SOHSpecialInteriorExitNames) + list(SOHSpecialInteriorEntranceNames) + all_named_entrances = list(SOHDungeonEntranceNames) + list(SOHDungeonExitNames) + list(SOHGrottoExitNames) + list(SOHGrottoEntranceNames) + list(SOHInteriorEntranceNames) + list(SOHInteriorExitNames) + list(SOHSpecialInteriorExitNames) + list(SOHSpecialInteriorEntranceNames) + list(SOHOverworldEntranceNames) if world.options.shuffle_owl_drop_entrances: one_way_entrance_names += [Regions.LH_OWL_FLIGHT, Regions.DMT_OWL_FLIGHT] diff --git a/worlds/oot_soh/Enums.py b/worlds/oot_soh/Enums.py index 693afadd393a..48d641b4b275 100644 --- a/worlds/oot_soh/Enums.py +++ b/worlds/oot_soh/Enums.py @@ -4147,7 +4147,7 @@ class SOHOverworldEntranceNames(StrEnum): LON_LON_RANCH_ENTRANCE = "Lon Lon Ranch Entrance" HYRULE_FIELD_CENTER_EXIT = "Hyrule Field Center Exit" ZORAS_DOMAIN_UNDERWATER_SHORTCUT = "Zoras Domain Underwater Shortcut" - LAKE_HYLIA_UNDERWATER_SHORTCUT = "Lakey Hylia Underwater Shortcut" + LAKE_HYLIA_UNDERWATER_SHORTCUT = "Lake Hylia Underwater Shortcut" GERUDOS_FORTRESS_EAST_EXIT = "Gerudos Fortress East Exit" GERUDO_VALLEY_WEST_EXIT = "Gerudo Valley West Exit" HAUNTED_WASTELAND_EAST_EXIT = "Haunted Wasteland East Exit" diff --git a/worlds/oot_soh/__init__.py b/worlds/oot_soh/__init__.py index ef7e54af13d7..860b97ababf4 100644 --- a/worlds/oot_soh/__init__.py +++ b/worlds/oot_soh/__init__.py @@ -266,7 +266,7 @@ def connect_entrances(self): # Overworld Entrances if self.options.shuffle_overworld_entrances: for entranceName in SOHOverworldEntranceNames: - if not self.options.decouple_entrances and entranceName == SOHOverworldEntranceNames.LAKE_HYLIA_RIVER_ENTRANCE: + if not self.options.decouple_entrances and sum(map(bool, [self.options.shuffle_grotto_entrances, self.options.shuffle_interior_entrances, self.options.shuffle_dungeon_entrances, True if self.options.shuffle_boss_entrances == "full" else False])) >= 1 and entranceName == SOHOverworldEntranceNames.LAKE_HYLIA_RIVER_ENTRANCE: continue # ignore our one way exit here diff --git a/worlds/oot_soh/location_access/overworld/castle_grounds.py b/worlds/oot_soh/location_access/overworld/castle_grounds.py index fb5f834d5e05..3e55a4e72f34 100644 --- a/worlds/oot_soh/location_access/overworld/castle_grounds.py +++ b/worlds/oot_soh/location_access/overworld/castle_grounds.py @@ -23,7 +23,7 @@ def set_region_rules(world: "SohWorld") -> None: # Castle Grounds # Connections connect_regions(Regions.CASTLE_GROUNDS, world, [ - (Regions.MARKET, lambda bundle: True, SOHOverworldEntranceNames.CASTLE_GROUNDS_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.MARKET, lambda bundle: True, SOHOverworldEntranceNames.CASTLE_GROUNDS_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.HYRULE_CASTLE_GROUNDS, lambda bundle: is_child(bundle)), (Regions.GANONS_CASTLE_GROUNDS, lambda bundle: is_adult(bundle)) ]) diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py index 02652d9c3acf..579ea22671d0 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_crater.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_crater.py @@ -23,7 +23,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.DMC_UPPER_NEARBY, world, [ (Regions.DMC_UPPER_LOCAL, lambda bundle: fire_timer(bundle) >= 48), - (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_CRATER_UPPER_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_CRATER_UPPER_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.DMC_UPPER_GROTTO, lambda bundle: blast_or_smash( bundle) and (fire_timer(bundle) >= 8 or hearts(bundle) >= 3), SOHGrottoEntranceNames.DMC_UPPER_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) @@ -83,7 +83,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.DMC_LOWER_NEARBY, world, [ (Regions.DMC_LOWER_LOCAL, lambda bundle: fire_timer(bundle) >= 48), - (Regions.GC_DARUNIAS_CHAMBER, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_TRAIL_GC_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.GC_DARUNIAS_CHAMBER, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_TRAIL_GC_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.DMC_GREAT_FAIRY_FOUNTAIN, lambda bundle: can_use(Items.MEGATON_HAMMER, bundle), SOHInteriorEntranceNames.DMC_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), (Regions.DMC_HAMMER_GROTTO, lambda bundle: is_adult( diff --git a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py index 3591b2ecd823..6de0c7a5344b 100644 --- a/worlds/oot_soh/location_access/overworld/death_mountain_trail.py +++ b/worlds/oot_soh/location_access/overworld/death_mountain_trail.py @@ -62,8 +62,8 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.DEATH_MOUNTAIN_TRAIL, world, [ - (Regions.KAK_BEHIND_GATE, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_TRAIL_BOTTOM_EXIT, SOHEntranceGroups.OVERWORLD), - (Regions.GORON_CITY, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_CRATER_GC_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.KAK_BEHIND_GATE, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_TRAIL_BOTTOM_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.GORON_CITY, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_CRATER_GC_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.DEATH_MOUNTAIN_SUMMIT, lambda bundle: blast_or_smash(bundle) or (is_adult(bundle) and ((has_item(LocalEvents.DMT_BEAN_PLANTED, bundle) and has_item(Items.GORONS_BRACELET, bundle)) or (can_use(Items.HOVER_BOOTS, bundle) and can_do_trick(Tricks.DMT_CLIMB_HOVERS, bundle))))), (Regions.DODONGOS_CAVERN_ENTRYWAY, lambda bundle: has_explosives(bundle) or has_item(Items.GORONS_BRACELET, bundle) or is_adult( @@ -96,7 +96,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.DEATH_MOUNTAIN_SUMMIT, world, [ (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True), - (Regions.DMC_UPPER_LOCAL, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_TRAIL_SUMMIT_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.DMC_UPPER_LOCAL, lambda bundle: True, SOHOverworldEntranceNames.DEATH_MOUNTAIN_TRAIL_SUMMIT_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.DMT_OWL_FLIGHT, lambda bundle: is_child(bundle)), (Regions.DMT_COW_GROTTO, lambda bundle: blast_or_smash(bundle), SOHGrottoEntranceNames.DMT_COW_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.DMT_GREAT_FAIRY_FOUNTAIN, lambda bundle: blast_or_smash(bundle), SOHInteriorEntranceNames.DMT_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) diff --git a/worlds/oot_soh/location_access/overworld/desert_colossus.py b/worlds/oot_soh/location_access/overworld/desert_colossus.py index 549b69857d77..76cfeff6b9dd 100644 --- a/worlds/oot_soh/location_access/overworld/desert_colossus.py +++ b/worlds/oot_soh/location_access/overworld/desert_colossus.py @@ -62,7 +62,7 @@ def set_region_rules(world: "SohWorld") -> None: lambda bundle: has_explosives(bundle), SOHInteriorEntranceNames.COLOSSUS_GREAT_FAIRY_FOUNTAIN_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.SPIRIT_TEMPLE_ENTRYWAY, lambda bundle: True, SOHDungeonEntranceNames.SPIRIT_TEMPLE_DUNGEON_ENTRNACE, SOHEntranceGroups.DUNGEON_ENTRANCE | SOHEntranceGroups.ANY_AGE, EntranceType.TWO_WAY), - (Regions.WASTELAND_NEAR_COLOSSUS, lambda bundle: True, SOHOverworldEntranceNames.DESERT_COLOSSUS_EAST_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.WASTELAND_NEAR_COLOSSUS, lambda bundle: True, SOHOverworldEntranceNames.DESERT_COLOSSUS_EAST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.ANY_AGE), (Regions.COLOSSUS_GROTTO, lambda bundle: can_use( Items.SILVER_GAUNTLETS, bundle), SOHGrottoEntranceNames.COLOSSUS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY) ]) diff --git a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py index aa2791a25d81..9439bac3d074 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_fortress.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_fortress.py @@ -33,7 +33,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GERUDO_FORTRESS_OUTSKIRTS, world, [ - (Regions.GV_FORTRESS_SIDE, lambda bundle: True, SOHOverworldEntranceNames.GERUDOS_FORTRESS_EAST_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.GV_FORTRESS_SIDE, lambda bundle: True, SOHOverworldEntranceNames.GERUDOS_FORTRESS_EAST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.ADULT), (Regions.THIEVES_HIDEOUT_1_TORCH_CELL, lambda bundle: True, SOHThievesHideoutEntranceNames.THIEVES_HIDEOUT_0, int(SOHEntranceGroups.THIEVES_HIDEOUT_ENTRANCE)), (Regions.GF_OUTSIDE_GATE, lambda bundle: has_item( LocalEvents.GF_GATE_OPEN, bundle)), @@ -335,7 +335,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.GF_OUTSIDE_GATE, world, [ (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: has_item( LocalEvents.GF_GATE_OPEN, bundle)), - (Regions.WASTELAND_NEAR_FORTRESS, lambda bundle: True, SOHOverworldEntranceNames.GERUDOS_FORTRESS_GATE_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.WASTELAND_NEAR_FORTRESS, lambda bundle: True, SOHOverworldEntranceNames.GERUDOS_FORTRESS_GATE_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), ]) # GF Storms Grotto diff --git a/worlds/oot_soh/location_access/overworld/gerudo_valley.py b/worlds/oot_soh/location_access/overworld/gerudo_valley.py index a02357ce5952..680b79736cfd 100644 --- a/worlds/oot_soh/location_access/overworld/gerudo_valley.py +++ b/worlds/oot_soh/location_access/overworld/gerudo_valley.py @@ -35,7 +35,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connection connect_regions(Regions.GERUDO_VALLEY, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.GERUDO_VALLEY_EAST_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.GERUDO_VALLEY_EAST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.GV_UPPER_STREAM, lambda bundle: is_child(bundle) or has_item(Items.BRONZE_SCALE, bundle) or take_damage(bundle)), (Regions.GV_CRATE_LEDGE, lambda bundle: is_child( @@ -44,7 +44,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GV_FORTRESS_SIDE, lambda bundle: (is_adult(bundle) and ( can_use(Items.EPONA, bundle) or can_use(Items.LONGSHOT, bundle) or world.options.fortress_carpenters.value == 2 or has_item( - Events.RESCUED_ALL_CARPENTERS, bundle))) or (is_child(bundle) and can_use(Items.HOOKSHOT, bundle)), SOHOverworldEntranceNames.GERUDO_VALLEY_WEST_EXIT, SOHEntranceGroups.OVERWORLD), + Events.RESCUED_ALL_CARPENTERS, bundle))) or (is_child(bundle) and can_use(Items.HOOKSHOT, bundle))), (Regions.GV_LOWER_STREAM, lambda bundle: is_child(bundle)) ]) @@ -91,7 +91,7 @@ def set_region_rules(world: "SohWorld") -> None: # GV Lower Stream # Connections connect_regions(Regions.GV_LOWER_STREAM, world, [ - (Regions.LAKE_HYLIA, lambda bundle: True, SOHOverworldEntranceNames.LAKE_HYLIA_RIVER_ENTRANCE, SOHEntranceGroups.OVERWORLD, EntranceType.ONE_WAY) + (Regions.LAKE_HYLIA, lambda bundle: True, SOHOverworldEntranceNames.LAKE_HYLIA_RIVER_ENTRANCE, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.ANY_AGE, EntranceType.ONE_WAY) ]) # GV Grotto Ledge @@ -144,7 +144,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GV_FORTRESS_SIDE, world, [ - (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True), + (Regions.GERUDO_FORTRESS_OUTSKIRTS, lambda bundle: True, SOHOverworldEntranceNames.GERUDO_VALLEY_WEST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.GV_UPPER_STREAM, lambda bundle: True), (Regions.GERUDO_VALLEY, lambda bundle: is_child(bundle) or can_use(Items.EPONA, bundle) or can_use(Items.LONGSHOT, diff --git a/worlds/oot_soh/location_access/overworld/goron_city.py b/worlds/oot_soh/location_access/overworld/goron_city.py index c49e4390b092..0ead4920ea02 100644 --- a/worlds/oot_soh/location_access/overworld/goron_city.py +++ b/worlds/oot_soh/location_access/overworld/goron_city.py @@ -76,7 +76,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.GORON_CITY, world, [ - (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True, SOHOverworldEntranceNames.GORON_CITY_UPPER_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.DEATH_MOUNTAIN_TRAIL, lambda bundle: True, SOHOverworldEntranceNames.GORON_CITY_UPPER_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.GC_MEDIGORON, lambda bundle: can_break_mud_walls( bundle) or has_item(Items.GORONS_BRACELET, bundle)), (Regions.GC_WOODS_WARP, lambda bundle: has_item( @@ -113,7 +113,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.GC_WOODS_WARP, world, [ (Regions.GORON_CITY, lambda bundle: has_item( LocalEvents.GC_WOODS_WARP_OPEN, bundle)), - (Regions.LOST_WOODS, lambda bundle: True, SOHOverworldEntranceNames.GORON_CITY_TUNNEL_SHORTCUT, SOHEntranceGroups.OVERWORLD) + (Regions.LOST_WOODS, lambda bundle: True, SOHOverworldEntranceNames.GORON_CITY_TUNNEL_SHORTCUT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE) ]) # Goron City Darunias Chamber @@ -133,7 +133,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.GC_DARUNIAS_CHAMBER, world, [ (Regions.GORON_CITY, lambda bundle: True), - (Regions.DMC_LOWER_LOCAL, lambda bundle: is_adult(bundle), SOHOverworldEntranceNames.GORON_CITY_DARUNIA_ROOM_EXIT, SOHEntranceGroups.OVERWORLD) + (Regions.DMC_LOWER_LOCAL, lambda bundle: is_adult(bundle), SOHOverworldEntranceNames.GORON_CITY_DARUNIA_ROOM_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE) ]) # Goron City Grotto Platform diff --git a/worlds/oot_soh/location_access/overworld/graveyard.py b/worlds/oot_soh/location_access/overworld/graveyard.py index 6a8334689a3d..476abfa766a2 100644 --- a/worlds/oot_soh/location_access/overworld/graveyard.py +++ b/worlds/oot_soh/location_access/overworld/graveyard.py @@ -78,7 +78,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.GRAVEYARD_DAMPES_GRAVE, lambda bundle: is_adult(bundle), SOHGrottoEntranceNames.GRAVEYARD_DAMPES_GRAVE_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ADULT_ONLY), (Regions.GRAVEYARD_DAMPES_HOUSE, lambda bundle: is_adult(bundle) and can_open_overworld_door(Items.DAMPES_HUT_KEY, bundle), SOHInteriorEntranceNames.GRAVEYARD_DAMPES_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ADULT_ONLY), - (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHOverworldEntranceNames.GRAVEYARD_ENTRANCE, SOHEntranceGroups.OVERWORLD), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHOverworldEntranceNames.GRAVEYARD_ENTRANCE, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.GRAVEYARD_WARP_PAD_REGION, lambda bundle: False) ]) diff --git a/worlds/oot_soh/location_access/overworld/haunted_wasteland.py b/worlds/oot_soh/location_access/overworld/haunted_wasteland.py index 79c9e0888d82..95c02dbd596a 100644 --- a/worlds/oot_soh/location_access/overworld/haunted_wasteland.py +++ b/worlds/oot_soh/location_access/overworld/haunted_wasteland.py @@ -19,7 +19,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.WASTELAND_NEAR_FORTRESS, world, [ - (Regions.GF_OUTSIDE_GATE, lambda bundle: True, SOHOverworldEntranceNames.HAUNTED_WASTELAND_EAST_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.GF_OUTSIDE_GATE, lambda bundle: True, SOHOverworldEntranceNames.HAUNTED_WASTELAND_EAST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.HAUNTED_WASTELAND, lambda bundle: can_use_any( [Items.HOVER_BOOTS, Items.LONGSHOT], bundle) or can_do_trick(Tricks.HW_CROSSING, bundle)) ]) @@ -70,7 +70,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.WASTELAND_NEAR_COLOSSUS, world, [ - (Regions.DESERT_COLOSSUS, lambda bundle: True, SOHOverworldEntranceNames.HAUNTED_WASTELAND_WEST_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.DESERT_COLOSSUS, lambda bundle: True, SOHOverworldEntranceNames.HAUNTED_WASTELAND_WEST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.HAUNTED_WASTELAND, lambda bundle: can_do_trick( Tricks.HW_REVERSE, bundle)) ]) diff --git a/worlds/oot_soh/location_access/overworld/hyrule_field.py b/worlds/oot_soh/location_access/overworld/hyrule_field.py index 761f92a9bf7c..e76eefe4957d 100644 --- a/worlds/oot_soh/location_access/overworld/hyrule_field.py +++ b/worlds/oot_soh/location_access/overworld/hyrule_field.py @@ -173,13 +173,13 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.HYRULE_FIELD, world, [ - (Regions.LW_BRIDGE, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_WOODED_EXIT, SOHEntranceGroups.OVERWORLD), - (Regions.LAKE_HYLIA, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_FENCE_EXIT, SOHEntranceGroups.OVERWORLD), - (Regions.GERUDO_VALLEY, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_ROCKY_PATH, SOHEntranceGroups.OVERWORLD), - (Regions.MARKET_ENTRANCE, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_ON_BRIDGE_SPAWN, SOHEntranceGroups.OVERWORLD), - (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_STAIRS_EXIT, SOHEntranceGroups.OVERWORLD), - (Regions.ZR_FRONT, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_RIVER_EXIT, SOHEntranceGroups.OVERWORLD), - (Regions.LON_LON_RANCH, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_CENTER_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.LW_BRIDGE, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_WOODED_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.LAKE_HYLIA, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_FENCE_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.GERUDO_VALLEY, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_ROCKY_PATH, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.MARKET_ENTRANCE, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_ON_BRIDGE_SPAWN, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.KAKARIKO_VILLAGE, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_STAIRS_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.ZR_FRONT, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_RIVER_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.LON_LON_RANCH, lambda bundle: True, SOHOverworldEntranceNames.HYRULE_FIELD_CENTER_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.HF_SOUTHEAST_GROTTO, lambda bundle: (blast_or_smash(bundle)), SOHGrottoEntranceNames.HF_SOUTHEAST_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.HF_OPEN_GROTTO, lambda bundle: True, SOHGrottoEntranceNames.HF_OPEN_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.HF_INSIDE_FENCE_GROTTO, lambda bundle: ( diff --git a/worlds/oot_soh/location_access/overworld/kakariko.py b/worlds/oot_soh/location_access/overworld/kakariko.py index 88d8b1f61cac..34b4e4713edb 100644 --- a/worlds/oot_soh/location_access/overworld/kakariko.py +++ b/worlds/oot_soh/location_access/overworld/kakariko.py @@ -122,7 +122,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.KAKARIKO_VILLAGE, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.KAKARIKO_VILLAGE_FRONT_GATE, SOHEntranceGroups.OVERWORLD), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.KAKARIKO_VILLAGE_FRONT_GATE, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.KAK_CARPENTER_BOSS_HOUSE, lambda bundle: can_open_overworld_door(Items.BOSS_HOUSE_KEY, bundle), SOHInteriorEntranceNames.KAK_CARPENTER_BOSS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.KAK_HOUSE_OF_SKULLTULA, lambda bundle: can_open_overworld_door( @@ -157,7 +157,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.KAK_IMPAS_ROOFTOP, lambda bundle: can_use(Items.HOOKSHOT, bundle) or can_do_trick(Tricks.KAK_ROOFTOP_GS, bundle) and can_use( Items.HOVER_BOOTS, bundle)), - (Regions.THE_GRAVEYARD, lambda bundle: True, SOHOverworldEntranceNames.KAKARIKO_VILLAGE_SOUTHEAST_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.THE_GRAVEYARD, lambda bundle: True, SOHOverworldEntranceNames.KAKARIKO_VILLAGE_SOUTHEAST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.KAK_BEHIND_GATE, lambda bundle: is_adult(bundle) or has_item(Events.KAKARIKO_GATE_OPEN, bundle)), (Regions.KAK_BACKYARD, lambda bundle: is_adult(bundle) or at_day(bundle)), @@ -423,7 +423,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.KAKARIKO_VILLAGE, lambda bundle: is_adult(bundle) or has_item(Events.KAKARIKO_GATE_OPEN, bundle) or can_do_trick( Tricks.VISIBLE_COLLISION, bundle)), - (Regions.DEATH_MOUNTAIN, lambda bundle: True, SOHOverworldEntranceNames.KAKARIKO_VILLAGE_GUARD_GATE, SOHEntranceGroups.OVERWORLD) + (Regions.DEATH_MOUNTAIN, lambda bundle: True, SOHOverworldEntranceNames.KAKARIKO_VILLAGE_GUARD_GATE, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE) ]) # Kak Well diff --git a/worlds/oot_soh/location_access/overworld/kokiri_forest.py b/worlds/oot_soh/location_access/overworld/kokiri_forest.py index 08efcc7b322f..cb2fdfb35c3f 100644 --- a/worlds/oot_soh/location_access/overworld/kokiri_forest.py +++ b/worlds/oot_soh/location_access/overworld/kokiri_forest.py @@ -179,9 +179,9 @@ def set_region_rules(world: "SohWorld") -> None: or (is_child(bundle) and has_item(LocalEvents.MIDO_SWORD_AND_SHIELD, bundle)) # Todo, maybe create a helper for handling settings or world.options.closed_forest.value == 2), - (Regions.LOST_WOODS, lambda bundle: True, SOHOverworldEntranceNames.KOKIRI_FOREST_UPPER_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.LOST_WOODS, lambda bundle: True, SOHOverworldEntranceNames.KOKIRI_FOREST_UPPER_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.LW_BRIDGE_FROM_FOREST, lambda bundle: world.options.closed_forest.value >= 1 or is_adult(bundle) or - has_item(Events.DEKU_TREE_COMPLETED, bundle), SOHOverworldEntranceNames.KOKIRI_FOREST_LOWER_EXIT, SOHEntranceGroups.OVERWORLD), + has_item(Events.DEKU_TREE_COMPLETED, bundle), SOHOverworldEntranceNames.KOKIRI_FOREST_LOWER_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.KF_STORMS_GROTTO, lambda bundle: can_open_storms_grotto(bundle), SOHGrottoEntranceNames.KF_STORMS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/lake_hylia.py b/worlds/oot_soh/location_access/overworld/lake_hylia.py index bf8365042a12..1370bcb80043 100644 --- a/worlds/oot_soh/location_access/overworld/lake_hylia.py +++ b/worlds/oot_soh/location_access/overworld/lake_hylia.py @@ -155,7 +155,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LAKE_HYLIA, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.LAKE_HYLIA_NORTH_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.LAKE_HYLIA_NORTH_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.LH_FROM_SHORTCUT, lambda bundle: True), (Regions.LH_OWL_FLIGHT, lambda bundle: is_child(bundle)), (Regions.LH_FISHING_ISLAND, lambda bundle: ((is_child(bundle) @@ -179,7 +179,7 @@ def set_region_rules(world: "SohWorld") -> None: can_use(Items.IRON_BOOTS, bundle)), (Regions.ZORAS_DOMAIN, lambda bundle: is_child(bundle) and (has_item(Items.SILVER_SCALE, bundle) or - can_use(Items.IRON_BOOTS, bundle)), SOHOverworldEntranceNames.LAKE_HYLIA_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD), + can_use(Items.IRON_BOOTS, bundle)), SOHOverworldEntranceNames.LAKE_HYLIA_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.CHILD_ONLY), ]) # LH from Water Temple diff --git a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py index 99b79160daad..eb653de113d2 100644 --- a/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py +++ b/worlds/oot_soh/location_access/overworld/lon_lon_ranch.py @@ -51,7 +51,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.LON_LON_RANCH, world, [ - (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.LON_LON_RANCH_ENTRANCE, SOHEntranceGroups.OVERWORLD), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.LON_LON_RANCH_ENTRANCE, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.LLR_TALONS_HOUSE, lambda bundle: can_open_overworld_door( Items.TALONS_HOUSE_KEY, bundle), SOHInteriorEntranceNames.LLR_TALONS_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE), (Regions.LLR_STABLES, lambda bundle: can_open_overworld_door( diff --git a/worlds/oot_soh/location_access/overworld/lost_woods.py b/worlds/oot_soh/location_access/overworld/lost_woods.py index c6d237545c02..263e815ecc56 100644 --- a/worlds/oot_soh/location_access/overworld/lost_woods.py +++ b/worlds/oot_soh/location_access/overworld/lost_woods.py @@ -27,7 +27,7 @@ def set_region_rules(world: "SohWorld") -> None: # LW Forest Exit # Connections connect_regions(Regions.LW_FOREST_EXIT, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), ]) # Lost Woods @@ -101,7 +101,7 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.LOST_WOODS, world, [ (Regions.LW_FOREST_EXIT, lambda bundle: True), - (Regions.GC_WOODS_WARP, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_TUNNEL_SHORTCUT, SOHEntranceGroups.OVERWORLD), + (Regions.GC_WOODS_WARP, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_TUNNEL_SHORTCUT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.LW_BRIDGE, lambda bundle: (is_adult(bundle) and ( has_item(LocalEvents.LW_BRIDGE_BEAN_PLANTED, bundle) or can_do_trick(Tricks.LW_BRIDGE, bundle))) or can_use(Items.HOVER_BOOTS, bundle) or can_use( @@ -109,7 +109,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.ZR_FROM_SHORTCUT, lambda bundle: has_item(Items.SILVER_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle) or (can_do_trick( Tricks.LOST_WOOD_NAVI_DIVE, bundle) and is_child(bundle) and has_item(Items.BRONZE_SCALE, - bundle) and can_jump_slash(bundle)), SOHOverworldEntranceNames.LOST_WOODS_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD), + bundle) and can_jump_slash(bundle)), SOHOverworldEntranceNames.LOST_WOODS_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.LW_BEYOND_MIDO, lambda bundle: is_child(bundle) or can_use(Items.SARIAS_SONG, bundle) or can_do_trick(Tricks.LW_MIDO_BACKFLIP, bundle)), @@ -160,7 +160,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.LW_FOREST_EXIT, lambda bundle: True), (Regions.LOST_WOODS, lambda bundle: is_child( bundle) or can_use(Items.SARIAS_SONG, bundle)), - (Regions.SFM_ENTRYWAY, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_NORTH_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.SFM_ENTRYWAY, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_NORTH_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.DEKU_THEATER, lambda bundle: True, SOHGrottoEntranceNames.DEKU_THEATER_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), (Regions.LW_SCRUBS_GROTTO, lambda bundle: blast_or_smash(bundle), SOHGrottoEntranceNames.LW_SCRUBS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) @@ -233,20 +233,24 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.LW_BEYOND_MIDO, lambda bundle: True, SOHGrottoExitNames.LW_SCRUBS_GROTTO_EXIT, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), ]) - # LW Bridge From Forest + # # LW Bridge From Forest + # # Location + # add_locations(Regions.LW_BRIDGE_FROM_FOREST, world, [ + # (Locations.LW_GIFT_FROM_SARIA, lambda bundle: True) + # ]) + # # Connections + # connect_regions(Regions.LW_BRIDGE_FROM_FOREST, world, [ + # (Regions.LW_BRIDGE, lambda bundle: True), + # ]) + + # LW Bridge # Location - add_locations(Regions.LW_BRIDGE_FROM_FOREST, world, [ + add_locations(Regions.LW_BRIDGE, world, [ (Locations.LW_GIFT_FROM_SARIA, lambda bundle: True) ]) # Connections - connect_regions(Regions.LW_BRIDGE_FROM_FOREST, world, [ - (Regions.LW_BRIDGE, lambda bundle: True), - ]) - - # LW Bridge - # Connections connect_regions(Regions.LW_BRIDGE, world, [ - (Regions.KOKIRI_FOREST, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_BRIDGE_EAST_EXIT, SOHEntranceGroups.OVERWORLD), - (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_BRIDGE_WEST_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.KOKIRI_FOREST, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_BRIDGE_EAST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.LOST_WOODS_BRIDGE_WEST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.LOST_WOODS, lambda bundle: can_use(Items.LONGSHOT, bundle)) ]) diff --git a/worlds/oot_soh/location_access/overworld/market.py b/worlds/oot_soh/location_access/overworld/market.py index 9e5e82c6b736..e91f601ffe52 100644 --- a/worlds/oot_soh/location_access/overworld/market.py +++ b/worlds/oot_soh/location_access/overworld/market.py @@ -19,8 +19,8 @@ def set_region_rules(world: "SohWorld") -> None: # Connections connect_regions(Regions.MARKET_ENTRANCE, world, [ (Regions.HYRULE_FIELD, lambda bundle: ( - is_adult(bundle) or at_day(bundle)), SOHOverworldEntranceNames.MARKET_ENTRANCE_NEAR_GUARD_EXIT, SOHEntranceGroups.OVERWORLD), - (Regions.MARKET, lambda bundle: True, SOHOverworldEntranceNames.MARKET_ENTRANCE_NORTH_EXIT, SOHEntranceGroups.OVERWORLD), + is_adult(bundle) or at_day(bundle)), SOHOverworldEntranceNames.MARKET_ENTRANCE_NEAR_GUARD_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.MARKET, lambda bundle: True, SOHOverworldEntranceNames.MARKET_ENTRANCE_NORTH_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.MARKET_GUARD_HOUSE, lambda bundle: can_open_overworld_door( Items.GUARD_HOUSE_KEY, bundle), SOHInteriorEntranceNames.MARKET_GUARD_HOUSE_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) @@ -55,9 +55,9 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.MARKET, world, [ - (Regions.MARKET_ENTRANCE, lambda bundle: True, SOHOverworldEntranceNames.MARKET_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD), - (Regions.TOT_ENTRANCE, lambda bundle: True, SOHOverworldEntranceNames.MARKET_DAY_TEMPLE_EXIT, SOHEntranceGroups.OVERWORLD), - (Regions.CASTLE_GROUNDS, lambda bundle: True, SOHOverworldEntranceNames.MARKET_DAY_CASTLE_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.MARKET_ENTRANCE, lambda bundle: True, SOHOverworldEntranceNames.MARKET_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.TOT_ENTRANCE, lambda bundle: True, SOHOverworldEntranceNames.MARKET_DAY_TEMPLE_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), + (Regions.CASTLE_GROUNDS, lambda bundle: True, SOHOverworldEntranceNames.MARKET_DAY_CASTLE_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.MARKET_BAZAAR, lambda bundle: (is_child(bundle) and at_day( bundle) and can_open_overworld_door(Items.MARKET_BAZAAR_KEY, bundle)), SOHInteriorEntranceNames.MARKET_BAZAAR_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.CHILD_ONLY), (Regions.MARKET_MASK_SHOP, lambda bundle: (is_child(bundle) and at_day( diff --git a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py index 7c6e9cd157c2..9f5791fa4a2f 100644 --- a/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py +++ b/worlds/oot_soh/location_access/overworld/sacred_forest_meadow.py @@ -13,7 +13,7 @@ def set_region_rules(world: "SohWorld") -> None: # SFM Entryway # Connections connect_regions(Regions.SFM_ENTRYWAY, world, [ - (Regions.LW_BEYOND_MIDO, lambda bundle: True, SOHOverworldEntranceNames.SACRED_FOREST_MEADOW_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.LW_BEYOND_MIDO, lambda bundle: True, SOHOverworldEntranceNames.SACRED_FOREST_MEADOW_SOUTH_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.SACRED_FOREST_MEADOW, lambda bundle: is_adult( bundle) or can_kill_enemy(bundle, Enemies.WOLFOS)), (Regions.SFM_WOLFOS_GROTTO, lambda bundle: can_open_bomb_grotto(bundle), SOHGrottoEntranceNames.SFM_WOLFOS_GROTTO_ENTRANCE, SOHEntranceGroups.GROTTO | SOHEntranceGroups.ANY_AGE), diff --git a/worlds/oot_soh/location_access/overworld/temple_of_time.py b/worlds/oot_soh/location_access/overworld/temple_of_time.py index 1b42f50ad1ec..c3cd300d959f 100644 --- a/worlds/oot_soh/location_access/overworld/temple_of_time.py +++ b/worlds/oot_soh/location_access/overworld/temple_of_time.py @@ -37,7 +37,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.TOT_ENTRANCE, world, [ - (Regions.MARKET, lambda bundle: True, SOHOverworldEntranceNames.TEMPLE_OF_TIME_EXTERIOR_DAY_GOSSIP_STONE_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.MARKET, lambda bundle: True, SOHOverworldEntranceNames.TEMPLE_OF_TIME_EXTERIOR_DAY_GOSSIP_STONE_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.TEMPLE_OF_TIME, lambda bundle: True, SOHSpecialInteriorEntranceNames.TEMPLE_OF_TIME_ENTRANCE, SOHEntranceGroups.INTERIOR | SOHEntranceGroups.ANY_AGE) ]) diff --git a/worlds/oot_soh/location_access/overworld/zoras_domain.py b/worlds/oot_soh/location_access/overworld/zoras_domain.py index 79982410eb92..168895c7f779 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_domain.py +++ b/worlds/oot_soh/location_access/overworld/zoras_domain.py @@ -82,9 +82,9 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZORAS_DOMAIN, world, [ - (Regions.ZR_BEHIND_WATERFALL, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_DOMAIN_ENTRANCE, SOHEntranceGroups.OVERWORLD), + (Regions.ZR_BEHIND_WATERFALL, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_DOMAIN_ENTRANCE, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.LH_FROM_SHORTCUT, lambda bundle: is_child(bundle) and ( - has_item(Items.SILVER_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle)), SOHOverworldEntranceNames.ZORAS_DOMAIN_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD), + has_item(Items.SILVER_SCALE, bundle) or can_use(Items.IRON_BOOTS, bundle)), SOHOverworldEntranceNames.ZORAS_DOMAIN_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.CHILD_ONLY), (Regions.ZD_BEHIND_KING_ZORA, lambda bundle: has_item(Events.DELIVER_LETTER, bundle) or world.options.zoras_fountain.value == 2 or ( world.options.zoras_fountain.value == 1 and is_adult(bundle)) or ( @@ -117,7 +117,7 @@ def set_region_rules(world: "SohWorld") -> None: (Regions.ZORAS_DOMAIN, lambda bundle: has_item(Events.DELIVER_LETTER, bundle) or world.options.zoras_fountain.value == 2 or ( world.options.zoras_fountain.value == 1 and is_adult(bundle))), - (Regions.ZORAS_FOUNTAIN, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_DOMAIN_KING_ZORA_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.ZORAS_FOUNTAIN, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_DOMAIN_KING_ZORA_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), ]) # ZD Shop diff --git a/worlds/oot_soh/location_access/overworld/zoras_fountain.py b/worlds/oot_soh/location_access/overworld/zoras_fountain.py index e0e66994dc02..b86492210e0c 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_fountain.py +++ b/worlds/oot_soh/location_access/overworld/zoras_fountain.py @@ -45,7 +45,7 @@ def set_region_rules(world: "SohWorld") -> None: ]) # Connections connect_regions(Regions.ZORAS_FOUNTAIN, world, [ - (Regions.ZD_BEHIND_KING_ZORA, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_FOUNTAIN_TUNNEL_EXIT, SOHEntranceGroups.OVERWORLD), + (Regions.ZD_BEHIND_KING_ZORA, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_FOUNTAIN_TUNNEL_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE), (Regions.ZF_ICEBERGS, lambda bundle: is_adult(bundle)), (Regions.ZF_LAKEBED, lambda bundle: can_use(Items.IRON_BOOTS, bundle)), (Regions.ZF_HIDDEN_CAVE, lambda bundle: can_use( diff --git a/worlds/oot_soh/location_access/overworld/zoras_river.py b/worlds/oot_soh/location_access/overworld/zoras_river.py index b45e5bdb1f73..a750fb2e9075 100644 --- a/worlds/oot_soh/location_access/overworld/zoras_river.py +++ b/worlds/oot_soh/location_access/overworld/zoras_river.py @@ -53,7 +53,7 @@ def set_region_rules(world: "SohWorld") -> None: connect_regions(Regions.ZR_FRONT, world, [ (Regions.ZORA_RIVER, lambda bundle: is_adult( bundle) or blast_or_smash(bundle)), - (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_RIVER_WEST_EXIT, SOHEntranceGroups.OVERWORLD) + (Regions.HYRULE_FIELD, lambda bundle: True, SOHOverworldEntranceNames.ZORAS_RIVER_WEST_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE) ]) # Zora River @@ -166,7 +166,7 @@ def set_region_rules(world: "SohWorld") -> None: can_do_trick(Tricks.ZR_CUCCO, bundle)) or (is_adult(bundle) and can_use(Items.HOVER_BOOTS, bundle) and - can_do_trick(Tricks.ZR_HOVERS, bundle)), SOHOverworldEntranceNames.ZORAS_RIVER_WATERFALL_EXIT, SOHEntranceGroups.OVERWORLD) + can_do_trick(Tricks.ZR_HOVERS, bundle)), SOHOverworldEntranceNames.ZORAS_RIVER_WATERFALL_EXIT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE) ]) # Events @@ -178,7 +178,7 @@ def set_region_rules(world: "SohWorld") -> None: has_item(Items.BOTTLE_WITH_FAIRY, bundle) or has_item(Items.BRONZE_SCALE, bundle)), (Regions.LOST_WOODS, lambda bundle: has_item(Items.SILVER_SCALE, bundle) or - can_use(Items.IRON_BOOTS, bundle), SOHOverworldEntranceNames.ZORAS_RIVER_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD) + can_use(Items.IRON_BOOTS, bundle), SOHOverworldEntranceNames.ZORAS_RIVER_UNDERWATER_SHORTCUT, SOHEntranceGroups.OVERWORLD | SOHEntranceGroups.BOTH_AGE) ])