From 035621e420fade50627ecf93cc7ecba048cfda6f Mon Sep 17 00:00:00 2001 From: aerinon Date: Tue, 28 Sep 2021 14:57:17 -0600 Subject: [PATCH] Rupee bow forbids certain lobbies in HC in standard Allow a lobby in keydrop shuffle Key rule fix when bk isn't possible Added controller awareness to world traversal --- BaseClasses.py | 12 +++++++++--- DoorShuffle.py | 14 +++++++++----- Doors.py | 7 +++++-- KeyDoorShuffle.py | 2 +- Main.py | 2 +- RELEASENOTES.md | 3 +++ Rules.py | 6 +++++- 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/BaseClasses.py b/BaseClasses.py index b7c13f45..58530558 100644 --- a/BaseClasses.py +++ b/BaseClasses.py @@ -559,7 +559,7 @@ class CollectionState(object): queue.append((new_entrance, new_crystal_state)) # else those connections that are not accessible yet if self.is_small_door(connection): - door = connection.door + door = connection.door if connection.door.smallKey else connection.door.controller dungeon_name = connection.parent_region.dungeon.name key_logic = self.world.key_logic[player][dungeon_name] if door.name not in self.reached_doors[player]: @@ -573,7 +573,7 @@ class CollectionState(object): checklist[connection.name] = (connection, crystal_state) elif door.name not in self.opened_doors[player]: opened_doors = self.opened_doors[player] - door = connection.door + door = connection.door if connection.door.smallKey else connection.door.controller if door.name not in opened_doors: self.door_counter[player][1][dungeon_name] += 1 opened_doors.add(door.name) @@ -956,7 +956,12 @@ class CollectionState(object): @staticmethod def is_small_door(connection): - return connection and connection.door and connection.door.smallKey + return connection and connection.door and (connection.door.smallKey or + CollectionState.is_controlled_by_small(connection)) + + @staticmethod + def is_controlled_by_small(connection): + return connection.door.controller and connection.door.controller.smallKey def is_door_open(self, door_name, player): return door_name in self.opened_doors[player] @@ -1641,6 +1646,7 @@ class Door(object): self.bk_shuffle_req = False self.standard_restricted = False # flag if portal is not allowed in HC in standard self.lw_restricted = False # flag if portal is not allowed in DW + self.rupee_bow_restricted = False # flag if portal is not allowed in HC in standard+rupee_bow # self.incognitoPos = -1 # self.sectorLink = False diff --git a/DoorShuffle.py b/DoorShuffle.py index c70cc040..917f78bd 100644 --- a/DoorShuffle.py +++ b/DoorShuffle.py @@ -368,7 +368,8 @@ def choose_portals(world, player): if world.doorShuffle[player] in ['basic', 'crossed']: cross_flag = world.doorShuffle[player] == 'crossed' - bk_shuffle = world.bigkeyshuffle[player] + # key drops allow the big key in the right place in Desert Tiles 2 + bk_shuffle = world.bigkeyshuffle[player] or world.keydropshuffle[player] std_flag = world.mode[player] == 'standard' # roast incognito doors world.get_room(0x60, player).delete(5) @@ -415,6 +416,7 @@ def choose_portals(world, player): for dungeon, info in shuffled_info: outstanding_portals = list(dungeon_portals[dungeon]) hc_flag = std_flag and dungeon == 'Hyrule Castle' + rupee_bow_flag = hc_flag and world.retro[player] # rupee bow if hc_flag: sanc = world.get_portal('Sanctuary', player) sanc.destination = True @@ -424,14 +426,14 @@ def choose_portals(world, player): info.required_passage = {x: y for x, y in info.required_passage.items() if len(y) > 0} for target_region, possible_portals in info.required_passage.items(): candidates = find_portal_candidates(master_door_list, dungeon, need_passage=True, crossed=cross_flag, - bk_shuffle=bk_shuffle) + bk_shuffle=bk_shuffle, rupee_bow=rupee_bow_flag) choice, portal = assign_portal(candidates, possible_portals, world, player) portal.destination = True clean_up_portal_assignment(portal_assignment, dungeon, portal, master_door_list, outstanding_portals) dead_end_choices = info.total - 1 - len(portal_assignment[dungeon]) for i in range(0, dead_end_choices): candidates = find_portal_candidates(master_door_list, dungeon, dead_end_allowed=True, - crossed=cross_flag, bk_shuffle=bk_shuffle) + crossed=cross_flag, bk_shuffle=bk_shuffle, rupee_bow=rupee_bow_flag) possible_portals = outstanding_portals if not info.sole_entrance else [x for x in outstanding_portals if x != info.sole_entrance] choice, portal = assign_portal(candidates, possible_portals, world, player) if choice.deadEnd: @@ -443,7 +445,7 @@ def choose_portals(world, player): the_rest = info.total - len(portal_assignment[dungeon]) for i in range(0, the_rest): candidates = find_portal_candidates(master_door_list, dungeon, crossed=cross_flag, - bk_shuffle=bk_shuffle, standard=hc_flag) + bk_shuffle=bk_shuffle, standard=hc_flag, rupee_bow=rupee_bow_flag) choice, portal = assign_portal(candidates, outstanding_portals, world, player) clean_up_portal_assignment(portal_assignment, dungeon, portal, master_door_list, outstanding_portals) @@ -564,7 +566,7 @@ def disconnect_portal(portal, world, player): def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allowed=False, crossed=False, - bk_shuffle=False, standard=False): + bk_shuffle=False, standard=False, rupee_bow=False): ret = [x for x in door_list if bk_shuffle or not x.bk_shuffle_req] if crossed: ret = [x for x in ret if not x.dungeonLink or x.dungeonLink == dungeon or x.dungeonLink.startswith('link')] @@ -576,6 +578,8 @@ def find_portal_candidates(door_list, dungeon, need_passage=False, dead_end_allo ret = [x for x in ret if not x.deadEnd] if standard: ret = [x for x in ret if not x.standard_restricted] + if rupee_bow: + ret = [x for x in ret if not x.rupee_bow_restricted] return ret diff --git a/Doors.py b/Doors.py index b0979a5d..a23f46f0 100644 --- a/Doors.py +++ b/Doors.py @@ -1490,8 +1490,11 @@ def create_doors(world, player): world.get_door('GT Petting Zoo SE', player).dead_end() world.get_door('GT DMs Room SW', player).dead_end() world.get_door("GT Bob\'s Room SE", player).passage = False - world.get_door('Desert Tiles 2 SE', player).bk_shuffle_req = True # key-drop note (todo) - world.get_door('Swamp Lobby S', player).standard_restricted = True # key-drop note (todo) + world.get_door('Desert Tiles 2 SE', player).bk_shuffle_req = True # key-drop note: allows this to be a portal + world.get_door('Swamp Lobby S', player).standard_restricted = True + world.get_door('PoD Mimics 2 SW', player).rupee_bow_restricted = True # bow statue + # enemizer logic could get rid of the following restriction + world.get_door('PoD Pit Room S', player).rupee_bow_restricted = True # so mimics 1 shouldn't be required # can't unlink from boss right now world.get_door('Hera Lobby S', player).dungeonLink = 'Tower of Hera' diff --git a/KeyDoorShuffle.py b/KeyDoorShuffle.py index a84fe5e8..945ad601 100644 --- a/KeyDoorShuffle.py +++ b/KeyDoorShuffle.py @@ -171,7 +171,7 @@ class PlacementRule(object): if loc.item and loc.item.bigkey: bk_blocked = True break - else: + elif len(self.check_locations_w_bk) > self.needed_keys_w_bk: def loc_has_bk(l): return (big_key_loc is not None and big_key_loc == l) or (l.item and l.item.bigkey) diff --git a/Main.py b/Main.py index 0db8af04..cfd79062 100644 --- a/Main.py +++ b/Main.py @@ -29,7 +29,7 @@ from Fill import sell_potions, sell_keys, balance_multiworld_progression, balanc from ItemList import generate_itempool, difficulties, fill_prizes, customize_shops from Utils import output_path, parse_player_names -__version__ = '0.5.1.2-u' +__version__ = '0.5.1.3-u' from source.classes.BabelFish import BabelFish diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 55a34c3f..dbfa2879 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -15,6 +15,9 @@ CLI: ```--bombbag``` # Bug Fixes and Notes. +* 0.5.1.3 + * Certain lobbies forbidden in standard when rupee bow is enabled + * Fixed issue with key logic * 0.5.1.2 * Allowed Blind's Cell to be shuffled anywhere if Blind is not the boss of Thieves Town * Remove unique annotation from a FastEnum that was causing problems diff --git a/Rules.py b/Rules.py index 42bfe2f2..9902347d 100644 --- a/Rules.py +++ b/Rules.py @@ -1942,7 +1942,11 @@ def add_key_logic_rules(world, player): key_logic = world.key_logic[player] for d_name, d_logic in key_logic.items(): for door_name, rule in d_logic.door_rules.items(): - add_rule(world.get_entrance(door_name, player), eval_small_key_door(door_name, d_name, player)) + door_entrance = world.get_entrance(door_name, player) + add_rule(door_entrance, eval_small_key_door(door_name, d_name, player)) + if door_entrance.door.dependents: + for dep in door_entrance.door.dependents: + add_rule(dep.entrance, eval_small_key_door(door_name, d_name, player)) for location in d_logic.bk_restricted: if not location.forced_item: forbid_item(location, d_logic.bk_name, player)