diff --git a/Main.py b/Main.py index 9bf886a2..9a507e85 100644 --- a/Main.py +++ b/Main.py @@ -719,9 +719,9 @@ def create_playthrough(world): collection_spheres.append(sphere) - logging.getLogger('').debug('Calculated final sphere %i, containing %i of %i progress items.', len(collection_spheres), len(sphere), len(required_locations)) + logging.debug('Calculated final sphere %i, containing %i of %i progress items.', len(collection_spheres), len(sphere), len(required_locations)) if not sphere: - raise RuntimeError('Not all required items reachable. Something went terribly wrong here.') + raise RuntimeError(f'Not all required items reachable. Unreachable locations: {required_locations}') def flist_to_iter(node): while node: diff --git a/MultiClient.py b/MultiClient.py index d75116df..8f4c6b49 100644 --- a/MultiClient.py +++ b/MultiClient.py @@ -32,6 +32,7 @@ import WebUI from worlds.alttp import Regions, Shops from worlds.alttp import Items +from worlds import network_data_package import Utils # logging note: @@ -86,8 +87,9 @@ class Context(): self.slot = None self.player_names: typing.Dict[int: str] = {} self.locations_recognized = set() - self.locations_checked = set() - self.locations_scouted = set() + # these should probably track IDs where possible + self.locations_checked:typing.Set[str] = set() + self.locations_scouted:typing.Set[str] = set() self.items_received = [] self.items_missing = [] self.items_checked = None @@ -99,8 +101,28 @@ class Context(): self.found_items = found_items self.finished_game = False self.slow_mode = False - self.jsontotextparser = JSONtoTextParser(self) + self.set_getters(network_data_package) + + def set_getters(self, data_package: dict, network=False): + if not network: + local_package = Utils.persistent_load().get("datapackage", {}).get("latest", {}) + if local_package and local_package["version"] > network_data_package["version"]: + data_package: dict = local_package + elif network and data_package["version"] > network_data_package["version"]: + Utils.persistent_store("datapackage", "latest", network_data_package) + + item_lookup: dict = data_package["lookup_any_item_id_to_name"] + locations_lookup: dict = data_package["lookup_any_location_id_to_name"] + + def get_item_name_from_id(code: int): + return item_lookup.get(code, f'Unknown item (ID:{code})') + self.item_name_getter = get_item_name_from_id + + def get_location_name_from_address(address: int): + return locations_lookup.get(address, f'Unknown location (ID:{address})') + self.location_name_getter = get_location_name_from_address + @property def endpoints(self): @@ -794,19 +816,6 @@ async def server_autoreconnect(ctx: Context): ctx.server_task = asyncio.create_task(server_loop(ctx)) -missing_unknown = re.compile("Unknown Location ID: (?P\d+)") - - -def convert_unknown_missing(missing_items: list) -> list: - missing = [] - for location in missing_items: - match = missing_unknown.match(location) - if match: - missing.append(Regions.lookup_id_to_name.get(int(match['ID']), location)) - else: - missing.append(location) - return missing - async def process_server_cmd(ctx: Context, args: dict): try: @@ -846,8 +855,13 @@ async def process_server_cmd(ctx: Context, args: dict): logger.info(f' Team #{team + 1}') current_team = team logger.info(' %s (Player %d)' % (name, slot)) + if args["datapackage_version"] > network_data_package["version"]: + await ctx.send_msgs([{"cmd": "GetDataPackage"}]) await server_auth(ctx, args['password']) + elif cmd == 'DataPackage': + ctx.set_getters(args['data'], network=True) + elif cmd == 'ConnectionRefused': errors = args["errors"] if 'InvalidSlot' in errors: @@ -913,7 +927,7 @@ async def process_server_cmd(ctx: Context, args: dict): for item, location, player in args['locations']: if location not in ctx.locations_info: replacements = {0xA2: 'Small Key', 0x9D: 'Big Key', 0x8D: 'Compass', 0x7D: 'Map'} - item_name = replacements.get(item, get_item_name_from_id(item)) + item_name = replacements.get(item, ctx.item_name_getter(item)) logger.info( f"Saw {color(item_name, 'red', 'bold')} at {list(Regions.location_table.keys())[location - 1]}") ctx.locations_info[location] = (item, player) @@ -923,32 +937,32 @@ async def process_server_cmd(ctx: Context, args: dict): found = NetworkItem(*args["item"]) receiving_player = args["receiver"] ctx.ui_node.notify_item_sent(ctx.player_names[found.player], ctx.player_names[receiving_player], - get_item_name_from_id(found.item), get_location_name_from_address(found.location), + ctx.item_name_getter(found.item), ctx.location_name_getter(found.location), found.player == ctx.slot, receiving_player == ctx.slot, - get_item_name_from_id(found.item) in Items.progression_items) - item = color(get_item_name_from_id(found.item), 'cyan' if found.player != ctx.slot else 'green') + ctx.item_name_getter(found.item) in Items.progression_items) + item = color(ctx.item_name_getter(found.item), 'cyan' if found.player != ctx.slot else 'green') found_player = color(ctx.player_names[found.player], 'yellow' if found.player != ctx.slot else 'magenta') receiving_player = color(ctx.player_names[receiving_player], 'yellow' if receiving_player != ctx.slot else 'magenta') logging.info( '%s sent %s to %s (%s)' % (found_player, item, receiving_player, - color(get_location_name_from_address(found.location), 'blue_bg', 'white'))) + color(ctx.location_name_getter(found.location), 'blue_bg', 'white'))) elif cmd == 'ItemFound': # going away found = NetworkItem(*args["item"]) - ctx.ui_node.notify_item_found(ctx.player_names[found.player], get_item_name_from_id(found.item), - get_location_name_from_address(found.location), found.player == ctx.slot, - get_item_name_from_id(found.item) in Items.progression_items) + ctx.ui_node.notify_item_found(ctx.player_names[found.player], ctx.item_name_getter(found.item), + ctx.location_name_getter(found.location), found.player == ctx.slot, + ctx.item_name_getter(found.item) in Items.progression_items) item = color_item(found.item, found.player == ctx.slot) player_sent = color(ctx.player_names[found.player], 'yellow' if found.player != ctx.slot else 'magenta') - logging.info('%s found %s (%s)' % (player_sent, item, color(get_location_name_from_address(found.location), + logging.info('%s found %s (%s)' % (player_sent, item, color(ctx.location_name_getter(found.location), 'blue_bg', 'white'))) elif cmd == 'Hint': # going away hints = [Utils.Hint(*hint) for hint in args["hints"]] for hint in hints: ctx.ui_node.send_hint(ctx.player_names[hint.finding_player], ctx.player_names[hint.receiving_player], - get_item_name_from_id(hint.item), get_location_name_from_address(hint.location), + ctx.item_name_getter(hint.item), ctx.location_name_getter(hint.location), hint.found, hint.finding_player == ctx.slot, hint.receiving_player == ctx.slot, hint.entrance if hint.entrance else None) item = color_item(hint.item, hint.found) @@ -958,7 +972,7 @@ async def process_server_cmd(ctx: Context, args: dict): 'yellow' if hint.receiving_player != ctx.slot else 'magenta') text = f"[Hint]: {player_recvd}'s {item} is " \ - f"at {color(get_location_name_from_address(hint.location), 'blue_bg', 'white')} " \ + f"at {color(ctx.location_name_getter(hint.location), 'blue_bg', 'white')} " \ f"in {player_find}'s World" if hint.entrance: text += " at " + color(hint.entrance, 'white_bg', 'black') @@ -1066,14 +1080,14 @@ class ClientCommandProcessor(CommandProcessor): """List all received items""" logger.info('Received items:') for index, item in enumerate(self.ctx.items_received, 1): - self.ctx.ui_node.notify_item_received(self.ctx.player_names[item.player], get_item_name_from_id(item.item), - get_location_name_from_address(item.location), index, + self.ctx.ui_node.notify_item_received(self.ctx.player_names[item.player], self.ctx.item_name_getter(item.item), + self.ctx.location_name_getter(item.location), index, len(self.ctx.items_received), - get_item_name_from_id(item.item) in Items.progression_items) + self.ctx.item_name_getter(item.item) in Items.progression_items) logging.info('%s from %s (%s) (%d/%d in list)' % ( - color(get_item_name_from_id(item.item), 'red', 'bold'), + color(self.ctx.item_name_getter(item.item), 'red', 'bold'), color(self.ctx.player_names[item.player], 'yellow'), - get_location_name_from_address(item.location), index, len(self.ctx.items_received))) + self.ctx.location_name_getter(item.location), index, len(self.ctx.items_received))) return True def _cmd_missing(self) -> bool: @@ -1166,7 +1180,6 @@ async def track_locations(ctx: Context, roomid, roomdata): if int(b) > 0 and my_check not in ctx.locations_checked: new_check(my_check) except Exception as e: - print(e) logger.info(f"Exception: {e}") for location, (loc_roomid, loc_mask) in location_table_uw.items(): @@ -1315,13 +1328,13 @@ async def game_watcher(ctx: Context): if recv_index < len(ctx.items_received) and recv_item == 0: item = ctx.items_received[recv_index] - ctx.ui_node.notify_item_received(ctx.player_names[item.player], get_item_name_from_id(item.item), - get_location_name_from_address(item.location), recv_index + 1, + ctx.ui_node.notify_item_received(ctx.player_names[item.player], ctx.item_name_getter(item.item), + ctx.location_name_getter(item.location), recv_index + 1, len(ctx.items_received), - get_item_name_from_id(item.item) in Items.progression_items) + ctx.item_name_getter(item.item) in Items.progression_items) logging.info('Received %s from %s (%s) (%d/%d in list)' % ( - color(get_item_name_from_id(item.item), 'red', 'bold'), color(ctx.player_names[item.player], 'yellow'), - get_location_name_from_address(item.location), recv_index + 1, len(ctx.items_received))) + color(ctx.item_name_getter(item.item), 'red', 'bold'), color(ctx.player_names[item.player], 'yellow'), + ctx.location_name_getter(item.location), recv_index + 1, len(ctx.items_received))) recv_index += 1 snes_buffered_write(ctx, RECV_PROGRESS_ADDR, bytes([recv_index & 0xFF, (recv_index >> 8) & 0xFF])) snes_buffered_write(ctx, RECV_ITEM_ADDR, bytes([item.item])) diff --git a/MultiServer.py b/MultiServer.py index 2ee82fe1..7d9610be 100644 --- a/MultiServer.py +++ b/MultiServer.py @@ -26,6 +26,7 @@ from prompt_toolkit.patch_stdout import patch_stdout from fuzzywuzzy import process as fuzzy_process from worlds.alttp import Items, Regions +from worlds import network_data_package import Utils from Utils import get_item_name_from_id, get_location_name_from_address, \ _version_tuple, restricted_loads, Version @@ -383,7 +384,8 @@ async def on_client_connected(ctx: Context, client: Client): 'forfeit_mode': ctx.forfeit_mode, 'remaining_mode': ctx.remaining_mode, 'hint_cost': ctx.hint_cost, - 'location_check_points': ctx.location_check_points + 'location_check_points': ctx.location_check_points, + 'datapackage_version': network_data_package["version"] }]) @@ -1046,7 +1048,10 @@ async def process_client_cmd(ctx: Context, client: Client, args: dict): await ctx.send_msgs(client, reply) await on_client_joined(ctx, client) - if client.auth: + elif cmd == "GetDataPackage": + await ctx.send_msgs(client, [{"cmd": "DataPackage", + "data": network_data_package}]) + elif client.auth: if cmd == 'Sync': items = get_received_items(ctx, client.team, client.slot) if items: diff --git a/Utils.py b/Utils.py index 9b977d40..ff897786 100644 --- a/Utils.py +++ b/Utils.py @@ -288,7 +288,7 @@ def get_location_name_from_address(address): return lookup_any_location_id_to_name.get(address, f'Unknown location (ID:{address})') -def persistent_store(category, key, value): +def persistent_store(category: str, key: typing.Any, value: typing.Any): path = local_path("_persistent_storage.yaml") storage: dict = persistent_load() category = storage.setdefault(category, {}) diff --git a/worlds/__init__.py b/worlds/__init__.py index c3fca7d5..41df342b 100644 --- a/worlds/__init__.py +++ b/worlds/__init__.py @@ -9,3 +9,9 @@ lookup_any_item_id_to_name = {**alttp, **hk} from .alttp import Regions from .hk import Locations lookup_any_location_id_to_name = {**Regions.lookup_id_to_name, **Locations.lookup_id_to_name} + +network_data_package = {"lookup_any_location_id_to_name": lookup_any_location_id_to_name, + "lookup_any_item_id_to_name": lookup_any_item_id_to_name, + "version": 1} + +print(network_data_package) \ No newline at end of file diff --git a/worlds/alttp/Items.py b/worlds/alttp/Items.py index 36a1373b..6b43742c 100644 --- a/worlds/alttp/Items.py +++ b/worlds/alttp/Items.py @@ -200,7 +200,7 @@ item_table = {'Bow': (True, None, 0x0B, 'You have\nchosen the\narcher class.', ' 'Open Floodgate': (True, 'Event', None, None, None, None, None, None, None, None), } -lookup_id_to_name = {data[2]: name for name, data in item_table.items() if data[2]} +lookup_id_to_name = {data[2]: name for name, data in item_table.items() if type(data[2]) == int} hint_blacklist = {"Triforce"} diff --git a/worlds/hk/Items.py b/worlds/hk/Items.py index d9f6d88f..639a4091 100644 --- a/worlds/hk/Items.py +++ b/worlds/hk/Items.py @@ -6,7 +6,6 @@ from .Types import HKItemData item_table = \ { '150_Geo-Resting_Grounds_Chest': HKItemData(advancement=False, id=16777336, type='Geo'), '160_Geo-Weavers_Den_Chest': HKItemData(advancement=False, id=16777338, type='Geo'), - '1_Geo': HKItemData(advancement=False, id=16777339, type='Fake'), '200_Geo-False_Knight_Chest': HKItemData(advancement=False, id=16777331, type='Geo'), '380_Geo-Soul_Master_Chest': HKItemData(advancement=False, id=16777332, type='Geo'), '620_Geo-Mantis_Lords_Chest': HKItemData(advancement=False, id=16777335, type='Geo'), @@ -79,11 +78,9 @@ item_table = \ 'Dream_Gate': HKItemData(advancement=True, id=16777229, type='Skill'), 'Dream_Nail': HKItemData(advancement=True, id=16777228, type='Skill'), 'Dream_Wielder': HKItemData(advancement=False, id=16777270, type='Charm'), - 'Dreamer': HKItemData(advancement=True, id=16777221, type='Fake'), 'Dreamshield': HKItemData(advancement=False, id=16777280, type='Charm'), 'Elegant_Key': HKItemData(advancement=True, id=16777291, type='Key'), 'Emilitia': HKItemData(advancement=True, id=0, type='Event'), - 'Equipped': HKItemData(advancement=False, id=16777511, type='Fake'), 'Failed_Tramway': HKItemData(advancement=True, id=0, type='Event'), 'Far_Left_Basin': HKItemData(advancement=True, id=0, type='Event'), 'Far_Left_Waterways': HKItemData(advancement=True, id=0, type='Event'), @@ -155,7 +152,6 @@ item_table = \ 'Grub-Waterways_Main': HKItemData(advancement=True, id=16777453, type='Grub'), 'Grub-Waterways_Requires_Tram': HKItemData(advancement=True, id=16777455, type='Grub'), "Grubberfly's_Elegy": HKItemData(advancement=True, id=16777275, type='Charm'), - 'Grubfather': HKItemData(advancement=False, id=16777509, type='Fake'), 'Grubsong': HKItemData(advancement=False, id=16777243, type='Charm'), "Hallownest's_Crown": HKItemData(advancement=True, id=0, type='Event'), "Hallownest_Seal-Beast's_Den": HKItemData(advancement=False, id=16777389, type='Relic'), @@ -180,6 +176,7 @@ item_table = \ 'Hidden_Station_Stag': HKItemData(advancement=True, id=16777499, type='Stag'), 'Hive': HKItemData(advancement=True, id=0, type='Event'), 'Hiveblood': HKItemData(advancement=False, id=16777269, type='Charm'), + 'Hollow Knight': HKItemData(advancement=True, id=0, type='Event'), 'Howling_Cliffs': HKItemData(advancement=True, id=0, type='Event'), 'Howling_Cliffs_Map': HKItemData(advancement=False, id=16777486, type='Map'), 'Howling_Wraiths': HKItemData(advancement=True, id=16777235, type='Skill'), @@ -259,7 +256,6 @@ item_table = \ 'Pale_Ore-Grubs': HKItemData(advancement=False, id=16777329, type='Ore'), 'Pale_Ore-Nosk': HKItemData(advancement=False, id=16777327, type='Ore'), 'Pale_Ore-Seer': HKItemData(advancement=False, id=16777328, type='Ore'), - 'Placeholder': HKItemData(advancement=False, id=16777512, type='Fake'), 'Pleasure_House': HKItemData(advancement=True, id=0, type='Event'), "Queen's_Gardens_Map": HKItemData(advancement=False, id=16777488, type='Map'), "Queen's_Gardens_Stag": HKItemData(advancement=True, id=16777494, type='Stag'), @@ -295,7 +291,6 @@ item_table = \ 'Right_Fog_Canyon': HKItemData(advancement=True, id=0, type='Event'), 'Right_Waterways': HKItemData(advancement=True, id=0, type='Event'), 'Royal_Waterways_Map': HKItemData(advancement=False, id=16777485, type='Map'), - 'Seer': HKItemData(advancement=False, id=16777510, type='Fake'), 'Shade_Cloak': HKItemData(advancement=True, id=16777226, type='Skill'), 'Shade_Soul': HKItemData(advancement=True, id=16777232, type='Skill'), 'Shaman_Stone': HKItemData(advancement=False, id=16777259, type='Charm'), diff --git a/worlds/hk/Locations.py b/worlds/hk/Locations.py index 2eff5590..0c97f182 100644 --- a/worlds/hk/Locations.py +++ b/worlds/hk/Locations.py @@ -6,7 +6,6 @@ lookup_id_to_name = \ 17825794: 'Monomon', 17825795: 'Herrah', 17825796: 'World_Sense', - 17825797: 'Dreamer', 17825798: 'Mothwing_Cloak', 17825799: 'Mantis_Claw', 17825800: 'Crystal_Heart', @@ -124,7 +123,6 @@ lookup_id_to_name = \ 17825912: '150_Geo-Resting_Grounds_Chest', 17825913: '80_Geo-Crystal_Peak_Chest', 17825914: '160_Geo-Weavers_Den_Chest', - 17825915: '1_Geo', 17825916: 'Rancid_Egg-Sly', 17825917: 'Rancid_Egg-Grubs', 17825918: 'Rancid_Egg-Sheo', @@ -293,11 +291,7 @@ lookup_id_to_name = \ 17826081: 'Lifeblood_Cocoon-Mantis_Village', 17826082: 'Lifeblood_Cocoon-Failed_Tramway', 17826083: 'Lifeblood_Cocoon-Galien', - 17826084: "Lifeblood_Cocoon-Kingdom's_Edge", - 17826085: 'Grubfather', - 17826086: 'Seer', - 17826087: 'Equipped', - 17826088: 'Placeholder'} + 17826084: "Lifeblood_Cocoon-Kingdom's_Edge"} diff --git a/worlds/hk/Rules.py b/worlds/hk/Rules.py index 3fa4f283..c339be07 100644 --- a/worlds/hk/Rules.py +++ b/worlds/hk/Rules.py @@ -5,9 +5,11 @@ from ..generic.Rules import set_rule def set_rules(world, player): if world.logic[player] != 'nologic': - world.completion_condition[player] = lambda state: state.has('Lurien', player) and \ - state.has('Monomon', player) and \ - state.has('Herrah', player) + # world.completion_condition[player] = lambda state: state.has('Lurien', player) and \ + # state.has('Monomon', player) and \ + # state.has('Herrah', player) + world.completion_condition[player] = lambda state: state.has('Hollow Knight', player) + set_rule(world.get_location("Lurien", player), lambda state: ((((state.has("Right_City", player) and state.has("Mantis_Claw", player)) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and (state.has("Monarch_Wings", player) or state.world.MILDSKIPS[player])) and (((((((state.has("Vengeful_Spirit", player) and state.has("Shade_Soul", player)) or (state.has("Desolate_Dive", player) and state.has("Descending_Dark", player))) or (state.has("Howling_Wraiths", player) and state.has("Abyss_Shriek", player))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player])))) set_rule(world.get_location("Monomon", player), lambda state: ((((state.has("Teacher's_Archives", player) and state.has("Mantis_Claw", player)) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and ((((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player])) or state.world.SPICYSKIPS[player])) and (state.has("Isma's_Tear", player) or state.has("Crystal_Heart", player)))) @@ -44,7 +46,7 @@ def set_rules(world, player): set_rule(world.get_location("Spore_Shroom", player), lambda state: ((state.has("Bottom_Left_Fungal_Wastes", player) and (state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player))) and ((state.has("Isma's_Tear", player) or (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) or (state.has("Mantis_Claw", player) and state.has("Crystal_Heart", player))))) set_rule(world.get_location("Soul_Catcher", player), lambda state: (state.has("Ancestral_Mound", player) and ((state.has("Mantis_Claw", player) or (((((((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player))) or state.has("Grubberfly's_Elegy", player)) or state.has("Glowing_Womb", player)) or ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) and state.has("Dash_Slash", player))) or (state.world.MILDSKIPS[player] and (state.has("Weaversong", player) or (state.has("Spore_Shroom", player) and (state.world.NOTCURSED[player] or state.has("Focus", player)))))) or (((state.has("Mark_of_Pride", player) or state.has("Cyclone_Slash", player)) or (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) and state.world.SPICYSKIPS[player]))) or (state.has("Monarch_Wings", player) and state.world.SHADESKIPS[player])))) set_rule(world.get_location("Soul_Eater", player), lambda state: ((state.has("Upper_Resting_Grounds", player) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player))) and (state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)))) - set_rule(world.get_location("Glowing_Womb", player), lambda state: ((state.has("Crossroads", player) and (state.has("Crystal_Heart", player) or ((state.world.SPIKETUNNELS[player] and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) and ((state.has("Dashmaster", player) or (state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player))) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))))) and ((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or ((((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) or state.has("Dreamer", player)) and state.world.SPICYSKIPS[player])))) + set_rule(world.get_location("Glowing_Womb", player), lambda state: ((state.has("Crossroads", player) and (state.has("Crystal_Heart", player) or ((state.world.SPIKETUNNELS[player] and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) and ((state.has("Dashmaster", player) or (state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player))) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))))) and ((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or (((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) and state.world.SPICYSKIPS[player])))) set_rule(world.get_location("Nailmaster's_Glory", player), lambda state: ((((state.has("Dirtmouth", player) and state.has("Crossroads", player)) and state.has("Cyclone_Slash", player)) and state.has("Dash_Slash", player)) and state.has("Great_Slash", player))) set_rule(world.get_location("Joni's_Blessing", player), lambda state: (state.has("Howling_Cliffs", player) and (state.world.DARKROOMS[player] or state.has("Lumafly_Lantern", player)))) set_rule(world.get_location("Shape_of_Unn", player), lambda state: (state.has("Lake_of_Unn", player) and (((state.has("Isma's_Tear", player) and (state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player))) or ((((((state.has("Mantis_Claw", player) and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) and state.has("Crystal_Heart", player)) and state.world.ACIDSKIPS[player]) and state.has("Monarch_Wings", player)) and (((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and state.world.FIREBALLSKIPS[player]) or ((state.has("Sharp_Shadow", player) and state.has("Mothwing_Cloak", player)) and state.has("Shade_Cloak", player)))) and state.world.SPICYSKIPS[player])) or ((((state.world.SPICYSKIPS[player] and state.world.ACIDSKIPS[player]) and state.has("Monarch_Wings", player)) and state.has("Crystal_Heart", player)) and ((state.has("Sharp_Shadow", player) and state.has("Mothwing_Cloak", player)) and state.has("Shade_Cloak", player)))))) @@ -141,7 +143,7 @@ def set_rules(world, player): set_rule(world.get_location("Wanderer's_Journal-Kingdom's_Edge_Entrance", player), lambda state: (state.has("Central_Kingdom's_Edge", player) and state.has("Mantis_Claw", player))) set_rule(world.get_location("Wanderer's_Journal-Kingdom's_Edge_Camp", player), lambda state: (state.has("Center_Right_Kingdom's_Edge", player) and (state.has("Monarch_Wings", player) or (state.has("Mantis_Claw", player) and (state.world.SPICYSKIPS[player] or state.has("Cast_Off_Shell", player)))))) set_rule(world.get_location("Wanderer's_Journal-Kingdom's_Edge_Requires_Dive", player), lambda state: (state.has("Center_Right_Kingdom's_Edge", player) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) - set_rule(world.get_location("Hallownest_Seal-Crossroads_Well", player), lambda state: (state.has("Crossroads", player) and ((state.has("Mantis_Claw", player) or (state.has("Monarch_Wings", player) and (state.world.SHADESKIPS[player] or ((((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) or state.has("Dreamer", player)) and state.world.SPICYSKIPS[player])))) or ((((((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) or state.has("Dreamer", player)) and state.world.SPICYSKIPS[player]) and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) and (state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))))))) + set_rule(world.get_location("Hallownest_Seal-Crossroads_Well", player), lambda state: (state.has("Crossroads", player) and ((state.has("Mantis_Claw", player) or (state.has("Monarch_Wings", player) and (state.world.SHADESKIPS[player] or (((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) and state.world.SPICYSKIPS[player])))) or (((((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) and state.world.SPICYSKIPS[player]) and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) and (state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))))))) set_rule(world.get_location("Hallownest_Seal-Grubs", player), lambda state: (state.has("Crossroads", player) and state.has_grubs(30, player))) set_rule(world.get_location("Hallownest_Seal-Greenpath", player), lambda state: (state.has("Greenpath", player) and (((state.has("Isma's_Tear", player) or (state.has("Monarch_Wings", player) and (state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))))) or ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) and ((((state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))) or state.has("Dashmaster", player)) or state.has("Monarch_Wings", player)) or state.has("Mantis_Claw", player)))) or state.has("Crystal_Heart", player)))) set_rule(world.get_location("Hallownest_Seal-Fog_Canyon_West", player), lambda state: state.has("Left_Fog_Canyon", player)) @@ -170,7 +172,7 @@ def set_rules(world, player): set_rule(world.get_location("Arcane_Egg-Lifeblood_Core", player), lambda state: ((state.has("Abyss", player) and ((state.has("Lifeblood_Heart", player) or state.has("Lifeblood_Core", player)) or state.has("Joni's_Blessing", player))) and (state.has("Crystal_Heart", player) and (state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player))))) set_rule(world.get_location("Arcane_Egg-Shade_Cloak", player), lambda state: ((state.has("Abyss", player) and ((state.has("Mantis_Claw", player) and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) or state.has("Monarch_Wings", player))) and ((state.has("Mothwing_Cloak", player) and state.has("Shade_Cloak", player)) or ((state.has("Queen_Fragment", player) and state.has("King_Fragment", player)) and state.has("Void_Heart", player))))) set_rule(world.get_location("Arcane_Egg-Birthplace", player), lambda state: (state.has("Abyss", player) and (((state.has("Queen_Fragment", player) and state.has("King_Fragment", player)) or (state.has("Queen_Fragment", player) and state.has("Void_Heart", player))) or (state.has("King_Fragment", player) and state.has("Void_Heart", player))))) - set_rule(world.get_location("Whispering_Root-Crossroads", player), lambda state: (((state.has("Crossroads", player) and state.has("Mantis_Claw", player)) and (((state.has("Monarch_Wings", player) or state.has("Crystal_Heart", player)) or (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) or ((((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) or state.has("Dreamer", player)) and state.world.SPICYSKIPS[player]))) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player)))) + set_rule(world.get_location("Whispering_Root-Crossroads", player), lambda state: (((state.has("Crossroads", player) and state.has("Mantis_Claw", player)) and (((state.has("Monarch_Wings", player) or state.has("Crystal_Heart", player)) or (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) or (((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) and state.world.SPICYSKIPS[player]))) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player)))) set_rule(world.get_location("Whispering_Root-Greenpath", player), lambda state: (((state.has("Far_Queen's_Gardens", player) and state.has("Greenpath", player)) and state.has("Mantis_Claw", player)) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player)))) set_rule(world.get_location("Whispering_Root-Leg_Eater", player), lambda state: (state.has("Right_Fog_Canyon", player) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player)))) set_rule(world.get_location("Whispering_Root-Mantis_Village", player), lambda state: ((state.has("Fungal_Wastes", player) and state.has("Mantis_Claw", player)) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player)))) @@ -192,7 +194,7 @@ def set_rules(world, player): set_rule(world.get_location("Boss_Essence-No_Eyes", player), lambda state: (((state.has("Stone_Sanctuary", player) and state.has("Lumafly_Lantern", player)) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and ((((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player])) or state.world.SPICYSKIPS[player]))) set_rule(world.get_location("Boss_Essence-Galien", player), lambda state: ((((state.has("Failed_Tramway", player) and (state.has("Lumafly_Lantern", player) or state.world.DARKROOMS[player])) or (state.has("Dark_Deepnest", player) and state.has("Mantis_Claw", player))) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and ((((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player])) or state.world.SPICYSKIPS[player]))) set_rule(world.get_location("Boss_Essence-Markoth", player), lambda state: (((state.has("Center_Right_Kingdom's_Edge", player) and (state.has("Mothwing_Cloak", player) and state.has("Shade_Cloak", player))) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and ((((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player])) or state.world.SPICYSKIPS[player]))) - set_rule(world.get_location("Boss_Essence-Failed_Champion", player), lambda state: (((state.has("Crossroads", player) and ((state.has("Mantis_Claw", player) and ((state.has("Monarch_Wings", player) or (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) or state.has("Crystal_Heart", player))) or (state.has("Monarch_Wings", player) and ((((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) or state.has("Dreamer", player)) and state.world.SPICYSKIPS[player])))) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and (((((((state.has("Vengeful_Spirit", player) and state.has("Shade_Soul", player)) or (state.has("Desolate_Dive", player) and state.has("Descending_Dark", player))) or (state.has("Howling_Wraiths", player) and state.has("Abyss_Shriek", player))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player])))) + set_rule(world.get_location("Boss_Essence-Failed_Champion", player), lambda state: (((state.has("Crossroads", player) and ((state.has("Mantis_Claw", player) and ((state.has("Monarch_Wings", player) or (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) or state.has("Crystal_Heart", player))) or (state.has("Monarch_Wings", player) and (((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) and state.world.SPICYSKIPS[player])))) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and (((((((state.has("Vengeful_Spirit", player) and state.has("Shade_Soul", player)) or (state.has("Desolate_Dive", player) and state.has("Descending_Dark", player))) or (state.has("Howling_Wraiths", player) and state.has("Abyss_Shriek", player))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player])))) set_rule(world.get_location("Boss_Essence-Soul_Tyrant", player), lambda state: (((state.has("Soul_Sanctum", player) and (state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player))) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and (((((((state.has("Vengeful_Spirit", player) and state.has("Shade_Soul", player)) or (state.has("Desolate_Dive", player) and state.has("Descending_Dark", player))) or (state.has("Howling_Wraiths", player) and state.has("Abyss_Shriek", player))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player])))) set_rule(world.get_location("Boss_Essence-Lost_Kin", player), lambda state: (((state.has("Far_Left_Basin", player) and (state.has("Mantis_Claw", player) or (state.has("Monarch_Wings", player) and state.world.MILDSKIPS[player]))) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and (((((((state.has("Vengeful_Spirit", player) and state.has("Shade_Soul", player)) or (state.has("Desolate_Dive", player) and state.has("Descending_Dark", player))) or (state.has("Howling_Wraiths", player) and state.has("Abyss_Shriek", player))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player])))) set_rule(world.get_location("Boss_Essence-White_Defender", player), lambda state: (((((((state.has("Central_Left_Waterways", player) and (state.has("Mantis_Claw", player) or (state.has("Monarch_Wings", player) and state.world.SPICYSKIPS[player]))) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player))) and ((state.has("Dream_Nail", player) or state.has("Dream_Gate", player)) or state.has("Awoken_Dream_Nail", player))) and (((((((state.has("Vengeful_Spirit", player) and state.has("Shade_Soul", player)) or (state.has("Desolate_Dive", player) and state.has("Descending_Dark", player))) or (state.has("Howling_Wraiths", player) and state.has("Abyss_Shriek", player))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) and (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.world.MILDSKIPS[player]))) and state.has("Lurien", player)) and state.has("Monomon", player)) and state.has("Herrah", player))) @@ -276,10 +278,11 @@ def set_rules(world, player): set_rule(world.get_location("Lifeblood_Cocoon-Failed_Tramway", player), lambda state: (state.has("Failed_Tramway", player) and (state.has("Mantis_Claw", player) or (state.has("Monarch_Wings", player) and (state.world.MILDSKIPS[player] or state.world.SHADESKIPS[player]))))) set_rule(world.get_location("Lifeblood_Cocoon-Galien", player), lambda state: (state.has("Dark_Deepnest", player) and state.has("Mantis_Claw", player))) set_rule(world.get_location("Lifeblood_Cocoon-Kingdom's_Edge", player), lambda state: (state.has("Upper_Kingdom's_Edge", player) and (state.has("Monarch_Wings", player) or (state.has("Mantis_Claw", player) and state.world.MILDSKIPS[player])))) - set_rule(world.get_location("Grubfather", player), lambda state: state.has("Crossroads", player)) - set_rule(world.get_location("Seer", player), lambda state: state.has("Upper_Resting_Grounds", player)) # Events + set_rule(world.get_location("Hollow Knight", player), lambda state: state.has('Lurien', player) and \ + state.has('Monomon', player) and \ + state.has('Herrah', player)) set_rule(world.get_location("Dirtmouth", player), lambda state: ((((state.has("Crossroads", player) or ((state.has("Upper_Crystal_Peak", player) and state.has("Mantis_Claw", player)) and state.has("Crystal_Heart", player))) or state.has("King's_Pass", player)) or (state.has("Howling_Cliffs", player) and (state.has("Crystal_Heart", player) or (state.has("Monarch_Wings", player) and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)))))) or (state.has("Dirtmouth_Stag", player) and state.has("Can_Stag", player)))) set_rule(world.get_location("Can_Stag", player), lambda state: (((((((((state.has("Crossroads", player) or state.has("Greenpath", player)) or state.has("Queen's_Station", player)) or state.has("Top_Left_Queen's_Gardens", player)) or state.has("Left_Elevator", player)) or state.has("Upper_King's_Station", player)) or (state.has("Right_City", player) and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)))) or state.has("Upper_Resting_Grounds", player)) or (state.has("Distant_Village", player) and ((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or (state.has("Beast's_Den", player) and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)))))) or state.has("Palace_Grounds", player))) @@ -294,7 +297,7 @@ def set_rules(world, player): set_rule(world.get_location("Right_Fog_Canyon", player), lambda state: ((((state.has("Left_Fog_Canyon", player) and (state.has("Mothwing_Cloak", player) and state.has("Shade_Cloak", player))) or (state.has("Fungal_Wastes", player) and state.has("Isma's_Tear", player))) or (state.has("Crossroads", player) and (state.has("Isma's_Tear", player) or (((state.has("Mantis_Claw", player) and state.has("Crystal_Heart", player)) or (state.has("Monarch_Wings", player) and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)))) and state.world.ACIDSKIPS[player])))) or state.has("Teacher's_Archives", player))) set_rule(world.get_location("Teacher's_Archives", player), lambda state: state.has("Right_Fog_Canyon", player)) set_rule(world.get_location("Queen's_Station", player), lambda state: ((state.has("Left_Fog_Canyon", player) or state.has("Fungal_Wastes", player)) or (state.has("Queen's_Station_Stag", player) and state.has("Can_Stag", player)))) - set_rule(world.get_location("Fungal_Wastes", player), lambda state: (((((((state.has("Queen's_Station", player) and ((((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) or state.has("Crystal_Heart", player)) or (state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))))) or (state.has("Isma's_Tear", player) and state.has("Right_Fog_Canyon", player))) or (state.has("Crossroads", player) and ((((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.has("Monarch_Wings", player)) or ((((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) or state.has("Dreamer", player)) and state.world.SPICYSKIPS[player])) or (state.has("Mantis_Claw", player) and (state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))))))) or (((state.has("Left_City", player) or state.has("Left_Elevator", player)) and state.has("Mantis_Claw", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or (state.has("Fungal_Core", player) and (state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)))) or (state.has("Mantis_Village", player) and ((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or state.world.MILDSKIPS[player]))) or (state.has("Mantis_Outskirts", player) and (((((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.has("Mantis_Claw", player)) or state.has("Monarch_Wings", player)) or state.has("Isma's_Tear", player)) or state.world.MILDSKIPS[player])))) + set_rule(world.get_location("Fungal_Wastes", player), lambda state: (((((((state.has("Queen's_Station", player) and ((((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) or state.has("Crystal_Heart", player)) or (state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))))) or (state.has("Isma's_Tear", player) and state.has("Right_Fog_Canyon", player))) or (state.has("Crossroads", player) and ((((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.has("Monarch_Wings", player)) or (((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) and state.world.SPICYSKIPS[player])) or (state.has("Mantis_Claw", player) and (state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player)))))))) or (((state.has("Left_City", player) or state.has("Left_Elevator", player)) and state.has("Mantis_Claw", player)) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player)))) or (state.has("Fungal_Core", player) and (state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)))) or (state.has("Mantis_Village", player) and ((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or state.world.MILDSKIPS[player]))) or (state.has("Mantis_Outskirts", player) and (((((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.has("Mantis_Claw", player)) or state.has("Monarch_Wings", player)) or state.has("Isma's_Tear", player)) or state.world.MILDSKIPS[player])))) set_rule(world.get_location("Bottom_Left_Fungal_Wastes", player), lambda state: (((state.has("Fungal_Wastes", player) and (state.has("Mantis_Claw", player) or (state.has("Monarch_Wings", player) and (state.world.SHADESKIPS[player] or state.world.SPICYSKIPS[player])))) or state.has("Bottom_Right_Queen's_Gardens", player)) or (state.has("Upper_Deepnest", player) and ((state.has("Mantis_Claw", player) and (((((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.has("Crystal_Heart", player)) or state.has("Monarch_Wings", player)) or state.world.SHADESKIPS[player]) or state.world.SPICYSKIPS[player])) or (state.has("Monarch_Wings", player) and (state.world.SHADESKIPS[player] or state.world.SPICYSKIPS[player])))))) set_rule(world.get_location("Fungal_Core", player), lambda state: ((state.has("Fungal_Wastes", player) and state.has("Mantis_Claw", player)) and state.has("Monarch_Wings", player))) set_rule(world.get_location("Mantis_Outskirts", player), lambda state: (state.has("Fungal_Wastes", player) or (state.has("Mantis_Village", player) and ((((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or state.has("Isma's_Tear", player)) or state.has("Crystal_Heart", player)) or ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) and state.world.MILDSKIPS[player]))))) @@ -350,7 +353,7 @@ def set_rules(world, player): set_rule(world.get_location("Upper_Resting_Grounds", player), lambda state: (((((state.has("Upper_Tram", player) or (state.has("Lower_Resting_Grounds", player) and ((((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.has("Mantis_Claw", player)) or state.has("Monarch_Wings", player)) or state.world.MILDSKIPS[player]))) or (state.has("Crystal_Peak", player) and (state.has("Lumafly_Lantern", player) or state.world.DARKROOMS[player]))) or state.has("Crystallized_Mound", player)) or state.has("Spirits_Glade", player)) or (state.has("Resting_Grounds_Stag", player) and state.has("Can_Stag", player)))) set_rule(world.get_location("Spirits_Glade", player), lambda state: (state.has_essence(200, player) and state.has("Upper_Resting_Grounds", player))) set_rule(world.get_location("Lower_Resting_Grounds", player), lambda state: (((state.has("Upper_Resting_Grounds", player) and (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player))) or state.has("Blue_Lake", player)) or state.has("Right_Elevator", player))) - set_rule(world.get_location("Blue_Lake", player), lambda state: ((state.has("Crossroads", player) and (((state.has("Mantis_Claw", player) and (state.has("Monarch_Wings", player) or state.has("Crystal_Heart", player))) or ((((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) or state.has("Dreamer", player)) and state.world.SPICYSKIPS[player])) or (state.world.SHADESKIPS[player] and ((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or ((state.world.SPICYSKIPS[player] and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) and (state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player))))))))) or (state.has("Lower_Resting_Grounds", player) and (state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player))))) + set_rule(world.get_location("Blue_Lake", player), lambda state: ((state.has("Crossroads", player) and (((state.has("Mantis_Claw", player) and (state.has("Monarch_Wings", player) or state.has("Crystal_Heart", player))) or (((state.has("Lurien", player) or state.has("Monomon", player)) or state.has("Herrah", player)) and state.world.SPICYSKIPS[player])) or (state.world.SHADESKIPS[player] and ((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) or ((state.world.SPICYSKIPS[player] and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) and (state.world.FIREBALLSKIPS[player] and ((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player))))))))) or (state.has("Lower_Resting_Grounds", player) and (state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player))))) set_rule(world.get_location("Top_Right_Queen's_Gardens", player), lambda state: ((state.has("Left_Fog_Canyon", player) and ((state.has("Isma's_Tear", player) or (((state.has("Mantis_Claw", player) and (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) and state.has("Crystal_Heart", player)) and state.world.ACIDSKIPS[player])) or (state.has("Mothwing_Cloak", player) and state.has("Shade_Cloak", player)))) or (state.has("Top_Left_Queen's_Gardens", player) and ((state.has("Crystal_Heart", player) or (state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player))) or state.has("Monarch_Wings", player))))) set_rule(world.get_location("Bottom_Right_Queen's_Gardens", player), lambda state: ((state.has("Top_Right_Queen's_Gardens", player) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or ((state.has("Mantis_Claw", player) or state.has("Monarch_Wings", player)) and state.has("Crystal_Heart", player)))) or (state.has("Bottom_Left_Queen's_Gardens", player) and state.has("Mantis_Claw", player)))) set_rule(world.get_location("Bottom_Left_Queen's_Gardens", player), lambda state: ((state.has("Bottom_Right_Queen's_Gardens", player) or ((state.has("Top_Left_Queen's_Gardens", player) and ((((state.has("Vengeful_Spirit", player) or state.has("Shade_Soul", player)) or (state.has("Howling_Wraiths", player) or state.has("Abyss_Shriek", player))) or (state.has("Desolate_Dive", player) or state.has("Descending_Dark", player))) or state.world.SPICYSKIPS[player])) and ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) or state.has("Monarch_Wings", player)))) or (((state.has("Dark_Deepnest", player) and state.has("Mantis_Claw", player)) and (state.has("Monarch_Wings", player) or ((state.has("Mothwing_Cloak", player) or state.has("Shade_Cloak", player)) and state.world.MILDSKIPS[player]))) and (state.has("Lumafly_Lantern", player) or (state.world.DARKROOMS[player] and state.world.SPICYSKIPS[player])))))