diff --git a/worlds/grinch/Client.py b/worlds/grinch/Client.py index 9d18c498..ac6ccf6f 100644 --- a/worlds/grinch/Client.py +++ b/worlds/grinch/Client.py @@ -6,7 +6,13 @@ import copy import uuid import Utils from .Locations import grinch_locations, GrinchLocation -from .Items import ALL_ITEMS_TABLE, MISSION_ITEMS_TABLE, GADGETS_TABLE, KEYS_TABLE, GrinchItemData #, SLEIGH_PARTS_TABLE +from .Items import ( + ALL_ITEMS_TABLE, + MISSION_ITEMS_TABLE, + GADGETS_TABLE, + KEYS_TABLE, + GrinchItemData, +) # , SLEIGH_PARTS_TABLE import worlds._bizhawk as bizhawk from worlds._bizhawk.client import BizHawkClient @@ -30,6 +36,7 @@ MAX_EGGS: int = 200 EGG_COUNT_ADDR: int = 0x010058 EGG_ADDR_BYTESIZE: int = 2 + class GrinchClient(BizHawkClient): game = "The Grinch" system = "PSX" @@ -52,27 +59,44 @@ class GrinchClient(BizHawkClient): async def validate_rom(self, ctx: "BizHawkClientContext") -> bool: from CommonClient import logger + # TODO Check the ROM data to see if it matches against bytes expected grinch_identifier_ram_address: int = 0x00928C bios_identifier_ram_address: int = 0x097F30 + try: - bytes_actual: bytes = (await bizhawk.read(ctx.bizhawk_ctx, [( - grinch_identifier_ram_address, 11, "MainRAM")]))[0] + bytes_actual: bytes = ( + await bizhawk.read( + ctx.bizhawk_ctx, [(grinch_identifier_ram_address, 11, "MainRAM")] + ) + )[0] psx_rom_name = bytes_actual.decode("ascii") if psx_rom_name != "SLUS_011.97": - bios_bytes_check: bytes = (await bizhawk.read(ctx.bizhawk_ctx, [( - bios_identifier_ram_address, 24, "MainRAM")]))[0] + bios_bytes_check: bytes = ( + await bizhawk.read( + ctx.bizhawk_ctx, [(bios_identifier_ram_address, 24, "MainRAM")] + ) + )[0] + if "System ROM Version" in bios_bytes_check.decode("ascii"): if not self.loading_bios_msg: self.loading_bios_msg = True - logger.error("BIOS is currently loading. Will wait up to 5 seconds before retrying.") + logger.error( + "BIOS is currently loading. Will wait up to 5 seconds before retrying." + ) + return False - logger.error("Invalid rom detected. You are not playing Grinch USA Version.") - raise Exception("Invalid rom detected. You are not playing Grinch USA Version.") + logger.error( + "Invalid rom detected. You are not playing Grinch USA Version." + ) + raise Exception( + "Invalid rom detected. You are not playing Grinch USA Version." + ) ctx.command_processor.commands["ringlink"] = _cmd_ringlink + except Exception: return False @@ -86,38 +110,54 @@ class GrinchClient(BizHawkClient): def on_package(self, ctx: "BizHawkClientContext", cmd: str, args: dict) -> None: from CommonClient import logger + super().on_package(ctx, cmd, args) + match cmd: case "Connected": # On Connect self.loc_unlimited_eggs = bool(ctx.slot_data["give_unlimited_eggs"]) self.unique_client_id = self._get_uuid() - logger.info("You are now connected to the client. "+ - "There may be a slight delay to check you are not in demo mode before locations start to send.") + logger.info( + "You are now connected to the client. " + + "There may be a slight delay to check you are not in demo mode before locations start to send." + ) self.ring_link_enabled = bool(ctx.slot_data["ring_link"]) tags = copy.deepcopy(ctx.tags) + if self.ring_link_enabled: ctx.tags.add("RingLink") + else: - ctx.tags -= { "RingLink" } + ctx.tags -= {"RingLink"} if tags != ctx.tags: - Utils.async_start(ctx.send_msgs([{"cmd": "ConnectUpdate", "tags": ctx.tags}]), "Update RingLink Tags") + Utils.async_start( + ctx.send_msgs([{"cmd": "ConnectUpdate", "tags": ctx.tags}]), + "Update RingLink Tags", + ) case "Bounced": if "tags" not in args: return - if "RingLink" in ctx.tags and "RingLink" in args["tags"] and args["data"]["source"] != self.unique_client_id: - Utils.async_start(self.ring_link_input(args["data"]["amount"], ctx), "SyncEggs") + if ( + "RingLink" in ctx.tags + and "RingLink" in args["tags"] + and args["data"]["source"] != self.unique_client_id + ): + Utils.async_start( + self.ring_link_input(args["data"]["amount"], ctx), "SyncEggs" + ) async def set_auth(self, ctx: "BizHawkClientContext") -> None: await ctx.get_username() async def game_watcher(self, ctx: "BizHawkClientContext") -> None: from CommonClient import logger - #If the player is not connected to an AP Server, or their connection was disconnected. + + # If the player is not connected to an AP Server, or their connection was disconnected. if not ctx.slot: return @@ -125,7 +165,9 @@ class GrinchClient(BizHawkClient): if not await self.ingame_checker(ctx): return - if not any(task.get_name() == "Grinch EggLink" for task in asyncio.all_tasks()): + if not any( + task.get_name() == "Grinch EggLink" for task in asyncio.all_tasks() + ): print("EggLink") self.send_ring_link = True Utils.async_start(self.ring_link_output(ctx), name="Grinch EggLink") @@ -138,16 +180,24 @@ class GrinchClient(BizHawkClient): except bizhawk.RequestFailedError as ex: # The connector didn't respond. Exit handler and return to main loop to reconnect - logger.error("Failure to connect / authenticate the grinch. Error details: " + str(ex)) + logger.error( + "Failure to connect / authenticate the grinch. Error details: " + + str(ex) + ) pass + except Exception as genericEx: # For all other errors, catch this and let the client gracefully disconnect - logger.error("Unknown error occurred while playing the grinch. Error details: " + str(genericEx)) + logger.error( + "Unknown error occurred while playing the grinch. Error details: " + + str(genericEx) + ) await ctx.disconnect(False) pass async def location_checker(self, ctx: "BizHawkClientContext"): from CommonClient import logger + # Update the AP Server to know what locations are not checked yet. local_locations_checked: list[int] = [] addr_list_to_read: list[tuple[int, int, str]] = [] @@ -157,11 +207,15 @@ class GrinchClient(BizHawkClient): for missing_location in local_ap_locations: grinch_loc_name = ctx.location_names.lookup_in_game(missing_location) grinch_loc_ram_data = grinch_locations[grinch_loc_name] - missing_addr_list: list[tuple[int, int, str]] = [(read_addr.ram_address, read_addr.bit_size, "MainRAM") for - read_addr in grinch_loc_ram_data.update_ram_addr] + missing_addr_list: list[tuple[int, int, str]] = [ + (read_addr.ram_address, read_addr.byte_size, "MainRAM") + for read_addr in grinch_loc_ram_data.update_ram_addr + ] addr_list_to_read = [*addr_list_to_read, *missing_addr_list] - returned_bytes: list[bytes] = await bizhawk.read(ctx.bizhawk_ctx, addr_list_to_read) + returned_bytes: list[bytes] = await bizhawk.read( + ctx.bizhawk_ctx, addr_list_to_read + ) # Now loop through everything again and this time get the byte value from the above read, convert to int, # and check to see if that ram address has our expected value. @@ -174,22 +228,41 @@ class GrinchClient(BizHawkClient): # Grinch ram data may have more than one address to update, so we are going to loop through all addresses in a location # We use a list here to keep track of all our checks. If they are all true, then and only then do we mark that location as checked. ram_checked_list: list[bool] = [] + for addr_to_update in grinch_loc_ram_data.update_ram_addr: is_binary = True if not addr_to_update.binary_bit_pos is None else False - orig_index: int = addr_list_to_read.index((addr_to_update.ram_address, addr_to_update.bit_size, "MainRAM")) - value_read_from_bizhawk: int = int.from_bytes(returned_bytes[orig_index], "little") + orig_index: int = addr_list_to_read.index( + (addr_to_update.ram_address, addr_to_update.byte_size, "MainRAM") + ) + value_read_from_bizhawk: int = int.from_bytes( + returned_bytes[orig_index], "little" + ) + if is_binary: - ram_checked_list.append((value_read_from_bizhawk & (1 << addr_to_update.binary_bit_pos)) > 0) + ram_checked_list.append( + (value_read_from_bizhawk & (1 << addr_to_update.binary_bit_pos)) + > 0 + ) + else: expected_int_value = addr_to_update.value - ram_checked_list.append(expected_int_value == value_read_from_bizhawk) + ram_checked_list.append( + expected_int_value == value_read_from_bizhawk + ) + if all(ram_checked_list): - local_locations_checked.append(GrinchLocation.get_apid(grinch_loc_ram_data.id)) + local_locations_checked.append( + GrinchLocation.get_apid(grinch_loc_ram_data.id) + ) # Update the AP server with the locally checked list of locations (In other words, locations I found in Grinch) - locations_sent_to_ap: set[int] = await ctx.check_locations(local_locations_checked) + locations_sent_to_ap: set[int] = await ctx.check_locations( + local_locations_checked + ) + if len(locations_sent_to_ap) > 0: await self.remove_physical_items(ctx) + ctx.locations_checked = set(local_locations_checked) async def receiving_items_handler(self, ctx: "BizHawkClientContext"): @@ -197,12 +270,20 @@ class GrinchClient(BizHawkClient): # If the list says that we have 3 items and we already received items, we will ignore and continue. # Otherwise, we will get the new items and give them to the player. - self.last_received_index = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [( - RECV_ITEM_ADDR, RECV_ITEM_BITSIZE, "MainRAM")]))[0], "little") + self.last_received_index = int.from_bytes( + ( + await bizhawk.read( + ctx.bizhawk_ctx, [(RECV_ITEM_ADDR, RECV_ITEM_BITSIZE, "MainRAM")] + ) + )[0], + "little", + ) + if len(ctx.items_received) == self.last_received_index: return + # Ensures we only get the new items that we want to give the player - new_items_only = ctx.items_received[self.last_received_index:] + new_items_only = ctx.items_received[self.last_received_index :] ram_addr_dict: dict[int, list[int]] = {} for item_received in new_items_only: @@ -211,83 +292,164 @@ class GrinchClient(BizHawkClient): for addr_to_update in grinch_item_ram_data.update_ram_addr: is_binary = True if not addr_to_update.binary_bit_pos is None else False + if addr_to_update.ram_address in ram_addr_dict.keys(): - current_ram_address_value = ram_addr_dict[addr_to_update.ram_address][0] + current_ram_address_value = ram_addr_dict[ + addr_to_update.ram_address + ][0] else: - current_ram_address_value = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [( - addr_to_update.ram_address, addr_to_update.bit_size, "MainRAM")]))[0], "little") + current_ram_address_value = int.from_bytes( + ( + await bizhawk.read( + ctx.bizhawk_ctx, + [ + ( + addr_to_update.ram_address, + addr_to_update.byte_size, + "MainRAM", + ) + ], + ) + )[0], + "little", + ) + if is_binary: - current_ram_address_value = (current_ram_address_value | (1 << addr_to_update.binary_bit_pos)) + current_ram_address_value = current_ram_address_value | ( + 1 << addr_to_update.binary_bit_pos + ) + elif addr_to_update.update_existing_value: # Grabs minimum value of a list of numbers and makes sure it does not go above max count possible current_ram_address_value += addr_to_update.value - current_ram_address_value = min(current_ram_address_value, addr_to_update.max_count) + current_ram_address_value = min( + current_ram_address_value, addr_to_update.max_count + ) + else: current_ram_address_value = addr_to_update.value # Write the updated value back into RAM - ram_addr_dict[addr_to_update.ram_address] = [current_ram_address_value, addr_to_update.bit_size] + ram_addr_dict[addr_to_update.ram_address] = [ + current_ram_address_value, + addr_to_update.byte_size, + ] self.last_received_index += 1 # Update the latest received item index to ram as well. ram_addr_dict[RECV_ITEM_ADDR] = [self.last_received_index, RECV_ITEM_BITSIZE] - await bizhawk.write(ctx.bizhawk_ctx, self.convert_dict_to_ram_list(ram_addr_dict)) + + await bizhawk.write( + ctx.bizhawk_ctx, self.convert_dict_to_ram_list(ram_addr_dict) + ) async def goal_checker(self, ctx: "BizHawkClientContext"): if not ctx.finished_game: goal_loc = grinch_locations["MC - Sleigh Ride - Neutralizing Santa"] goal_ram_address = goal_loc.update_ram_addr[0] - current_ram_address_value = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [( - goal_ram_address.ram_address, goal_ram_address.bit_size, "MainRAM")]))[0], "little") + current_ram_address_value = int.from_bytes( + ( + await bizhawk.read( + ctx.bizhawk_ctx, + [ + ( + goal_ram_address.ram_address, + goal_ram_address.byte_size, + "MainRAM", + ) + ], + ) + )[0], + "little", + ) + if (current_ram_address_value & (1 << goal_ram_address.binary_bit_pos)) > 0: - # if current_ram_address_value == goal_ram_address.value: + # if current_ram_address_value == goal_ram_address.value: ctx.finished_game = True - await ctx.send_msgs([{ - "cmd": "StatusUpdate", - "status": NetUtils.ClientStatus.CLIENT_GOAL, - }]) + await ctx.send_msgs( + [ + { + "cmd": "StatusUpdate", + "status": NetUtils.ClientStatus.CLIENT_GOAL, + } + ] + ) # This function's entire purpose is to take away items we physically received ingame, but have not received from AP async def remove_physical_items(self, ctx: "BizHawkClientContext"): ram_addr_dict: dict[int, list[int]] = {} list_recv_itemids: list[int] = [netItem.item for netItem in ctx.items_received] - items_to_check: dict[str, GrinchItemData] = {**GADGETS_TABLE} #, **SLEIGH_PARTS_TABLE - heart_count = len(list(item_id for item_id in list_recv_itemids if item_id == 42570)) + items_to_check: dict[str, GrinchItemData] = { + **GADGETS_TABLE + } # , **SLEIGH_PARTS_TABLE + heart_count = len( + list(item_id for item_id in list_recv_itemids if item_id == 42570) + ) heart_item_data = ALL_ITEMS_TABLE["Heart of Stone"] - ram_addr_dict[heart_item_data.update_ram_addr[0].ram_address] = [min(heart_count, 4), 1] + ram_addr_dict[heart_item_data.update_ram_addr[0].ram_address] = [ + min(heart_count, 4), + 1, + ] # Setting mission count for all accesses back to 0 to prevent warping/unlocking after completing 3 missions ram_addr_dict[0x0100F0] = [0, 4] - for (item_name, item_data) in items_to_check.items(): + for item_name, item_data in items_to_check.items(): # If item is an event or already been received, ignore. - if item_data.id is None or GrinchLocation.get_apid(item_data.id) in list_recv_itemids: + if ( + item_data.id is None + or GrinchLocation.get_apid(item_data.id) in list_recv_itemids + ): continue # This assumes we don't have the item so we must set all the data to 0 for addr_to_update in item_data.update_ram_addr: is_binary = True if not addr_to_update.binary_bit_pos is None else False + if is_binary: if addr_to_update.ram_address in ram_addr_dict.keys(): current_bin_value = ram_addr_dict[addr_to_update.ram_address][0] + else: - current_bin_value = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [( - addr_to_update.ram_address, addr_to_update.bit_size, "MainRAM")]))[0], "little") + current_bin_value = int.from_bytes( + ( + await bizhawk.read( + ctx.bizhawk_ctx, + [ + ( + addr_to_update.ram_address, + addr_to_update.byte_size, + "MainRAM", + ) + ], + ) + )[0], + "little", + ) current_bin_value &= ~(1 << addr_to_update.binary_bit_pos) ram_addr_dict[addr_to_update.ram_address] = [current_bin_value, 1] + else: - ram_addr_dict[addr_to_update.ram_address] = [0, addr_to_update.bit_size] + ram_addr_dict[addr_to_update.ram_address] = [ + 0, + addr_to_update.byte_size, + ] - await bizhawk.write(ctx.bizhawk_ctx, self.convert_dict_to_ram_list(ram_addr_dict)) + await bizhawk.write( + ctx.bizhawk_ctx, self.convert_dict_to_ram_list(ram_addr_dict) + ) - - def convert_dict_to_ram_list(self, addr_dict: dict[int, list[int]]) -> list[tuple[int, Sequence[int], str]]: + def convert_dict_to_ram_list( + self, addr_dict: dict[int, list[int]] + ) -> list[tuple[int, Sequence[int], str]]: addr_list_to_update: list[tuple[int, Sequence[int], str]] = [] - for (key, val) in addr_dict.items(): - addr_list_to_update.append((key, val[0].to_bytes(val[1], "little"), "MainRAM")) + for key, val in addr_dict.items(): + addr_list_to_update.append( + (key, val[0].to_bytes(val[1], "little"), "MainRAM") + ) return addr_list_to_update @@ -296,56 +458,93 @@ class GrinchClient(BizHawkClient): ram_addr_dict: dict[int, list[int]] = {} list_recv_itemids: list[int] = [netItem.item for netItem in ctx.items_received] - items_to_check: dict[str, GrinchItemData] = {**KEYS_TABLE, **MISSION_ITEMS_TABLE} + items_to_check: dict[str, GrinchItemData] = { + **KEYS_TABLE, + **MISSION_ITEMS_TABLE, + } - for (item_name, item_data) in items_to_check.items(): + for item_name, item_data in items_to_check.items(): # If item is an event or already been received, ignore. - if item_data.id is None: # or GrinchLocation.get_apid(item_data.id) in list_recv_itemids: + if ( + item_data.id is None + ): # or GrinchLocation.get_apid(item_data.id) in list_recv_itemids: continue # This will either constantly update the item to ensure you still have it or take it away if you don't deserve it for addr_to_update in item_data.update_ram_addr: is_binary = True if not addr_to_update.binary_bit_pos is None else False + if is_binary: if addr_to_update.ram_address in ram_addr_dict.keys(): current_bin_value = ram_addr_dict[addr_to_update.ram_address][0] + else: - current_bin_value = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [( - addr_to_update.ram_address, addr_to_update.bit_size, "MainRAM")]))[0], "little") + current_bin_value = int.from_bytes( + ( + await bizhawk.read( + ctx.bizhawk_ctx, + [ + ( + addr_to_update.ram_address, + addr_to_update.byte_size, + "MainRAM", + ) + ], + ) + )[0], + "little", + ) + if GrinchLocation.get_apid(item_data.id) in list_recv_itemids: - current_bin_value |= (1 << addr_to_update.binary_bit_pos) + current_bin_value |= 1 << addr_to_update.binary_bit_pos + else: current_bin_value &= ~(1 << addr_to_update.binary_bit_pos) ram_addr_dict[addr_to_update.ram_address] = [current_bin_value, 1] + else: if GrinchLocation.get_apid(item_data.id) in list_recv_itemids: - ram_addr_dict[addr_to_update.ram_address] = [addr_to_update.value, addr_to_update.bit_size] - else: - ram_addr_dict[addr_to_update.ram_address] = [0, addr_to_update.bit_size] + ram_addr_dict[addr_to_update.ram_address] = [ + addr_to_update.value, + addr_to_update.byte_size, + ] - await bizhawk.write(ctx.bizhawk_ctx, self.convert_dict_to_ram_list(ram_addr_dict)) + else: + ram_addr_dict[addr_to_update.ram_address] = [ + 0, + addr_to_update.byte_size, + ] + + await bizhawk.write( + ctx.bizhawk_ctx, self.convert_dict_to_ram_list(ram_addr_dict) + ) async def ingame_checker(self, ctx: "BizHawkClientContext"): from CommonClient import logger - ingame_map_id = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [( - 0x010000, 1, "MainRAM")]))[0], "little") - initial_cutscene_checker = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [( - 0x010094, 1, "MainRAM")]))[0], "little") + ingame_map_id = int.from_bytes( + (await bizhawk.read(ctx.bizhawk_ctx, [(0x010000, 1, "MainRAM")]))[0], + "little", + ) + initial_cutscene_checker = int.from_bytes( + (await bizhawk.read(ctx.bizhawk_ctx, [(0x010094, 1, "MainRAM")]))[0], + "little", + ) - #If not in game or at a menu, or loading the publisher logos + # If not in game or at a menu, or loading the publisher logos if ingame_map_id <= 0x04 or ingame_map_id >= 0x35: self.ingame_log = False return False - #If grinch has changed maps + # If grinch has changed maps if not ingame_map_id == self.last_map_location: # If the last "map" we were on was a menu or a publisher logo if self.last_map_location in MENU_MAP_IDS: # Reset our demo mode checker just in case the game is in demo mode. self.demo_mode_buffer = 0 self.ingame_log = False + if initial_cutscene_checker != 1: return False @@ -358,27 +557,42 @@ class GrinchClient(BizHawkClient): self.demo_mode_buffer += 1 return False - demo_mode = int.from_bytes((await bizhawk.read(ctx.bizhawk_ctx, [( - 0x01008A, 1, "MainRAM")]))[0], "little") + demo_mode = int.from_bytes( + (await bizhawk.read(ctx.bizhawk_ctx, [(0x01008A, 1, "MainRAM")]))[0], + "little", + ) + if demo_mode == 1: return False if not self.ingame_log: logger.info("You can now start sending locations from the Grinch!") self.ingame_log = True + return True async def option_handler(self, ctx: "BizHawkClientContext"): if self.loc_unlimited_eggs: - await bizhawk.write(ctx.bizhawk_ctx, [(EGG_COUNT_ADDR, MAX_EGGS.to_bytes(2,"little"), "MainRAM")]) + await bizhawk.write( + ctx.bizhawk_ctx, + [(EGG_COUNT_ADDR, MAX_EGGS.to_bytes(2, "little"), "MainRAM")], + ) async def ring_link_output(self, ctx: "BizHawkClientContext"): from CommonClient import logger + while self.send_ring_link and ctx.slot: try: current_egg_count = int.from_bytes( - (await bizhawk.read(ctx.bizhawk_ctx, [(EGG_COUNT_ADDR, EGG_ADDR_BYTESIZE, "MainRAM")]))[0], "little") + ( + await bizhawk.read( + ctx.bizhawk_ctx, + [(EGG_COUNT_ADDR, EGG_ADDR_BYTESIZE, "MainRAM")], + ) + )[0], + "little", + ) if (current_egg_count - self.previous_egg_count) != 0: msg = { @@ -386,29 +600,55 @@ class GrinchClient(BizHawkClient): "data": { "time": time.time(), "source": self.unique_client_id, - "amount": current_egg_count - self.previous_egg_count + "amount": current_egg_count - self.previous_egg_count, }, - "tags": ["RingLink"] + "tags": ["RingLink"], } await ctx.send_msgs([msg]) self.previous_egg_count = current_egg_count # logger.info(f"RingLink: You sent {str(current_egg_count - self.previous_egg_count)} rotten eggs.") + await asyncio.sleep(0.1) + except Exception as ex: - logger.error("While monitoring grinch's egg count ingame, an error occurred. Details:"+ str(ex)) + logger.error( + "While monitoring grinch's egg count ingame, an error occurred. Details:" + + str(ex) + ) self.send_ring_link = False if not ctx.slot: - logger.info("You must be connected to the multi-world in order for RingLink to work properly.") + logger.info( + "You must be connected to the multi-world in order for RingLink to work properly." + ) async def ring_link_input(self, egg_amount: int, ctx: "BizHawkClientContext"): from CommonClient import logger + game_egg_count = int.from_bytes( - (await bizhawk.read(ctx.bizhawk_ctx, [(EGG_COUNT_ADDR, EGG_ADDR_BYTESIZE, "MainRAM")]))[0], "little") - non_neg_eggs = game_egg_count + egg_amount if game_egg_count + egg_amount > 0 else 0 + ( + await bizhawk.read( + ctx.bizhawk_ctx, [(EGG_COUNT_ADDR, EGG_ADDR_BYTESIZE, "MainRAM")] + ) + )[0], + "little", + ) + non_neg_eggs = ( + game_egg_count + egg_amount if game_egg_count + egg_amount > 0 else 0 + ) current_egg_count = min(non_neg_eggs, MAX_EGGS) - await bizhawk.write(ctx.bizhawk_ctx, [(EGG_COUNT_ADDR, - int(current_egg_count).to_bytes(EGG_ADDR_BYTESIZE, "little"), "MainRAM")]) + + await bizhawk.write( + ctx.bizhawk_ctx, + [ + ( + EGG_COUNT_ADDR, + int(current_egg_count).to_bytes(EGG_ADDR_BYTESIZE, "little"), + "MainRAM", + ) + ], + ) + self.previous_egg_count = current_egg_count # logger.info(f"RingLink: You received {str(egg_amount)} rotten eggs.") @@ -419,18 +659,27 @@ class GrinchClient(BizHawkClient): uid += ord(char) return uid + def _cmd_ringlink(self): """Toggle ringling from client. Overrides default setting.""" if not self.ctx.slot: return - Utils.async_start(_update_ring_link(self.ctx, not "RingLink" in self.ctx.tags), name="Update RingLink") + + Utils.async_start( + _update_ring_link(self.ctx, not "RingLink" in self.ctx.tags), + name="Update RingLink", + ) + async def _update_ring_link(ctx: "BizHawkClientContext", ring_link: bool): """Helper function to set Ring Link connection tag on/off and update the connection if already connected.""" old_tags = copy.deepcopy(ctx.tags) + if ring_link: ctx.tags.add("RingLink") + else: ctx.tags -= {"RingLink"} + if old_tags != ctx.tags and ctx.server and not ctx.server.socket.closed: - await ctx.send_msgs([{"cmd": "ConnectUpdate", "tags": ctx.tags}]) \ No newline at end of file + await ctx.send_msgs([{"cmd": "ConnectUpdate", "tags": ctx.tags}]) diff --git a/worlds/grinch/Items.py b/worlds/grinch/Items.py index 75d48ca2..402800b7 100644 --- a/worlds/grinch/Items.py +++ b/worlds/grinch/Items.py @@ -1,32 +1,41 @@ from typing import NamedTuple, Optional -from .RamHandler import GrinchRamData +from .RamHandler import GrinchRamData, UpdateMethod from BaseClasses import Item -from BaseClasses import ItemClassification as IC #IC can be any name, saves having to type the whole word in code +from BaseClasses import ( + ItemClassification as IC, +) # IC can be any name, saves having to type the whole word in code + class GrinchItemData(NamedTuple): - item_group: list[str] #arbituary that can be whatever it can be, basically the field/property for item groups + item_group: list[ + str + ] # arbituary that can be whatever it can be, basically the field/property for item groups id: Optional[int] classification: IC update_ram_addr: list[GrinchRamData] + class GrinchItem(Item): game: str = "The Grinch" - #Tells server what item id it is + # Tells server what item id it is @staticmethod def get_apid(id: int): - #If you give me an input id, I will return the Grinch equivalent server/ap id + # If you give me an input id, I will return the Grinch equivalent server/ap id base_id: int = 42069 return base_id + id if id is not None else None def __init__(self, name: str, player: int, data: GrinchItemData): - super(GrinchItem, self).__init__(name,data.classification, GrinchItem.get_apid(data.id), player) + super(GrinchItem, self).__init__( + name, data.classification, GrinchItem.get_apid(data.id), player + ) self.type = data.item_group self.item_id = data.id -#allows hinting of items via category + +# allows hinting of items via category def get_item_names_per_category() -> dict[str, set[str]]: categories: dict[str, set[str]] = {} @@ -36,123 +45,306 @@ def get_item_names_per_category() -> dict[str, set[str]]: return categories -REL: str = "Rotten Egg Launcher" -RS: str = "Rocket Spring" -SS: str = "Slime Shooter" -OCD: str = "Octopus Climbing Device" -MM: str = "Marine Mobile" -GC: str = "Grinch Copter" -WV: str = "Whoville Vacuum Tube" -WF: str = "Who Forest Vacuum Tube" -WD: str = "Who Dump Vacuum Tube" -WL: str = "Who Lake Vacuum Tube" -VT: str = "Progressive Vacuum Tube" -PC: str = "Pancake" -SR: str = "Sleigh Room Key" -BB: str = "Bad Breath" -SZ: str = "Seize" -MX: str = "Max" -SN: str = "Sneak" -WC: str = "Who Cloak" -PB: str = "Painting Bucket" -SC: str = "Scissors" -GB: str = "Glue Bucket" -CCAC: str = "Cable Car Access Card" -DRL: str = "Drill" -RP: str = "Rope" -HK: str = "Hook" -ST: str = "Sculpting Tools" -HMR: str = "Hammer" -SCL: str = "Scout Clothes" -#Gadgets -#All gadgets require at least 4 different blueprints to be unlocked in the computer in Mount Crumpit. +class grinch_items: + class gadgets: + BINOCULARS: str = "Binoculars" + ROCKET_EGG_LAUNCHER: str = "Rotten Egg Launcher" + ROCKET_SPRING: str = "Rocket Spring" + SLIME_SHOOTER: str = "Slime Shooter" + OCTOPUS_CLIMBING_DEVICE: str = "Octopus Climbing Device" + MARINE_MOBILE: str = "Marine Mobile" + GRINCH_COPTER: str = "Grinch Copter" + + class keys: + WHOVILLE: str = "Whoville Vacuum Tube" + WHO_FOREST: str = "Who Forest Vacuum Tube" + WHO_DUMP: str = "Who Dump Vacuum Tube" + WHO_LAKE: str = "Who Lake Vacuum Tube" + PROGRESSIVE_VACUUM_TUBE: str = "Progressive Vacuum Tube" + SLEIGH_ROOM_KEY: str = "Sleigh Room Key" + + class moves: + PANCAKE: str = "Pancake" + BAD_BREATH: str = "Bad Breath" + SIEZE: str = "Seize" + MAX: str = "Max" + SNEAK: str = "Sneak" + + class level_items: + WV_WHO_CLOAK: str = "Who Cloak" + WV_PAINT_BUCKET: str = "Painting Bucket" + WV_HAMMER: str = "Hammer" + WV_SCULPTIN_TOOLS: str = "Sculpting Tools" + WF_GLUE_BUCKET: str = "Glue Bucket" + WF_CABLE_CAR_ACCESS_CARD: str = "Cable Car Access Card" + WD_SCISSORS: str = "Scissors" + WL_ROPE: str = "Rope" + WL_HOOK: str = "Hook" + WL_DRILLL: str = "Drill" + WL_SCOUT_CLOTHES: str = "Scout Clothes" + + class useful_items: + HEART_OF_STONE: str = "Heart of Stone" + + class trap_items: + DEPLETION_TRAP: str = "Depletion Trap" + DUMP_IT_TO_CRUMPIT: str = "Dump it to Crumpit" + WHO_SENT_ME_BACK: str = "Who sent me back?" + + +class grinch_categories: + FILLER: str = "Filler" + GADGETS: str = "Gadgets" + HEALING_ITEMS: str = "Healing Items" + MISSION_SPECIFIC_ITEMS: str = "Mission Specific Items" + MOVES: str = "Moves" + REQUIRED_ITEM: str = "Required Items" + ROTTEN_EGG_BUNDLES: str = "Rotten Egg Bundles" + SLEIGH_ROOM: str = "Sleigh Room" + TRAPS: str = "Traps" + USEFUL_ITEMS: str = "Useful Items" + VACUUM_TUBES: str = "Vacuum Tubes" + + +# Gadgets +# All gadgets require at least 4 different blueprints to be unlocked in the computer in Mount Crumpit. GADGETS_TABLE: dict[str, GrinchItemData] = { - "Binoculars": GrinchItemData(["Gadgets"], 100, IC.useful, - [GrinchRamData(0x0102B6, value=0x40), GrinchRamData(0x0102B7, value=0x41), - GrinchRamData(0x0102B8, value=0x44), GrinchRamData(0x0102B9, value=0x45), - # GrinchRamData(0x0100BC, binary_bit_pos=0) - ]), - "Rotten Egg Launcher": GrinchItemData(["Gadgets"], 101, IC.progression, - [GrinchRamData(0x0102BA, value=0x40), GrinchRamData(0x0102BB, value=0x41), - GrinchRamData(0x0102BC, value=0x44), GrinchRamData(0x0102BD, value=0x45), - # GrinchRamData(0x0100BC, binary_bit_pos=1) - ]), - "Rocket Spring": GrinchItemData(["Gadgets"], 102, IC.progression, - [GrinchRamData(0x0102BE, value=0x40), GrinchRamData(0x0102BF, value=0x41), - GrinchRamData(0x0102C0, value=0x42), GrinchRamData(0x0102C1, value=0x44), - GrinchRamData(0x0102C2, value=0x45), GrinchRamData(0x0102C3, value=0x46), - GrinchRamData(0x0102C4, value=0x48), GrinchRamData(0x0102C5, value=0x49), - GrinchRamData(0x0102C6, value=0x4A), - # GrinchRamData(0x0100BC, binary_bit_pos=2) - ]), - "Slime Shooter": GrinchItemData(["Gadgets", "Slime Gun"], 103, IC.progression, - [GrinchRamData(0x0102C7, value=0x40), GrinchRamData(0x0102C8, value=0x41), - GrinchRamData(0x0102C9, value=0x42), GrinchRamData(0x0102CA, value=0x44), - GrinchRamData(0x0102CB, value=0x45), GrinchRamData(0x0102CC, value=0x46), - GrinchRamData(0x0102CD, value=0x48), GrinchRamData(0x0102CE, value=0x49), - GrinchRamData(0x0102CF, value=0x4A), - # GrinchRamData(0x0100BC, binary_bit_pos=3) - ]), - "Octopus Climbing Device": GrinchItemData(["Gadgets"], 104, IC.progression, - [GrinchRamData(0x0102D0, value=0x40), GrinchRamData(0x0102D1, value=0x41), - GrinchRamData(0x0102D2, value=0x42), GrinchRamData(0x0102D3, value=0x44), - GrinchRamData(0x0102D4, value=0x45), GrinchRamData(0x0102D5, value=0x46), - GrinchRamData(0x0102D6, value=0x48), GrinchRamData(0x0102D7, value=0x49), - GrinchRamData(0x0102D8, value=0x4A), - # GrinchRamData(0x0100BC, binary_bit_pos=4) - ]), - "Marine Mobile": GrinchItemData(["Gadgets"], 105, IC.progression, - [GrinchRamData(0x0102D9, value=0x40), GrinchRamData(0x0102DA, value=0x41), - GrinchRamData(0x0102DB, value=0x42), GrinchRamData(0x0102DC, value=0x43), - GrinchRamData(0x0102DD, value=0x44), GrinchRamData(0x0102DE, value=0x45), - GrinchRamData(0x0102DF, value=0x46), GrinchRamData(0x0102E0, value=0x47), - GrinchRamData(0x0102E1, value=0x48), GrinchRamData(0x0102E2, value=0x49), - GrinchRamData(0x0102E3, value=0x4A), GrinchRamData(0x0102E4, value=0x4B), - GrinchRamData(0x0102E5, value=0x4C), GrinchRamData(0x0102E6, value=0x4D), - GrinchRamData(0x0102E7, value=0x4E), GrinchRamData(0x0102E8, value=0x4F), - # GrinchRamData(0x0100BC, binary_bit_pos=5) - ]), - "Grinch Copter": GrinchItemData(["Gadgets"], 106, IC.progression, - [GrinchRamData(0x0102E9, value=0x40), GrinchRamData(0x0102EA, value=0x41), - GrinchRamData(0x0102EB, value=0x42), GrinchRamData(0x0102EC, value=0x43), - GrinchRamData(0x0102ED, value=0x44), GrinchRamData(0x0102EE, value=0x45), - GrinchRamData(0x0102EF, value=0x46), GrinchRamData(0x0102F0, value=0x47), - GrinchRamData(0x0102F1, value=0x48), GrinchRamData(0x0102F2, value=0x49), - GrinchRamData(0x0102F3, value=0x4A), GrinchRamData(0x0102F4, value=0x4B), - GrinchRamData(0x0102F5, value=0x4C), GrinchRamData(0x0102F6, value=0x4D), - GrinchRamData(0x0102F7, value=0x4E), GrinchRamData(0x0102F8, value=0x4F), - # GrinchRamData(0x0100BC, binary_bit_pos=6) - ]) + grinch_items.gadgets.BINOCULARS: GrinchItemData( + [grinch_categories.GADGETS], + 100, + IC.useful, + [ + GrinchRamData(0x0102B6, value=0x40), + GrinchRamData(0x0102B7, value=0x41), + GrinchRamData(0x0102B8, value=0x44), + GrinchRamData(0x0102B9, value=0x45), + # GrinchRamData(0x0100BC, binary_bit_pos=0) + ], + ), + grinch_items.gadgets.ROCKET_EGG_LAUNCHER: GrinchItemData( + [grinch_categories.GADGETS], + 101, + IC.progression, + [ + GrinchRamData(0x0102BA, value=0x40), + GrinchRamData(0x0102BB, value=0x41), + GrinchRamData(0x0102BC, value=0x44), + GrinchRamData(0x0102BD, value=0x45), + # GrinchRamData(0x0100BC, binary_bit_pos=1) + ], + ), + grinch_items.gadgets.ROCKET_SPRING: GrinchItemData( + [grinch_categories.GADGETS], + 102, + IC.progression, + [ + GrinchRamData(0x0102BE, value=0x40), + GrinchRamData(0x0102BF, value=0x41), + GrinchRamData(0x0102C0, value=0x42), + GrinchRamData(0x0102C1, value=0x44), + GrinchRamData(0x0102C2, value=0x45), + GrinchRamData(0x0102C3, value=0x46), + GrinchRamData(0x0102C4, value=0x48), + GrinchRamData(0x0102C5, value=0x49), + GrinchRamData(0x0102C6, value=0x4A), + # GrinchRamData(0x0100BC, binary_bit_pos=2) + ], + ), + grinch_items.gadgets.SLIME_SHOOTER: GrinchItemData( + [ + grinch_categories.GADGETS, + "Slime Gun", # For canon --MarioSpore + ], + 103, + IC.progression, + [ + GrinchRamData(0x0102C7, value=0x40), + GrinchRamData(0x0102C8, value=0x41), + GrinchRamData(0x0102C9, value=0x42), + GrinchRamData(0x0102CA, value=0x44), + GrinchRamData(0x0102CB, value=0x45), + GrinchRamData(0x0102CC, value=0x46), + GrinchRamData(0x0102CD, value=0x48), + GrinchRamData(0x0102CE, value=0x49), + GrinchRamData(0x0102CF, value=0x4A), + # GrinchRamData(0x0100BC, binary_bit_pos=3) + ], + ), + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE: GrinchItemData( + [grinch_categories.GADGETS], + 104, + IC.progression, + [ + GrinchRamData(0x0102D0, value=0x40), + GrinchRamData(0x0102D1, value=0x41), + GrinchRamData(0x0102D2, value=0x42), + GrinchRamData(0x0102D3, value=0x44), + GrinchRamData(0x0102D4, value=0x45), + GrinchRamData(0x0102D5, value=0x46), + GrinchRamData(0x0102D6, value=0x48), + GrinchRamData(0x0102D7, value=0x49), + GrinchRamData(0x0102D8, value=0x4A), + # GrinchRamData(0x0100BC, binary_bit_pos=4) + ], + ), + grinch_items.gadgets.MARINE_MOBILE: GrinchItemData( + [grinch_categories.GADGETS], + 105, + IC.progression, + [ + GrinchRamData(0x0102D9, value=0x40), + GrinchRamData(0x0102DA, value=0x41), + GrinchRamData(0x0102DB, value=0x42), + GrinchRamData(0x0102DC, value=0x43), + GrinchRamData(0x0102DD, value=0x44), + GrinchRamData(0x0102DE, value=0x45), + GrinchRamData(0x0102DF, value=0x46), + GrinchRamData(0x0102E0, value=0x47), + GrinchRamData(0x0102E1, value=0x48), + GrinchRamData(0x0102E2, value=0x49), + GrinchRamData(0x0102E3, value=0x4A), + GrinchRamData(0x0102E4, value=0x4B), + GrinchRamData(0x0102E5, value=0x4C), + GrinchRamData(0x0102E6, value=0x4D), + GrinchRamData(0x0102E7, value=0x4E), + GrinchRamData(0x0102E8, value=0x4F), + # GrinchRamData(0x0100BC, binary_bit_pos=5) + ], + ), + grinch_items.gadgets.GRINCH_COPTER: GrinchItemData( + [grinch_categories.GADGETS], + 106, + IC.progression, + [ + GrinchRamData(0x0102E9, value=0x40), + GrinchRamData(0x0102EA, value=0x41), + GrinchRamData(0x0102EB, value=0x42), + GrinchRamData(0x0102EC, value=0x43), + GrinchRamData(0x0102ED, value=0x44), + GrinchRamData(0x0102EE, value=0x45), + GrinchRamData(0x0102EF, value=0x46), + GrinchRamData(0x0102F0, value=0x47), + GrinchRamData(0x0102F1, value=0x48), + GrinchRamData(0x0102F2, value=0x49), + GrinchRamData(0x0102F3, value=0x4A), + GrinchRamData(0x0102F4, value=0x4B), + GrinchRamData(0x0102F5, value=0x4C), + GrinchRamData(0x0102F6, value=0x4D), + GrinchRamData(0x0102F7, value=0x4E), + GrinchRamData(0x0102F8, value=0x4F), + # GrinchRamData(0x0100BC, binary_bit_pos=6) + ], + ), } -#Mission Specific Items +# Mission Specific Items MISSION_ITEMS_TABLE: dict[str, GrinchItemData] = { - "Who Cloak": GrinchItemData(["Mission Specific Items", "Useful Items"], 200, IC.progression, - [GrinchRamData(0x0101F9, binary_bit_pos=0)]), - "Painting Bucket": GrinchItemData(["Mission Specific Items", "Useful Items"], 201, IC.progression_deprioritized, - [GrinchRamData(0x0101F9, binary_bit_pos=1)]), - "Scissors": GrinchItemData(["Mission Specific Items", "Useful Items"], 202, IC.progression_deprioritized, - [GrinchRamData(0x0101F9, binary_bit_pos=6), GrinchRamData(0x0100C2, binary_bit_pos=1)]), - "Glue Bucket": GrinchItemData(["Mission Specific Items", "Useful Items"], 203, IC.progression_deprioritized, - [GrinchRamData(0x0101F9, binary_bit_pos=4)]), - "Cable Car Access Card": GrinchItemData(["Mission Specific Items", "Useful Items"], 204, IC.progression, - [GrinchRamData(0x0101F9, binary_bit_pos=5)]), - "Drill": GrinchItemData(["Mission Specific Items", "Useful Items"], 205, IC.progression_deprioritized, - [GrinchRamData(0x0101FA, binary_bit_pos=2)]), - "Rope": GrinchItemData(["Mission Specific Items", "Useful Items"], 206, IC.progression_deprioritized, - [GrinchRamData(0x0101FA, binary_bit_pos=1)]), - "Hook": GrinchItemData(["Mission Specific Items", "Useful Items"], 207, IC.progression_deprioritized, - [GrinchRamData(0x0101FA, binary_bit_pos=0)]), - "Sculpting Tools": GrinchItemData(["Mission Specific Items", "Useful Items"], 208, IC.progression_deprioritized, - [GrinchRamData(0x0101F9, binary_bit_pos=2)]), - "Hammer": GrinchItemData(["Mission Specific Items", "Useful Items"], 209, IC.progression_deprioritized, - [GrinchRamData(0x0101F9, binary_bit_pos=3)]), - "Scout Clothes": GrinchItemData(["Mission Specific Items", "Useful Items"], 210, IC.progression, - [GrinchRamData(0x0101F9, binary_bit_pos=7)]) + grinch_items.level_items.WV_WHO_CLOAK: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 200, + IC.progression, + [GrinchRamData(0x0101F9, binary_bit_pos=0)], + ), + grinch_items.level_items.WV_PAINT_BUCKET: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 201, + IC.progression_deprioritized, + [GrinchRamData(0x0101F9, binary_bit_pos=1)], + ), + grinch_items.level_items.WD_SCISSORS: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 202, + IC.progression_deprioritized, + [ + GrinchRamData(0x0101F9, binary_bit_pos=6), + GrinchRamData(0x0100C2, binary_bit_pos=1), + ], + ), + grinch_items.level_items.WF_GLUE_BUCKET: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 203, + IC.progression_deprioritized, + [GrinchRamData(0x0101F9, binary_bit_pos=4)], + ), + grinch_items.level_items.WF_CABLE_CAR_ACCESS_CARD: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 204, + IC.progression, + [GrinchRamData(0x0101F9, binary_bit_pos=5)], + ), + grinch_items.level_items.WL_DRILLL: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 205, + IC.progression_deprioritized, + [GrinchRamData(0x0101FA, binary_bit_pos=2)], + ), + grinch_items.level_items.WL_ROPE: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 206, + IC.progression_deprioritized, + [GrinchRamData(0x0101FA, binary_bit_pos=1)], + ), + grinch_items.level_items.WL_HOOK: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 207, + IC.progression_deprioritized, + [GrinchRamData(0x0101FA, binary_bit_pos=0)], + ), + grinch_items.level_items.WV_SCULPTIN_TOOLS: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 208, + IC.progression_deprioritized, + [GrinchRamData(0x0101F9, binary_bit_pos=2)], + ), + grinch_items.level_items.WV_HAMMER: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 209, + IC.progression_deprioritized, + [GrinchRamData(0x0101F9, binary_bit_pos=3)], + ), + grinch_items.level_items.WL_SCOUT_CLOTHES: GrinchItemData( + [ + grinch_categories.MISSION_SPECIFIC_ITEMS, + grinch_categories.USEFUL_ITEMS, + ], + 210, + IC.progression, + [GrinchRamData(0x0101F9, binary_bit_pos=7)], + ), } -#Sleigh Parts +# Sleigh Parts # SLEIGH_PARTS_TABLE: dict[str, GrinchItemData] = { # "Exhaust Pipes": GrinchItemData(["Sleigh Parts"], 300, IC.progression_skip_balancing, # [GrinchRamData(0x0101FB, binary_bit_pos=2)]), @@ -166,16 +358,32 @@ MISSION_ITEMS_TABLE: dict[str, GrinchItemData] = { # [GrinchRamData(0x0101FB, binary_bit_pos=6)]) # } -#Access Keys +# Access Keys KEYS_TABLE: dict[str, GrinchItemData] = { - "Whoville Vacuum Tube": GrinchItemData(["Vacuum Tubes"], 400, IC.progression, - [GrinchRamData(0x010200, binary_bit_pos=1)]), - "Who Forest Vacuum Tube": GrinchItemData(["Vacuum Tubes"], 401, IC.progression, - [GrinchRamData(0x0100AA, binary_bit_pos=2)]), - "Who Dump Vacuum Tube": GrinchItemData(["Vacuum Tubes"], 402, IC.progression, - [GrinchRamData(0x0100AA, binary_bit_pos=3)]), - "Who Lake Vacuum Tube": GrinchItemData(["Vacuum Tubes"], 403, IC.progression, - [GrinchRamData(0x0100AA, binary_bit_pos=4)]), + grinch_items.keys.WHOVILLE: GrinchItemData( + [grinch_categories.VACUUM_TUBES], + 400, + IC.progression, + [GrinchRamData(0x010200, binary_bit_pos=1)], + ), + grinch_items.keys.WHO_FOREST: GrinchItemData( + [grinch_categories.VACUUM_TUBES], + 401, + IC.progression, + [GrinchRamData(0x0100AA, binary_bit_pos=2)], + ), + grinch_items.keys.WHO_DUMP: GrinchItemData( + [grinch_categories.VACUUM_TUBES], + 402, + IC.progression, + [GrinchRamData(0x0100AA, binary_bit_pos=3)], + ), + grinch_items.keys.WHO_LAKE: GrinchItemData( + [grinch_categories.VACUUM_TUBES], + 403, + IC.progression, + [GrinchRamData(0x0100AA, binary_bit_pos=4)], + ), # "Progressive Vacuum Tube": GrinchItemData(["Vacuum Tubes"], 404, IC.progression, # [GrinchRamData()]), # "Spin N' Win Door Unlock": GrinchItemData(["Supadow Door Unlocks"], 405, IC.progression, @@ -188,71 +396,196 @@ KEYS_TABLE: dict[str, GrinchItemData] = { # [GrinchRamData()]), # "Bike Race Access": GrinchItemData(["Supadow Door Unlocks", 409, IC.progression, # [GrinchRamData()]) - "Sleigh Room Key": GrinchItemData(["Sleigh Room"], 410, IC.progression, - [GrinchRamData(0x010200, binary_bit_pos=6), GrinchRamData(0x0100AA, binary_bit_pos=5)]) + grinch_items.keys.SLEIGH_ROOM_KEY: GrinchItemData( + [ + grinch_categories.SLEIGH_ROOM, + grinch_categories.REQUIRED_ITEM, + ], + 410, + IC.progression, + [ + GrinchRamData(0x010200, binary_bit_pos=6), + GrinchRamData(0x0100AA, binary_bit_pos=5), + ], + ), } -#Misc Items +# Misc Items MISC_ITEMS_TABLE: dict[str, GrinchItemData] = { # This item may not function properly if you receive it during a loading screen or in Mount Crumpit # "Fully Healed Grinch": GrinchItemData(["Health Items", "Filler"], 500, IC.filler, # [GrinchRamData(0x0E8FDC, value=120)]), - "5 Rotten Eggs": GrinchItemData(["Rotten Egg Bundles", "Filler"], 502, IC.filler, - [GrinchRamData(0x010058, value=5, update_existing_value=True, max_count=200, bit_size=2)]), - "10 Rotten Eggs": GrinchItemData(["Rotten Egg Bundles", "Filler"], 503, IC.filler, - [GrinchRamData(0x010058, value=10, update_existing_value=True, max_count=200, bit_size=2)]), - "20 Rotten Eggs": GrinchItemData(["Rotten Egg Bundles", "Filler"], 504, IC.filler, - [GrinchRamData(0x010058, value=20, update_existing_value=True, max_count=200, bit_size=2)]) + "5 Rotten Eggs": GrinchItemData( + [ + grinch_categories.ROTTEN_EGG_BUNDLES, + grinch_categories.FILLER, + ], + 502, + IC.filler, + [ + GrinchRamData( + 0x010058, + value=5, + update_method=UpdateMethod.ADD, + max_count=200, + byte_size=2, + ) + ], + ), + "10 Rotten Eggs": GrinchItemData( + [ + grinch_categories.ROTTEN_EGG_BUNDLES, + grinch_categories.FILLER, + ], + 503, + IC.filler, + [ + GrinchRamData( + 0x010058, + value=10, + update_method=UpdateMethod.ADD, + max_count=200, + byte_size=2, + ) + ], + ), + "20 Rotten Eggs": GrinchItemData( + [ + grinch_categories.ROTTEN_EGG_BUNDLES, + grinch_categories.FILLER, + ], + 504, + IC.filler, + [ + GrinchRamData( + 0x010058, + value=20, + update_method=UpdateMethod.ADD, + max_count=200, + byte_size=2, + ) + ], + ), } -USEFUL_IC_TABLE: dict[str, GrinchItemData] = { - "Heart of Stone": GrinchItemData(["Health Items"], 501, IC.useful, - [GrinchRamData(0x0100ED, value=1, update_existing_value=True, max_count=4)]) +USEFUL_ITEMS_TABLE: dict[str, GrinchItemData] = { + grinch_items.useful_items.HEART_OF_STONE: GrinchItemData( + [ + grinch_categories.USEFUL_ITEMS, + grinch_categories.HEALING_ITEMS, + ], + 501, + IC.useful, + [ + GrinchRamData( + 0x0100ED, + value=1, + update_method=UpdateMethod.ADD, + max_count=4, + ) + ], + ) } -#Traps +# Traps TRAPS_TABLE: dict[str, GrinchItemData] = { -# alias to Ice Trap for traplink + # alias to Ice Trap for traplink # "Freeze Trap": GrinchItemData(["Traps"], 600, IC.trap, [GrinchRamData()]), # "Bee Trap": GrinchItemData(["Traps"], 601, IC.trap, [GrinchRamData()]), # "Electrocution Trap": GrinchItemData(["Traps"], 602, IC.trap, [GrinchRamData()]), -# alias to Slowness Trap for traplink + # alias to Slowness Trap for traplink # "Tip Toe Trap": GrinchItemData(["Traps"], 603, IC.trap, [GrinchRamData()]), -# This item may not function properly if you receive it during a loading screen or in Mount Crumpit -# alias to Exhaustion Trap -# "Damage Trap": GrinchItemData(["Traps"], 604, IC.trap, [GrinchRamData(0x0E8FDC, value=-20, update_existing_value=True)]), - "Depletion Trap": GrinchItemData(["Traps"], 605, IC.trap, [GrinchRamData(0x010058, value=0, bit_size=2)]), - "Dump it to Crumpit": GrinchItemData(["Traps"], 606, IC.trap, #Alias to Home Trap for traplink - [GrinchRamData(0x010000, value=0x05), GrinchRamData(0x08FB94, value=1), GrinchRamData(0x0100B4, value=0)]), -#alias to Spring Trap for traplink + # This item may not function properly if you receive it during a loading screen or in Mount Crumpit + # alias to Exhaustion Trap + # "Damage Trap": GrinchItemData(["Traps"], 604, IC.trap, [GrinchRamData(0x0E8FDC, value=-20, update_method=UpdateMethod.ADD)]), + grinch_items.trap_items.DEPLETION_TRAP: GrinchItemData( + [grinch_categories.TRAPS], + 605, + IC.trap, + [GrinchRamData(0x010058, value=0, byte_size=2)], + ), + grinch_items.trap_items.DUMP_IT_TO_CRUMPIT: GrinchItemData( + [grinch_categories.TRAPS], + 606, + IC.trap, # Alias to Home Trap for traplink + [ + GrinchRamData(0x010000, value=0x05), + GrinchRamData(0x08FB94, value=1), + GrinchRamData(0x0100B4, value=0), + ], + ), + # alias to Spring Trap for traplink # "Rocket Spring Trap": GrinchItemData(["Traps"], 607, IC.trap, [GrinchRamData()]), -#alias to Home Trap for traplink - "Who sent me back?": GrinchItemData(["Traps"], 608, IC.trap, [GrinchRamData(0x08FB94, value=1)]), + # alias to Home Trap for traplink + grinch_items.trap_items.WHO_SENT_ME_BACK: GrinchItemData( + [grinch_categories.TRAPS], + 608, + IC.trap, + [ + GrinchRamData(0x08FB94, value=1), + ], + ), # "Cutscene Trap": GrinchItemData(["Traps"], 609, IC.trap, [GrinchRamData()]), # "No Vac Trap": GrinchItemData(["Traps"], 610, IC.trap, [GrinchRamData(0x0102DA, value=0]), - # "Invisible Trap": GrinchItemData(["Traps"], 611, IC.trap, [GrinchRamData(0x0102DA, value=0, bit_size=4)]) + # "Invisible Trap": GrinchItemData(["Traps"], 611, IC.trap, [GrinchRamData(0x0102DA, value=0, byte_size=4)]) # "Child Trap": GrinchItemData(["Traps"], 612, IC.trap,[GrinchRamData()]) # "Disable Jump Trap": GrinchItemData(["Traps"], 613, IC.trap,[GrinchRamData(0x010026, binary_bit_pos=6)]) } -#Movesets -# MOVES_TABLE: dict[str, GrinchItemData] = { -# "Bad Breath": GrinchItemData(["Movesets"], 700, IC.progression, [GrinchRamData(0x0100BB, binary_bit_pos=1)]), -# "Pancake": GrinchItemData(["Movesets"], 701, IC.progression, [GrinchRamData(0x0100BB, binary_bit_pos=2)]), -# "Push & Pull": GrinchItemData(["Movesets"], 702, IC.progression, [GrinchRamData(0x0100BB, binary_bit_pos=3)]), -# "Max": GrinchItemData(["Movesets"], 703, IC.progression, [GrinchRamData(0x0100BB, binary_bit_pos=4)]), -# "Tip Toe": GrinchItemData(["Movesets"], 704, IC.progression, [GrinchRamData(0x0100BB, binary_bit_pos=5)]) -# } -#Double star combines all dictionaries from each individual list together +# Movesets +MOVES_TABLE: dict[str, GrinchItemData] = { + grinch_items.moves.BAD_BREATH: GrinchItemData( + [grinch_categories.MOVES], + 700, + IC.progression, + [ + GrinchRamData(0x0100BB, binary_bit_pos=1), + ], + ), + grinch_items.moves.PANCAKE: GrinchItemData( + [grinch_categories.MOVES], + 701, + IC.progression, + [ + GrinchRamData(0x0100BB, binary_bit_pos=2), + ], + ), + grinch_items.moves.SIEZE: GrinchItemData( + [grinch_categories.MOVES], + 702, + IC.progression, + [ + GrinchRamData(0x0100BB, binary_bit_pos=3), + ], + ), + grinch_items.moves.MAX: GrinchItemData( + [grinch_categories.MOVES], + 703, + IC.progression, + [ + GrinchRamData(0x0100BB, binary_bit_pos=4), + ], + ), + grinch_items.moves.SNEAK: GrinchItemData( + [grinch_categories.MOVES], + 704, + IC.progression, + [ + GrinchRamData(0x0100BB, binary_bit_pos=5), + ], + ), +} + +# Double star combines all dictionaries from each individual list together ALL_ITEMS_TABLE: dict[str, GrinchItemData] = { **GADGETS_TABLE, **MISSION_ITEMS_TABLE, **KEYS_TABLE, **MISC_ITEMS_TABLE, **TRAPS_TABLE, - **USEFUL_IC_TABLE, + **USEFUL_ITEMS_TABLE, # **SLEIGH_PARTS_TABLE, - # **MOVES_TABLE, + **MOVES_TABLE, } # Psuedocoding traplink table @@ -268,8 +601,9 @@ ALL_ITEMS_TABLE: dict[str, GrinchItemData] = { # ELEC_TRAP_EQUIV = [] # DEPL_TRAP_EQUIV = ["Dry Trap"] + def grinch_items_to_id() -> dict[str, int]: item_mappings: dict[str, int] = {} for ItemName, ItemData in ALL_ITEMS_TABLE.items(): item_mappings.update({ItemName: GrinchItem.get_apid(ItemData.id)}) - return item_mappings \ No newline at end of file + return item_mappings diff --git a/worlds/grinch/Locations.py b/worlds/grinch/Locations.py index 5df37100..fa930655 100644 --- a/worlds/grinch/Locations.py +++ b/worlds/grinch/Locations.py @@ -9,7 +9,10 @@ class GrinchLocationData(NamedTuple): location_group: Optional[list[str]] id: Optional[int] update_ram_addr: list[GrinchRamData] - reset_addr: Optional[list[GrinchRamData]] = None # Addresses to update once we find the item + reset_addr: Optional[list[GrinchRamData]] = ( + None # Addresses to update once we find the item + ) + class GrinchLocation(Location): game: str = "The Grinch" @@ -19,191 +22,1229 @@ class GrinchLocation(Location): base_id: int = 42069 return base_id + id if id is not None else None - def __init__(self, player: int, name: str, parent: Region, data: GrinchLocationData): + def __init__( + self, player: int, name: str, parent: Region, data: GrinchLocationData + ): address = None if data.id is None else GrinchLocation.get_apid(data.id) - super(GrinchLocation, self).__init__(player, name, address=address, parent=parent) + super(GrinchLocation, self).__init__( + player, name, address=address, parent=parent + ) self.code = data.id self.region = data.region self.type = data.location_group self.address = self.address + def get_location_names_per_category() -> dict[str, set[str]]: categories: dict[str, set[str]] = {} for name, data in grinch_locations.items(): if data.location_group is None: - continue + continue for group in data.location_group: # iterate over each category categories.setdefault(group, set()).add(name) return categories + grinch_locations = { -#Going to use current map id as indicator whether or not you visited a location -#Visitsanity - "WV - First Visit": GrinchLocationData("Whoville", ["Visitsanity", "Whoville"], 100, [GrinchRamData(0x010000, value=0x07)]), - "WV - Post Office - First Visit": GrinchLocationData("Post Office", ["Visitsanity", "Whoville", "Post Office"], 101, [GrinchRamData(0x010000, value=0x0A)]), - "WV - City Hall - First Visit": GrinchLocationData("City Hall", ["Visitsanity", "Whoville", "City Hall"], 102, [GrinchRamData(0x010000, value=0x08)]), - "WV - Clock Tower - First Visit": GrinchLocationData("Clock Tower", ["Visitsanity", "Whoville", "Clock Tower"], 103, [GrinchRamData(0x010000, value=0x09)]), - "WF - First Visit": GrinchLocationData("Who Forest", ["Visitsanity", "Who Forest"], 104, [GrinchRamData(0x010000, value=0x0B)]), - "WF - Ski Resort - First Visit": GrinchLocationData("Ski Resort", ["Visitsanity", "Who Forest", "Ski Resort"], 105, [GrinchRamData(0x010000, value=0x0C)]), - "WF - Civic Center - First Visit": GrinchLocationData("Civic Center", ["Visitsanity", "Who Forest", "Civic Center"], 106, [GrinchRamData(0x010000, value=0x0D)]), - "WD - First Visit": GrinchLocationData("Who Dump", ["Visitsanity", "Who Dump"], 107, [GrinchRamData(0x010000, value=0x0E)]), - "WD - Minefield - First Visit": GrinchLocationData("Minefield", ["Visitsanity", "Who Dump", "Minefield"], 108, [GrinchRamData(0x010000, value=0x11)]), - "WD - Power Plant - First Visit": GrinchLocationData("Power Plant", ["Visitsanity", "Who Dump", "Power Plant"], 109, [GrinchRamData(0x010000, value=0x10)]), - "WD - Generator Building - First Visit": GrinchLocationData("Generator Building", ["Visitsanity", "Who Dump", "Generator Building"], 110, [GrinchRamData(0x010000, value=0x0F)]), - "WL - South Shore - First Visit": GrinchLocationData("Who Lake", ["Visitsanity", "Who Lake", "South Shore"], 111, [GrinchRamData(0x010000, value=0x12)]), - "WL - Submarine World - First Visit": GrinchLocationData("Submarine World", ["Visitsanity", "Who Lake", "Submarine World"], 112, [GrinchRamData(0x010000, value=0x17)]), - "WL - Scout's Hut - First Visit": GrinchLocationData("Scout's Hut", ["Visitsanity", "Who Lake", "Scout's Hut"], 113, [GrinchRamData(0x010000, value=0x13)]), - "WL - North Shore - First Visit": GrinchLocationData("North Shore", ["Visitsanity", "Who Lake", "North Shore"], 114, [GrinchRamData(0x010000, value=0x14)]), - "WL - Mayor's Villa - First Visit": GrinchLocationData("Mayor's Villa", ["Visitsanity", "Who Lake", "Mayor's Villa"], 115, [GrinchRamData(0x010000, value=0x16)]), -#Need to find mission completion address for handful of locations that are not documented. -#Missions that have value are those ones we need to find the check for -#Whoville Missions - "WV - Post Office - Shuffling The Mail": GrinchLocationData("Post Office", ["Whoville Missions", "Missions", "Whoville", "Post Office"], 201, [GrinchRamData(0x0100BE, binary_bit_pos=0)]), - "WV - Smashing Snowmen": GrinchLocationData("Whoville", ["Whoville Missions", "Missions", "Whoville"], 200, [GrinchRamData(0x0100C5, value=10)]), - "WV - Painting The Mayor's Posters": GrinchLocationData("Whoville", ["Whoville Missions", "Missions", "Whoville"], 202, [GrinchRamData(0x0100C6, value=10)]), - "WV - Launching Eggs Into Houses": GrinchLocationData("Whoville", ["Whoville Missions", "Missions", "Whoville"], 203, [GrinchRamData(0x0100C7, value=10)]), - "WV - City Hall - Modifying The Mayor's Statue": GrinchLocationData("City Hall", ["Whoville Missions", "Missions", "Whoville", "City Hall"], 204, [GrinchRamData(0x0100BE, binary_bit_pos=1)]), - "WV - Clock Tower - Advancing The Countdown-To-Xmas Clock": GrinchLocationData("Clock Tower", ["Whoville Missions", "Missions", "Whoville", "Clock Tower"], 205, [GrinchRamData(0x0100BE, binary_bit_pos=2)]), - "WV - Squashing All Gifts": GrinchLocationData("Whoville", ["Whoville Missions", "Missions", "Giftsanity", "Whoville"], 206, [GrinchRamData(0x01005C, value=500, bit_size=2)]), -#Who Forest Missions - "WF - Making Xmas Trees Droop": GrinchLocationData("Who Forest", ["Who Forest Missions", "Missions", "Who Forest"], 300, [GrinchRamData(0x0100C8, value=10)]), - "WF - Sabotaging Snow Cannon With Glue": GrinchLocationData("Who Forest", ["Who Forest Missions", "Missions", "Who Forest"], 301, [GrinchRamData(0x0100BE, binary_bit_pos=3)]), - "WF - Putting Beehives In Cabins": GrinchLocationData("Who Forest", ["Who Forest Missions", "Missions", "Who Forest"], 302, [GrinchRamData(0x0100CA, value=10)]), - "WF - Ski Resort - Sliming The Mayor's Skis": GrinchLocationData("Ski Resort", ["Who Forest Missions", "Missions", "Who Forest", "Ski Resort"], 303, [GrinchRamData(0x0100BE, binary_bit_pos=4)]), - "WF - Civic Center - Replacing The Candles On The Cake With Fireworks": GrinchLocationData("Civic Center", ["Who Forest Missions", "Missions", "Who Forest", "Civic Center"], 304, [GrinchRamData(0x0100BE, binary_bit_pos=5)]), - "WF - Squashing All Gifts": GrinchLocationData("Who Forest", ["Who Forest Missions", "Missions", "Giftsanity", "Who Forest"], 305, [GrinchRamData(0x01005E, value=750, bit_size=2)]), -#Who Dump Missions - "WD - Stealing Food From Birds": GrinchLocationData("Who Dump", ["Who Dump Missions", "Missions", "Who Dump"], 400, [GrinchRamData(0x0100CB, value=10)]), - "WD - Feeding The Computer With Robot Parts": GrinchLocationData("Who Dump", ["Who Dump Missions", "Missions", "Who Dump"], 401, [GrinchRamData(0x0100BF, binary_bit_pos=2)]), - "WD - Infesting The Mayor's House With Rats": GrinchLocationData("Who Dump", ["Who Dump Missions", "Missions", "Who Dump"], 402, [GrinchRamData(0x0100BE, binary_bit_pos=6)]), - "WD - Conducting The Stinky Gas To Who-Bris' Shack": GrinchLocationData("Who Dump", ["Who Dump Missions", "Missions", "Who Dump"], 403, [GrinchRamData(0x0100BE, binary_bit_pos=7)]), - "WD - Minefield - Shaving Who Dump Guardian": GrinchLocationData("Minefield", ["Who Dump Missions", "Missions", "Who Dump", "Minefield"], 404, [GrinchRamData(0x0100BF, binary_bit_pos=0)]), - "WD - Generator Building - Short-Circuiting Power-Plant": GrinchLocationData("Generator Building", ["Who Dump Missions", "Missions", "Who Dump", "Generator Building"], 405, [GrinchRamData(0x0100BF, binary_bit_pos=1)]), - "WD - Squashing All Gifts": GrinchLocationData("Who Dump", ["Who Dump Missions", "Missions", "Who Dump", "Giftsanity"], 406, [GrinchRamData(0x010060, value=750, bit_size=2)]), -#Who Lake Missions - "WL - South Shore - Putting Thistles In Shorts": GrinchLocationData("Who Lake", ["Who Lake Missions", "Missions", "Who Lake", "South Shore", "South Shore Missions"], 500, [GrinchRamData(0x0100E5, value=10)]), - "WL - South Shore - Sabotaging The Tents": GrinchLocationData("Who Lake", ["Who Lake Missions", "Missions", "Who Lake", "South Shore", "South Shore Missions"], 501, [GrinchRamData(0x0100E6, value=10)]), - "WL - North Shore - Drilling Holes In Canoes": GrinchLocationData("North Shore", ["Who Lake Missions", "Missions", "Who Lake", "North Shore"], 502, [GrinchRamData(0x0100EE, value=10)]), - "WL - Submarine World - Modifying The Marine Mobile": GrinchLocationData("Submarine World", ["Who Lake Missions", "Missions", "Who Lake", "Submarine World"], 503, [GrinchRamData(0x0100BF, binary_bit_pos=4)]), - "WL - Mayor's Villa - Hooking The Mayor's Bed To The Motorboat": GrinchLocationData("Mayor's Villa", ["Who Lake Missions", "Missions", "Who Lake", "Mayor's Villa"], 504, [GrinchRamData(0x0100BF, binary_bit_pos=3)]), - "WL - Squashing All Gifts": GrinchLocationData("Who Lake", ["Who Lake Missions", "Missions", "Who Lake", "Giftsanity"], 505, [GrinchRamData(0x010062, value=1000, bit_size=2)]), -#Need to find binary values for individual blueprints, but all ram addresses are found -#Blueprints -#Binoculars Blueprints - "WV - Binoculars BP on Post Office Roof": GrinchLocationData("Whoville", ["Binocular Blueprints", "Blueprints", "Whoville", "Whoville Blueprints"], 600, [GrinchRamData(0x01020B, binary_bit_pos=2)]), - "WV - City Hall - Binoculars BP left side of Library": GrinchLocationData("City Hall", ["Binocular Blueprints", "Blueprints", "Whoville", "Whoville Blueprints", "City Hall", "City Hall Blueprints"], 601, [GrinchRamData(0x01021F, binary_bit_pos=6)]), - "WV - City Hall - Binoculars BP front side of Library": GrinchLocationData("City Hall", ["Binocular Blueprints", "Blueprints", "Whoville", "Whoville Blueprints", "City Hall", "City Hall Blueprints"], 602, [GrinchRamData(0x01021F, binary_bit_pos=5)]), - "WV - City Hall - Binoculars BP right side of Library": GrinchLocationData("City Hall", ["Binocular Blueprints", "Blueprints", "Whoville", "Whoville Blueprints", "City Hall", "City Hall Blueprints"], 603, [GrinchRamData(0x01021F, binary_bit_pos=4)]), -#Rotten Egg Launcher Blueprints - "WV - REL BP left of City Hall": GrinchLocationData("Whoville", ["Rotten Egg Launcher Blueprints", "Blueprints", "Whoville", "Whoville Blueprints"], 700, [GrinchRamData(0x01020B, binary_bit_pos=0)]), - "WV - REL BP left of Clock Tower": GrinchLocationData("Whoville", ["Rotten Egg Launcher Blueprints", "Blueprints", "Whoville", "Whoville Blueprints"], 701, [GrinchRamData(0x01020B, binary_bit_pos=1)]), - "WV - Post Office - REL BP inside Silver Room": GrinchLocationData("Post Office", ["Rotten Egg Launcher Blueprints", "Blueprints", "Whoville", "Whoville Blueprints", "Post Office", "Post Office Blueprints"], 702, [GrinchRamData(0x01021C, binary_bit_pos=1)]), - "WV - Post Office - REL BP at Entrance Door after Mission Completion": GrinchLocationData("Post Office", ["Rotten Egg Launcher Blueprints", "Blueprints", "Whoville", "Whoville Blueprints", "Post Office", "Post Office Blueprints"], 703, [GrinchRamData(0x01021C, binary_bit_pos=2)]), -#Rocket Spring Blueprints - "WF - RS BP behind Vacuum Tube": GrinchLocationData("Who Forest", ["Rocket Spring Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 800, [GrinchRamData(0x010243, binary_bit_pos=3)]), - "WF - RS BP in front of 2nd House near Vacuum Tube": GrinchLocationData("Who Forest", ["Rocket Spring Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 801, [GrinchRamData(0x010243, binary_bit_pos=1)]), - "WF - RS BP near Tree House on Ground": GrinchLocationData("Who Forest", ["Rocket Spring Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 802, [GrinchRamData(0x010243, binary_bit_pos=4)]), - "WF - RS BP behind Cable Car House": GrinchLocationData("Who Forest", ["Rocket Spring Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 804, [GrinchRamData(0x010242, binary_bit_pos=7)]), - "WF - RS BP near Who Snowball in Cave": GrinchLocationData("Who Forest", ["Rocket Spring Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 805, [GrinchRamData(0x010242, binary_bit_pos=6)]), - "WF - RS BP on Branch Platform closest to Glue Cannon": GrinchLocationData("Who Forest", ["Rocket Spring Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 806, [GrinchRamData(0x010243, binary_bit_pos=2)]), - "WF - RS BP on Branch Platform Near Beast": GrinchLocationData("Who Forest", ["Rocket Spring Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 807, [GrinchRamData(0x010243, binary_bit_pos=0)]), - "WF - RS BP on Branch Platform Elevated next to House": GrinchLocationData("Who Forest", ["Rocket Spring Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 808, [GrinchRamData(0x010243, binary_bit_pos=6)]), - "WF - RS BP on Tree House": GrinchLocationData("Who Forest", ["Rocket Spring Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 809, [GrinchRamData(0x010243, binary_bit_pos=5)]), -#Slime Shooter Blueprints - "WF - SS BP in Branch Platform Elevated House": GrinchLocationData("Who Forest", ["Slime Shooter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 900, [GrinchRamData(0x010244, binary_bit_pos=3)]), - "WF - SS BP in Branch Platform House next to Beast": GrinchLocationData("Who Forest", ["Slime Shooter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 901, [GrinchRamData(0x010243, binary_bit_pos=7)]), - "WF - SS BP in House in front of Civic Center Cave": GrinchLocationData("Who Forest", ["Slime Shooter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 902, [GrinchRamData(0x010244, binary_bit_pos=2)]), - "WF - SS BP in House next to Tree House": GrinchLocationData("Who Forest", ["Slime Shooter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 903, [GrinchRamData(0x010244, binary_bit_pos=1)]), - "WF - SS BP in House across from Tree House": GrinchLocationData("Who Forest", ["Slime Shooter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 904, [GrinchRamData(0x010244, binary_bit_pos=5)]), - "WF - SS BP in 2nd House near Vacuum Tube Right Side": GrinchLocationData("Who Forest", ["Slime Shooter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 905, [GrinchRamData(0x010244, binary_bit_pos=4)]), - "WF - SS BP in 2nd House near Vacuum Tube Left Side": GrinchLocationData("Who Forest", ["Slime Shooter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 906, [GrinchRamData(0x010244, binary_bit_pos=7)]), - "WF - SS BP in 2nd House near Vacuum Tube inbetween Blueprints": GrinchLocationData("Who Forest", ["Slime Shooter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 907, [GrinchRamData(0x010244, binary_bit_pos=6)]), - "WF - SS BP in House near Vacuum Tube": GrinchLocationData("Who Forest", ["Slime Shooter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints"], 908, [GrinchRamData(0x010244, binary_bit_pos=0)]), -#Octopus Climbing Device - "WD - OCD BP inside Middle Pipe": GrinchLocationData("Who Dump", ["Octopus Climbing Device Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints"], 1001, [GrinchRamData(0x010252, binary_bit_pos=3)]), - "WD - OCD BP inside Right Pipe": GrinchLocationData("Who Dump", ["Octopus Climbing Device Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints"], 1002, [GrinchRamData(0x010252, binary_bit_pos=5)]), - "WD - OCD BP in Vent to Mayor's House": GrinchLocationData("Who Dump", ["Octopus Climbing Device Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints"], 1003, [GrinchRamData(0x010252, binary_bit_pos=1)]), - "WD - OCD BP inside Left Pipe": GrinchLocationData("Who Dump", ["Octopus Climbing Device Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints"], 1004, [GrinchRamData(0x010252, binary_bit_pos=4)]), - "WD - OCD BP near Right Side of Power Plant Wall": GrinchLocationData("Who Dump", ["Octopus Climbing Device Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints"], 1005, [GrinchRamData(0x010252, binary_bit_pos=0)]), - "WD - OCD BP near Who-Bris' Shack": GrinchLocationData("Who Dump", ["Octopus Climbing Device Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints"], 1006, [GrinchRamData(0x010252, binary_bit_pos=2)]), - "WD - Minefield - OCD BP on Left Side of House": GrinchLocationData("Minefield", ["Octopus Climbing Device Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints", "Minefield", "Minefield Blueprints"], 1007, [GrinchRamData(0x01026E, binary_bit_pos=2)]), - "WD - Minefield - OCD BP on Right Side of Shack": GrinchLocationData("Minefield", ["Octopus Climbing Device Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints", "Minefield", "Minefield Blueprints"], 1008, [GrinchRamData(0x01026E, binary_bit_pos=4)]), - "WD - Minefield - OCD BP inside Guardian's House": GrinchLocationData("Minefield", ["Octopus Climbing Device Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints", "Minefield", "Minefield Blueprints"], 1009, [GrinchRamData(0x01026E, binary_bit_pos=3)]), -#Marine Mobile Blueprints - "WL - South Shore - MM BP on Bridge to Scout's Hut": GrinchLocationData("Who Lake", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "South Shore", "South Shore Blueprints"], 1100, [GrinchRamData(0x010281, binary_bit_pos=5)]), - "WL - South Shore - MM BP across from Tent near Porcupine": GrinchLocationData("Who Lake", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "South Shore", "South Shore Blueprints"], 1101, [GrinchRamData(0x010281, binary_bit_pos=6)]), - "WL - South Shore - MM BP near Outhouse": GrinchLocationData("Who Lake", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "South Shore", "South Shore Blueprints"], 1102, [GrinchRamData(0x010281, binary_bit_pos=7)]), - "WL - South Shore - MM BP near Hill Bridge": GrinchLocationData("Who Lake", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "South Shore", "South Shore Blueprints"], 1103, [GrinchRamData(0x010282, binary_bit_pos=0)]), - "WL - South Shore - MM BP on Scout's Hut Roof": GrinchLocationData("Who Lake", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "South Shore", "South Shore Blueprints"], 1104, [GrinchRamData(0x010281, binary_bit_pos=4)]), - "WL - South Shore - MM BP on Grass Platform": GrinchLocationData("Who Lake", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "South Shore", "South Shore Blueprints"], 1105, [GrinchRamData(0x010281, binary_bit_pos=2)]), - "WL - South Shore - MM BP across Zipline Platform": GrinchLocationData("Who Lake", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "South Shore", "South Shore Blueprints"], 1106, [GrinchRamData(0x010281, binary_bit_pos=3)]), - "WL - South Shore - MM BP behind Summer Beast": GrinchLocationData("Who Lake", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "South Shore", "South Shore Blueprints"], 1107, [GrinchRamData(0x010282, binary_bit_pos=1)]), - "WL - North Shore - MM BP below Bridge": GrinchLocationData("North Shore", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "North Shore", "North Shore Blueprints"], 1108, [GrinchRamData(0x010293, binary_bit_pos=0)]), - "WL - North Shore - MM BP behind Skunk Hut": GrinchLocationData("North Shore", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "North Shore", "North Shore Blueprints"], 1109, [GrinchRamData(0x010293, binary_bit_pos=2)]), - "WL - North Shore - MM BP inside Skunk Hut": GrinchLocationData("North Shore", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "North Shore", "North Shore Blueprints"], 1110, [GrinchRamData(0x010292, binary_bit_pos=6)]), - "WL - North Shore - MM BP inside House's Fence": GrinchLocationData("North Shore", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "North Shore", "North Shore Blueprints"], 1111, [GrinchRamData(0x010292, binary_bit_pos=7)]), - "WL - North Shore - MM BP inside Boulder Box near Bridge": GrinchLocationData("North Shore", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "North Shore", "North Shore Blueprints"], 1112, [GrinchRamData(0x010293, binary_bit_pos=3)]), - "WL - North Shore - MM BP inside Boulder Box behind Skunk Hut": GrinchLocationData("North Shore", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "North Shore", "North Shore Blueprints"], 1113, [GrinchRamData(0x010293, binary_bit_pos=4)]), - "WL - North Shore - MM BP inside Drill House": GrinchLocationData("North Shore", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "North Shore", "North Shore Blueprints"], 1114, [GrinchRamData(0x010292, binary_bit_pos=5)]), - "WL - North Shore - MM BP on Crow Platform near Drill House": GrinchLocationData("North Shore", ["Marine Mobile Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "North Shore", "North Shore Blueprints"], 1115, [GrinchRamData(0x010293, binary_bit_pos=1)]), - #Grinch Copter Blueprints - "WV - City Hall - GC BP in Safe Room": GrinchLocationData("City Hall", ["Grinch Copter Blueprints", "Blueprints", "Whoville", "Whoville Blueprints", "City Hall", "City Hall Blueprints"], 1200, [GrinchRamData(0x01021F, binary_bit_pos=7)]), - "WV - City Hall - GC BP in Statue Room": GrinchLocationData("City Hall", ["Grinch Copter Blueprints", "Blueprints", "Whoville", "Whoville Blueprints", "City Hall", "City Hall Blueprints"], 1201, [GrinchRamData(0x010220, binary_bit_pos=0)]), - "WV - Clock Tower - GC BP in Bedroom": GrinchLocationData("Clock Tower", ["Grinch Copter Blueprints", "Blueprints", "Whoville", "Whoville Blueprints", "Clock Tower", "Clock Tower Blueprints"], 1202, [GrinchRamData(0x010216, binary_bit_pos=3)]), - "WV - Clock Tower - GC BP in Bell Room": GrinchLocationData("Clock Tower", ["Grinch Copter Blueprints", "Blueprints", "Whoville", "Whoville Blueprints", "Clock Tower", "Clock Tower Blueprints"], 1203, [GrinchRamData(0x010216, binary_bit_pos=2)]), - "WF - Ski Resort - GC BP inside Dog's Fence": GrinchLocationData("Ski Resort", ["Grinch Copter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints", "Ski Resort", "Ski Resort Blueprints"], 1204, [GrinchRamData(0x010234, binary_bit_pos=7)]), - "WF - Ski Resort - GC BP in Max Cave": GrinchLocationData("Ski Resort", ["Grinch Copter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints", "Ski Resort", "Ski Resort Blueprints"], 1205, [GrinchRamData(0x010234, binary_bit_pos=6)]), - "WF - Civic Center - GC BP on Left Side in Bat Cave Wall": GrinchLocationData("Civic Center", ["Grinch Copter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints", "Civic Center", "Civic Center Blueprints"], 1206, [GrinchRamData(0x01022A, binary_bit_pos=7)]), - "WF - Civic Center - GC BP in Frozen Ice": GrinchLocationData("Civic Center", ["Grinch Copter Blueprints", "Blueprints", "Who Forest", "Who Forest Blueprints", "Civic Center", "Civic Center Blueprints"], 1207, [GrinchRamData(0x01022B, binary_bit_pos=0)]), - "WD - Power Plant - GC BP in Max Cave": GrinchLocationData("Power Plant", ["Grinch Copter Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints", "Power Plant", "Power Plant Blueprints"], 1208, [GrinchRamData(0x010265, binary_bit_pos=1)]), - "WD - Power Plant - GC BP After First Gate": GrinchLocationData("Power Plant", ["Grinch Copter Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints", "Power Plant", "Power Plant Blueprints"], 1209, [GrinchRamData(0x010265, binary_bit_pos=2)]), - "WD - Generator Building - GC BP on the Highest Platform": GrinchLocationData("Generator Building", ["Grinch Copter Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints", "Generator Building", "Generator Building Blueprints"], 1210, [GrinchRamData(0x01026B, binary_bit_pos=0)]), - "WD - Generator Building - GC BP at the Entrance after Mission Completion": GrinchLocationData("Generator Building", ["Grinch Copter Blueprints", "Blueprints", "Who Dump", "Who Dump Blueprints", "Generator Building", "Generator Building Blueprints"], 1211, [GrinchRamData(0x01026B, binary_bit_pos=1)]), - "WL - Submarine World - GC BP Just Below Water Surface": GrinchLocationData("Submarine World", ["Grinch Copter Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "Submarine World", "Submarine World Blueprints"], 1212, [GrinchRamData(0x010289, binary_bit_pos=3)]), - "WL - Submarine World - GC BP Underwater": GrinchLocationData("Submarine World", ["Grinch Copter Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "Submarine World", "Submarine World Blueprints"], 1213, [GrinchRamData(0x010289, binary_bit_pos=4)]), - "WL - Mayor's Villa - GC BP on Tree Branch": GrinchLocationData("Mayor's Villa", ["Grinch Copter Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "Mayor's Villa", "Mayor's Villa Blueprints"], 1214, [GrinchRamData(0x010275, binary_bit_pos=7)]), - "WL - Mayor's Villa - GC BP in Pirate's Cave": GrinchLocationData("Mayor's Villa", ["Grinch Copter Blueprints", "Blueprints", "Who Lake", "Who Lake Blueprints", "Mayor's Villa", "Mayor's Villa Blueprints"], 1215, [GrinchRamData(0x010275, binary_bit_pos=6)]), -#Sleigh Room Locations - "MC - Sleigh Ride - Stealing All Gifts": GrinchLocationData("Sleigh Room", ["Sleigh Ride"], 1300, [GrinchRamData(0x0100BF, binary_bit_pos=6)]), - "MC - Sleigh Ride - Neutralizing Santa": GrinchLocationData("Sleigh Room", None, None, [GrinchRamData(0x0100BF, binary_bit_pos=7)]),#[GrinchRamData(0x010000, value=0x3E)]), -#Heart of Stones - "WV - Post Office - Heart of Stone": GrinchLocationData("Post Office", ["Heart of Stones", "Whoville", "Post Office"], 1400, [GrinchRamData(0x0101FA, binary_bit_pos=6)]), - "WF - Ski Resort - Heart of Stone": GrinchLocationData("Ski Resort", ["Heart of Stones", "Who Forest", "Ski Resort"], 1401, [GrinchRamData(0x0101FA, binary_bit_pos=7)]), - "WD - Minefield - Heart of Stone": GrinchLocationData("Minefield", ["Heart of Stones", "Who Dump", "Minefield"], 1402, [GrinchRamData(0x0101FB, binary_bit_pos=0)]), - "WL - North Shore - Heart of Stone": GrinchLocationData("North Shore", ["Heart of Stones", "Who Lake", "North Shore"], 1403, [GrinchRamData(0x0101FB, binary_bit_pos=1)]), -#Supadow Minigames - # "Spin N' Win - Easy": GrinchLocationData("Spin N' Win", ["Supadow Minigames", "Spin N' Win"], 1500, [GrinchRamData()]), - # "Spin N' Win - Hard": GrinchLocationData("Spin N' Win", ["Supadow Minigames", "Spin N' Win"], 1501, [GrinchRamData()]), - # "Spin N' Win - Real Tough": GrinchLocationData("Spin N' Win", ["Supadow Minigames", "Spin N' Win"], 1502, [GrinchRamData()]), - # "Dankamania - Easy - 15 Points": GrinchLocationData("Dankamania", ["Supadow Minigames", "Dankamania"], 1503, [GrinchRamData()]), - # "Dankamania - Hard - 15 Points": GrinchLocationData("Dankamania", ["Supadow Minigames", "Dankamania"], 1504, [GrinchRamData()]), - # "Dankamania - Real Tough - 15 Points": GrinchLocationData("Dankamania", ["Supadow Minigames", "Dankamania"], 1505, [GrinchRamData()]), - # "The Copter Race Contest - Easy": GrinchLocationData("The Copter Race Contest", ["Supadow Minigames", "The Copter Race Contest"], 1506, [GrinchRamData()]), - # "The Copter Race Contest - Hard": GrinchLocationData("The Copter Race Contest", ["Supadow Minigames", "The Copter Race Contest"], 1507, [GrinchRamData()]), - # "The Copter Race Contest - Real Tough": GrinchLocationData("The Copter Race Contest", ["Supadow Minigames", "The Copter Race Contest"], 1508, [GrinchRamData()]), - # "Bike Race - 1st Place": GrinchLocationData("Bike Race", ["Supadow Minigames", "Bike Race"], 1509, [GrinchRamData()]), - # "Bike Race - Top 2": GrinchLocationData("Bike Race", ["Supadow Minigames", "Bike Race"], 1510, [GrinchRamData()]), - # "Bike Race - Top 3": GrinchLocationData("Bike Race", ["Supadow Minigames", "Bike Race"], 1511, [GrinchRamData()]), -# Sleigh Part Locations - "WV - Exhaust Pipes": GrinchLocationData("Whoville", ["Sleigh Ride", "Whoville"], 1600, [GrinchRamData(0x0101FB, binary_bit_pos=2)]), - "WF - Skis": GrinchLocationData("Who Forest", ["Sleigh Ride", "Who Forest"], 1601, [GrinchRamData(0x0101FB, binary_bit_pos=3)]), - "WD - Tires": GrinchLocationData("Who Dump", ["Sleigh Ride", "Who Dump"], 1602, [GrinchRamData(0x0101FB, binary_bit_pos=4)]), - "WL - Submarine World - Twin-End Tuba": GrinchLocationData("Submarine World", ["Sleigh Ride", "Who Lake", "South Shore"], 1603, [GrinchRamData(0x0101FB, binary_bit_pos=6)]), - "WL - South Shore - GPS": GrinchLocationData("Who Lake", ["Sleigh Ride", "Who Lake", "Submarine World"], 1604, [GrinchRamData(0x0101FB, binary_bit_pos=5)]), -# Mount Crumpit Locations - "MC - 1st Crate Squashed": GrinchLocationData("Mount Crumpit", ["Mount Crumpit"], 1700, [GrinchRamData(0x095343, value=1)]), - "MC - 2nd Crate Squashed": GrinchLocationData("Mount Crumpit", ["Mount Crumpit"], 1701, [GrinchRamData(0x095343, value=2)]), - "MC - 3rd Crate Squashed": GrinchLocationData("Mount Crumpit", ["Mount Crumpit"], 1702, [GrinchRamData(0x095343, value=3)]), - "MC - 4th Crate Squashed": GrinchLocationData("Mount Crumpit", ["Mount Crumpit"], 1703, [GrinchRamData(0x095343, value=4)]), - "MC - 5th Crate Squashed": GrinchLocationData("Mount Crumpit", ["Mount Crumpit"], 1704, [GrinchRamData(0x095343, value=5)]), + # Going to use current map id as indicator whether or not you visited a location + # Visitsanity + "WV - First Visit": GrinchLocationData( + "Whoville", + ["Visitsanity", "Whoville"], + 100, + [GrinchRamData(0x010000, value=0x07)], + ), + "WV - Post Office - First Visit": GrinchLocationData( + "Post Office", + ["Visitsanity", "Whoville", "Post Office"], + 101, + [GrinchRamData(0x010000, value=0x0A)], + ), + "WV - City Hall - First Visit": GrinchLocationData( + "City Hall", + ["Visitsanity", "Whoville", "City Hall"], + 102, + [GrinchRamData(0x010000, value=0x08)], + ), + "WV - Clock Tower - First Visit": GrinchLocationData( + "Clock Tower", + ["Visitsanity", "Whoville", "Clock Tower"], + 103, + [GrinchRamData(0x010000, value=0x09)], + ), + "WF - First Visit": GrinchLocationData( + "Who Forest", + ["Visitsanity", "Who Forest"], + 104, + [GrinchRamData(0x010000, value=0x0B)], + ), + "WF - Ski Resort - First Visit": GrinchLocationData( + "Ski Resort", + ["Visitsanity", "Who Forest", "Ski Resort"], + 105, + [GrinchRamData(0x010000, value=0x0C)], + ), + "WF - Civic Center - First Visit": GrinchLocationData( + "Civic Center", + ["Visitsanity", "Who Forest", "Civic Center"], + 106, + [GrinchRamData(0x010000, value=0x0D)], + ), + "WD - First Visit": GrinchLocationData( + "Who Dump", + ["Visitsanity", "Who Dump"], + 107, + [GrinchRamData(0x010000, value=0x0E)], + ), + "WD - Minefield - First Visit": GrinchLocationData( + "Minefield", + ["Visitsanity", "Who Dump", "Minefield"], + 108, + [GrinchRamData(0x010000, value=0x11)], + ), + "WD - Power Plant - First Visit": GrinchLocationData( + "Power Plant", + ["Visitsanity", "Who Dump", "Power Plant"], + 109, + [GrinchRamData(0x010000, value=0x10)], + ), + "WD - Generator Building - First Visit": GrinchLocationData( + "Generator Building", + ["Visitsanity", "Who Dump", "Generator Building"], + 110, + [GrinchRamData(0x010000, value=0x0F)], + ), + "WL - South Shore - First Visit": GrinchLocationData( + "Who Lake", + ["Visitsanity", "Who Lake", "South Shore"], + 111, + [GrinchRamData(0x010000, value=0x12)], + ), + "WL - Submarine World - First Visit": GrinchLocationData( + "Submarine World", + ["Visitsanity", "Who Lake", "Submarine World"], + 112, + [GrinchRamData(0x010000, value=0x17)], + ), + "WL - Scout's Hut - First Visit": GrinchLocationData( + "Scout's Hut", + ["Visitsanity", "Who Lake", "Scout's Hut"], + 113, + [GrinchRamData(0x010000, value=0x13)], + ), + "WL - North Shore - First Visit": GrinchLocationData( + "North Shore", + ["Visitsanity", "Who Lake", "North Shore"], + 114, + [GrinchRamData(0x010000, value=0x14)], + ), + "WL - Mayor's Villa - First Visit": GrinchLocationData( + "Mayor's Villa", + ["Visitsanity", "Who Lake", "Mayor's Villa"], + 115, + [GrinchRamData(0x010000, value=0x16)], + ), + # Need to find mission completion address for handful of locations that are not documented. + # Missions that have value are those ones we need to find the check for + # Whoville Missions + "WV - Post Office - Shuffling The Mail": GrinchLocationData( + "Post Office", + ["Whoville Missions", "Missions", "Whoville", "Post Office"], + 201, + [GrinchRamData(0x0100BE, binary_bit_pos=0)], + ), + "WV - Smashing Snowmen": GrinchLocationData( + "Whoville", + ["Whoville Missions", "Missions", "Whoville"], + 200, + [GrinchRamData(0x0100C5, value=10)], + ), + "WV - Painting The Mayor's Posters": GrinchLocationData( + "Whoville", + ["Whoville Missions", "Missions", "Whoville"], + 202, + [GrinchRamData(0x0100C6, value=10)], + ), + "WV - Launching Eggs Into Houses": GrinchLocationData( + "Whoville", + ["Whoville Missions", "Missions", "Whoville"], + 203, + [GrinchRamData(0x0100C7, value=10)], + ), + "WV - City Hall - Modifying The Mayor's Statue": GrinchLocationData( + "City Hall", + ["Whoville Missions", "Missions", "Whoville", "City Hall"], + 204, + [GrinchRamData(0x0100BE, binary_bit_pos=1)], + ), + "WV - Clock Tower - Advancing The Countdown-To-Xmas Clock": GrinchLocationData( + "Clock Tower", + ["Whoville Missions", "Missions", "Whoville", "Clock Tower"], + 205, + [GrinchRamData(0x0100BE, binary_bit_pos=2)], + ), + "WV - Squashing All Gifts": GrinchLocationData( + "Whoville", + ["Whoville Missions", "Missions", "Giftsanity", "Whoville"], + 206, + [GrinchRamData(0x01005C, value=500, byte_size=2)], + ), + # Who Forest Missions + "WF - Making Xmas Trees Droop": GrinchLocationData( + "Who Forest", + ["Who Forest Missions", "Missions", "Who Forest"], + 300, + [GrinchRamData(0x0100C8, value=10)], + ), + "WF - Sabotaging Snow Cannon With Glue": GrinchLocationData( + "Who Forest", + ["Who Forest Missions", "Missions", "Who Forest"], + 301, + [GrinchRamData(0x0100BE, binary_bit_pos=3)], + ), + "WF - Putting Beehives In Cabins": GrinchLocationData( + "Who Forest", + ["Who Forest Missions", "Missions", "Who Forest"], + 302, + [GrinchRamData(0x0100CA, value=10)], + ), + "WF - Ski Resort - Sliming The Mayor's Skis": GrinchLocationData( + "Ski Resort", + ["Who Forest Missions", "Missions", "Who Forest", "Ski Resort"], + 303, + [GrinchRamData(0x0100BE, binary_bit_pos=4)], + ), + "WF - Civic Center - Replacing The Candles On The Cake With Fireworks": GrinchLocationData( + "Civic Center", + ["Who Forest Missions", "Missions", "Who Forest", "Civic Center"], + 304, + [GrinchRamData(0x0100BE, binary_bit_pos=5)], + ), + "WF - Squashing All Gifts": GrinchLocationData( + "Who Forest", + ["Who Forest Missions", "Missions", "Giftsanity", "Who Forest"], + 305, + [GrinchRamData(0x01005E, value=750, byte_size=2)], + ), + # Who Dump Missions + "WD - Stealing Food From Birds": GrinchLocationData( + "Who Dump", + ["Who Dump Missions", "Missions", "Who Dump"], + 400, + [GrinchRamData(0x0100CB, value=10)], + ), + "WD - Feeding The Computer With Robot Parts": GrinchLocationData( + "Who Dump", + ["Who Dump Missions", "Missions", "Who Dump"], + 401, + [GrinchRamData(0x0100BF, binary_bit_pos=2)], + ), + "WD - Infesting The Mayor's House With Rats": GrinchLocationData( + "Who Dump", + ["Who Dump Missions", "Missions", "Who Dump"], + 402, + [GrinchRamData(0x0100BE, binary_bit_pos=6)], + ), + "WD - Conducting The Stinky Gas To Who-Bris' Shack": GrinchLocationData( + "Who Dump", + ["Who Dump Missions", "Missions", "Who Dump"], + 403, + [GrinchRamData(0x0100BE, binary_bit_pos=7)], + ), + "WD - Minefield - Shaving Who Dump Guardian": GrinchLocationData( + "Minefield", + ["Who Dump Missions", "Missions", "Who Dump", "Minefield"], + 404, + [GrinchRamData(0x0100BF, binary_bit_pos=0)], + ), + "WD - Generator Building - Short-Circuiting Power-Plant": GrinchLocationData( + "Generator Building", + ["Who Dump Missions", "Missions", "Who Dump", "Generator Building"], + 405, + [GrinchRamData(0x0100BF, binary_bit_pos=1)], + ), + "WD - Squashing All Gifts": GrinchLocationData( + "Who Dump", + ["Who Dump Missions", "Missions", "Who Dump", "Giftsanity"], + 406, + [GrinchRamData(0x010060, value=750, byte_size=2)], + ), + # Who Lake Missions + "WL - South Shore - Putting Thistles In Shorts": GrinchLocationData( + "Who Lake", + [ + "Who Lake Missions", + "Missions", + "Who Lake", + "South Shore", + "South Shore Missions", + ], + 500, + [GrinchRamData(0x0100E5, value=10)], + ), + "WL - South Shore - Sabotaging The Tents": GrinchLocationData( + "Who Lake", + [ + "Who Lake Missions", + "Missions", + "Who Lake", + "South Shore", + "South Shore Missions", + ], + 501, + [GrinchRamData(0x0100E6, value=10)], + ), + "WL - North Shore - Drilling Holes In Canoes": GrinchLocationData( + "North Shore", + ["Who Lake Missions", "Missions", "Who Lake", "North Shore"], + 502, + [GrinchRamData(0x0100EE, value=10)], + ), + "WL - Submarine World - Modifying The Marine Mobile": GrinchLocationData( + "Submarine World", + ["Who Lake Missions", "Missions", "Who Lake", "Submarine World"], + 503, + [GrinchRamData(0x0100BF, binary_bit_pos=4)], + ), + "WL - Mayor's Villa - Hooking The Mayor's Bed To The Motorboat": GrinchLocationData( + "Mayor's Villa", + ["Who Lake Missions", "Missions", "Who Lake", "Mayor's Villa"], + 504, + [GrinchRamData(0x0100BF, binary_bit_pos=3)], + ), + "WL - Squashing All Gifts": GrinchLocationData( + "Who Lake", + ["Who Lake Missions", "Missions", "Who Lake", "Giftsanity"], + 505, + [GrinchRamData(0x010062, value=1000, byte_size=2)], + ), + # Need to find binary values for individual blueprints, but all ram addresses are found + # Blueprints + # Binoculars Blueprints + "WV - Binoculars BP on Post Office Roof": GrinchLocationData( + "Whoville", + ["Binocular Blueprints", "Blueprints", "Whoville", "Whoville Blueprints"], + 600, + [GrinchRamData(0x01020B, binary_bit_pos=2)], + ), + "WV - City Hall - Binoculars BP left side of Library": GrinchLocationData( + "City Hall", + [ + "Binocular Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + "City Hall", + "City Hall Blueprints", + ], + 601, + [GrinchRamData(0x01021F, binary_bit_pos=6)], + ), + "WV - City Hall - Binoculars BP front side of Library": GrinchLocationData( + "City Hall", + [ + "Binocular Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + "City Hall", + "City Hall Blueprints", + ], + 602, + [GrinchRamData(0x01021F, binary_bit_pos=5)], + ), + "WV - City Hall - Binoculars BP right side of Library": GrinchLocationData( + "City Hall", + [ + "Binocular Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + "City Hall", + "City Hall Blueprints", + ], + 603, + [GrinchRamData(0x01021F, binary_bit_pos=4)], + ), + # Rotten Egg Launcher Blueprints + "WV - REL BP left of City Hall": GrinchLocationData( + "Whoville", + [ + "Rotten Egg Launcher Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + ], + 700, + [GrinchRamData(0x01020B, binary_bit_pos=0)], + ), + "WV - REL BP left of Clock Tower": GrinchLocationData( + "Whoville", + [ + "Rotten Egg Launcher Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + ], + 701, + [GrinchRamData(0x01020B, binary_bit_pos=1)], + ), + "WV - Post Office - REL BP inside Silver Room": GrinchLocationData( + "Post Office", + [ + "Rotten Egg Launcher Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + "Post Office", + "Post Office Blueprints", + ], + 702, + [GrinchRamData(0x01021C, binary_bit_pos=1)], + ), + "WV - Post Office - REL BP at Entrance Door after Mission Completion": GrinchLocationData( + "Post Office", + [ + "Rotten Egg Launcher Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + "Post Office", + "Post Office Blueprints", + ], + 703, + [GrinchRamData(0x01021C, binary_bit_pos=2)], + ), + # Rocket Spring Blueprints + "WF - RS BP behind Vacuum Tube": GrinchLocationData( + "Who Forest", + [ + "Rocket Spring Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 800, + [GrinchRamData(0x010243, binary_bit_pos=3)], + ), + "WF - RS BP in front of 2nd House near Vacuum Tube": GrinchLocationData( + "Who Forest", + [ + "Rocket Spring Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 801, + [GrinchRamData(0x010243, binary_bit_pos=1)], + ), + "WF - RS BP near Tree House on Ground": GrinchLocationData( + "Who Forest", + [ + "Rocket Spring Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 802, + [GrinchRamData(0x010243, binary_bit_pos=4)], + ), + "WF - RS BP behind Cable Car House": GrinchLocationData( + "Who Forest", + [ + "Rocket Spring Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 804, + [GrinchRamData(0x010242, binary_bit_pos=7)], + ), + "WF - RS BP near Who Snowball in Cave": GrinchLocationData( + "Who Forest", + [ + "Rocket Spring Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 805, + [GrinchRamData(0x010242, binary_bit_pos=6)], + ), + "WF - RS BP on Branch Platform closest to Glue Cannon": GrinchLocationData( + "Who Forest", + [ + "Rocket Spring Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 806, + [GrinchRamData(0x010243, binary_bit_pos=2)], + ), + "WF - RS BP on Branch Platform Near Beast": GrinchLocationData( + "Who Forest", + [ + "Rocket Spring Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 807, + [GrinchRamData(0x010243, binary_bit_pos=0)], + ), + "WF - RS BP on Branch Platform Elevated next to House": GrinchLocationData( + "Who Forest", + [ + "Rocket Spring Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 808, + [GrinchRamData(0x010243, binary_bit_pos=6)], + ), + "WF - RS BP on Tree House": GrinchLocationData( + "Who Forest", + [ + "Rocket Spring Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 809, + [GrinchRamData(0x010243, binary_bit_pos=5)], + ), + # Slime Shooter Blueprints + "WF - SS BP in Branch Platform Elevated House": GrinchLocationData( + "Who Forest", + [ + "Slime Shooter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 900, + [GrinchRamData(0x010244, binary_bit_pos=3)], + ), + "WF - SS BP in Branch Platform House next to Beast": GrinchLocationData( + "Who Forest", + [ + "Slime Shooter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 901, + [GrinchRamData(0x010243, binary_bit_pos=7)], + ), + "WF - SS BP in House in front of Civic Center Cave": GrinchLocationData( + "Who Forest", + [ + "Slime Shooter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 902, + [GrinchRamData(0x010244, binary_bit_pos=2)], + ), + "WF - SS BP in House next to Tree House": GrinchLocationData( + "Who Forest", + [ + "Slime Shooter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 903, + [GrinchRamData(0x010244, binary_bit_pos=1)], + ), + "WF - SS BP in House across from Tree House": GrinchLocationData( + "Who Forest", + [ + "Slime Shooter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 904, + [GrinchRamData(0x010244, binary_bit_pos=5)], + ), + "WF - SS BP in 2nd House near Vacuum Tube Right Side": GrinchLocationData( + "Who Forest", + [ + "Slime Shooter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 905, + [GrinchRamData(0x010244, binary_bit_pos=4)], + ), + "WF - SS BP in 2nd House near Vacuum Tube Left Side": GrinchLocationData( + "Who Forest", + [ + "Slime Shooter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 906, + [GrinchRamData(0x010244, binary_bit_pos=7)], + ), + "WF - SS BP in 2nd House near Vacuum Tube inbetween Blueprints": GrinchLocationData( + "Who Forest", + [ + "Slime Shooter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 907, + [GrinchRamData(0x010244, binary_bit_pos=6)], + ), + "WF - SS BP in House near Vacuum Tube": GrinchLocationData( + "Who Forest", + [ + "Slime Shooter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + ], + 908, + [GrinchRamData(0x010244, binary_bit_pos=0)], + ), + # Octopus Climbing Device + "WD - OCD BP inside Middle Pipe": GrinchLocationData( + "Who Dump", + [ + "Octopus Climbing Device Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + ], + 1001, + [GrinchRamData(0x010252, binary_bit_pos=3)], + ), + "WD - OCD BP inside Right Pipe": GrinchLocationData( + "Who Dump", + [ + "Octopus Climbing Device Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + ], + 1002, + [GrinchRamData(0x010252, binary_bit_pos=5)], + ), + "WD - OCD BP in Vent to Mayor's House": GrinchLocationData( + "Who Dump", + [ + "Octopus Climbing Device Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + ], + 1003, + [GrinchRamData(0x010252, binary_bit_pos=1)], + ), + "WD - OCD BP inside Left Pipe": GrinchLocationData( + "Who Dump", + [ + "Octopus Climbing Device Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + ], + 1004, + [GrinchRamData(0x010252, binary_bit_pos=4)], + ), + "WD - OCD BP near Right Side of Power Plant Wall": GrinchLocationData( + "Who Dump", + [ + "Octopus Climbing Device Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + ], + 1005, + [GrinchRamData(0x010252, binary_bit_pos=0)], + ), + "WD - OCD BP near Who-Bris' Shack": GrinchLocationData( + "Who Dump", + [ + "Octopus Climbing Device Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + ], + 1006, + [GrinchRamData(0x010252, binary_bit_pos=2)], + ), + "WD - Minefield - OCD BP on Left Side of House": GrinchLocationData( + "Minefield", + [ + "Octopus Climbing Device Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + "Minefield", + "Minefield Blueprints", + ], + 1007, + [GrinchRamData(0x01026E, binary_bit_pos=2)], + ), + "WD - Minefield - OCD BP on Right Side of Shack": GrinchLocationData( + "Minefield", + [ + "Octopus Climbing Device Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + "Minefield", + "Minefield Blueprints", + ], + 1008, + [GrinchRamData(0x01026E, binary_bit_pos=4)], + ), + "WD - Minefield - OCD BP inside Guardian's House": GrinchLocationData( + "Minefield", + [ + "Octopus Climbing Device Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + "Minefield", + "Minefield Blueprints", + ], + 1009, + [GrinchRamData(0x01026E, binary_bit_pos=3)], + ), + # Marine Mobile Blueprints + "WL - South Shore - MM BP on Bridge to Scout's Hut": GrinchLocationData( + "Who Lake", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "South Shore", + "South Shore Blueprints", + ], + 1100, + [GrinchRamData(0x010281, binary_bit_pos=5)], + ), + "WL - South Shore - MM BP across from Tent near Porcupine": GrinchLocationData( + "Who Lake", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "South Shore", + "South Shore Blueprints", + ], + 1101, + [GrinchRamData(0x010281, binary_bit_pos=6)], + ), + "WL - South Shore - MM BP near Outhouse": GrinchLocationData( + "Who Lake", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "South Shore", + "South Shore Blueprints", + ], + 1102, + [GrinchRamData(0x010281, binary_bit_pos=7)], + ), + "WL - South Shore - MM BP near Hill Bridge": GrinchLocationData( + "Who Lake", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "South Shore", + "South Shore Blueprints", + ], + 1103, + [GrinchRamData(0x010282, binary_bit_pos=0)], + ), + "WL - South Shore - MM BP on Scout's Hut Roof": GrinchLocationData( + "Who Lake", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "South Shore", + "South Shore Blueprints", + ], + 1104, + [GrinchRamData(0x010281, binary_bit_pos=4)], + ), + "WL - South Shore - MM BP on Grass Platform": GrinchLocationData( + "Who Lake", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "South Shore", + "South Shore Blueprints", + ], + 1105, + [GrinchRamData(0x010281, binary_bit_pos=2)], + ), + "WL - South Shore - MM BP across Zipline Platform": GrinchLocationData( + "Who Lake", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "South Shore", + "South Shore Blueprints", + ], + 1106, + [GrinchRamData(0x010281, binary_bit_pos=3)], + ), + "WL - South Shore - MM BP behind Summer Beast": GrinchLocationData( + "Who Lake", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "South Shore", + "South Shore Blueprints", + ], + 1107, + [GrinchRamData(0x010282, binary_bit_pos=1)], + ), + "WL - North Shore - MM BP below Bridge": GrinchLocationData( + "North Shore", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "North Shore", + "North Shore Blueprints", + ], + 1108, + [GrinchRamData(0x010293, binary_bit_pos=0)], + ), + "WL - North Shore - MM BP behind Skunk Hut": GrinchLocationData( + "North Shore", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "North Shore", + "North Shore Blueprints", + ], + 1109, + [GrinchRamData(0x010293, binary_bit_pos=2)], + ), + "WL - North Shore - MM BP inside Skunk Hut": GrinchLocationData( + "North Shore", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "North Shore", + "North Shore Blueprints", + ], + 1110, + [GrinchRamData(0x010292, binary_bit_pos=6)], + ), + "WL - North Shore - MM BP inside House's Fence": GrinchLocationData( + "North Shore", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "North Shore", + "North Shore Blueprints", + ], + 1111, + [GrinchRamData(0x010292, binary_bit_pos=7)], + ), + "WL - North Shore - MM BP inside Boulder Box near Bridge": GrinchLocationData( + "North Shore", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "North Shore", + "North Shore Blueprints", + ], + 1112, + [GrinchRamData(0x010293, binary_bit_pos=3)], + ), + "WL - North Shore - MM BP inside Boulder Box behind Skunk Hut": GrinchLocationData( + "North Shore", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "North Shore", + "North Shore Blueprints", + ], + 1113, + [GrinchRamData(0x010293, binary_bit_pos=4)], + ), + "WL - North Shore - MM BP inside Drill House": GrinchLocationData( + "North Shore", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "North Shore", + "North Shore Blueprints", + ], + 1114, + [GrinchRamData(0x010292, binary_bit_pos=5)], + ), + "WL - North Shore - MM BP on Crow Platform near Drill House": GrinchLocationData( + "North Shore", + [ + "Marine Mobile Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "North Shore", + "North Shore Blueprints", + ], + 1115, + [GrinchRamData(0x010293, binary_bit_pos=1)], + ), + # Grinch Copter Blueprints + "WV - City Hall - GC BP in Safe Room": GrinchLocationData( + "City Hall", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + "City Hall", + "City Hall Blueprints", + ], + 1200, + [GrinchRamData(0x01021F, binary_bit_pos=7)], + ), + "WV - City Hall - GC BP in Statue Room": GrinchLocationData( + "City Hall", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + "City Hall", + "City Hall Blueprints", + ], + 1201, + [GrinchRamData(0x010220, binary_bit_pos=0)], + ), + "WV - Clock Tower - GC BP in Bedroom": GrinchLocationData( + "Clock Tower", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + "Clock Tower", + "Clock Tower Blueprints", + ], + 1202, + [GrinchRamData(0x010216, binary_bit_pos=3)], + ), + "WV - Clock Tower - GC BP in Bell Room": GrinchLocationData( + "Clock Tower", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Whoville", + "Whoville Blueprints", + "Clock Tower", + "Clock Tower Blueprints", + ], + 1203, + [GrinchRamData(0x010216, binary_bit_pos=2)], + ), + "WF - Ski Resort - GC BP inside Dog's Fence": GrinchLocationData( + "Ski Resort", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + "Ski Resort", + "Ski Resort Blueprints", + ], + 1204, + [GrinchRamData(0x010234, binary_bit_pos=7)], + ), + "WF - Ski Resort - GC BP in Max Cave": GrinchLocationData( + "Ski Resort", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + "Ski Resort", + "Ski Resort Blueprints", + ], + 1205, + [GrinchRamData(0x010234, binary_bit_pos=6)], + ), + "WF - Civic Center - GC BP on Left Side in Bat Cave Wall": GrinchLocationData( + "Civic Center", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + "Civic Center", + "Civic Center Blueprints", + ], + 1206, + [GrinchRamData(0x01022A, binary_bit_pos=7)], + ), + "WF - Civic Center - GC BP in Frozen Ice": GrinchLocationData( + "Civic Center", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Forest", + "Who Forest Blueprints", + "Civic Center", + "Civic Center Blueprints", + ], + 1207, + [GrinchRamData(0x01022B, binary_bit_pos=0)], + ), + "WD - Power Plant - GC BP in Max Cave": GrinchLocationData( + "Power Plant", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + "Power Plant", + "Power Plant Blueprints", + ], + 1208, + [GrinchRamData(0x010265, binary_bit_pos=1)], + ), + "WD - Power Plant - GC BP After First Gate": GrinchLocationData( + "Power Plant", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + "Power Plant", + "Power Plant Blueprints", + ], + 1209, + [GrinchRamData(0x010265, binary_bit_pos=2)], + ), + "WD - Generator Building - GC BP on the Highest Platform": GrinchLocationData( + "Generator Building", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + "Generator Building", + "Generator Building Blueprints", + ], + 1210, + [GrinchRamData(0x01026B, binary_bit_pos=0)], + ), + "WD - Generator Building - GC BP at the Entrance after Mission Completion": GrinchLocationData( + "Generator Building", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Dump", + "Who Dump Blueprints", + "Generator Building", + "Generator Building Blueprints", + ], + 1211, + [GrinchRamData(0x01026B, binary_bit_pos=1)], + ), + "WL - Submarine World - GC BP Just Below Water Surface": GrinchLocationData( + "Submarine World", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "Submarine World", + "Submarine World Blueprints", + ], + 1212, + [GrinchRamData(0x010289, binary_bit_pos=3)], + ), + "WL - Submarine World - GC BP Underwater": GrinchLocationData( + "Submarine World", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "Submarine World", + "Submarine World Blueprints", + ], + 1213, + [GrinchRamData(0x010289, binary_bit_pos=4)], + ), + "WL - Mayor's Villa - GC BP on Tree Branch": GrinchLocationData( + "Mayor's Villa", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "Mayor's Villa", + "Mayor's Villa Blueprints", + ], + 1214, + [GrinchRamData(0x010275, binary_bit_pos=7)], + ), + "WL - Mayor's Villa - GC BP in Pirate's Cave": GrinchLocationData( + "Mayor's Villa", + [ + "Grinch Copter Blueprints", + "Blueprints", + "Who Lake", + "Who Lake Blueprints", + "Mayor's Villa", + "Mayor's Villa Blueprints", + ], + 1215, + [GrinchRamData(0x010275, binary_bit_pos=6)], + ), + # Sleigh Room Locations + "MC - Sleigh Ride - Stealing All Gifts": GrinchLocationData( + "Sleigh Room", + ["Sleigh Ride"], + 1300, + [GrinchRamData(0x0100BF, binary_bit_pos=6)], + ), + "MC - Sleigh Ride - Neutralizing Santa": GrinchLocationData( + "Sleigh Room", None, None, [GrinchRamData(0x0100BF, binary_bit_pos=7)] + ), # [GrinchRamData(0x010000, value=0x3E)]), + # Heart of Stones + "WV - Post Office - Heart of Stone": GrinchLocationData( + "Post Office", + ["Heart of Stones", "Whoville", "Post Office"], + 1400, + [GrinchRamData(0x0101FA, binary_bit_pos=6)], + ), + "WF - Ski Resort - Heart of Stone": GrinchLocationData( + "Ski Resort", + ["Heart of Stones", "Who Forest", "Ski Resort"], + 1401, + [GrinchRamData(0x0101FA, binary_bit_pos=7)], + ), + "WD - Minefield - Heart of Stone": GrinchLocationData( + "Minefield", + ["Heart of Stones", "Who Dump", "Minefield"], + 1402, + [GrinchRamData(0x0101FB, binary_bit_pos=0)], + ), + "WL - North Shore - Heart of Stone": GrinchLocationData( + "North Shore", + ["Heart of Stones", "Who Lake", "North Shore"], + 1403, + [GrinchRamData(0x0101FB, binary_bit_pos=1)], + ), + # Supadow Minigames + # "Spin N' Win - Easy": GrinchLocationData("Spin N' Win", ["Supadow Minigames", "Spin N' Win"], 1500, [GrinchRamData()]), + # "Spin N' Win - Hard": GrinchLocationData("Spin N' Win", ["Supadow Minigames", "Spin N' Win"], 1501, [GrinchRamData()]), + # "Spin N' Win - Real Tough": GrinchLocationData("Spin N' Win", ["Supadow Minigames", "Spin N' Win"], 1502, [GrinchRamData()]), + # "Dankamania - Easy - 15 Points": GrinchLocationData("Dankamania", ["Supadow Minigames", "Dankamania"], 1503, [GrinchRamData()]), + # "Dankamania - Hard - 15 Points": GrinchLocationData("Dankamania", ["Supadow Minigames", "Dankamania"], 1504, [GrinchRamData()]), + # "Dankamania - Real Tough - 15 Points": GrinchLocationData("Dankamania", ["Supadow Minigames", "Dankamania"], 1505, [GrinchRamData()]), + # "The Copter Race Contest - Easy": GrinchLocationData("The Copter Race Contest", ["Supadow Minigames", "The Copter Race Contest"], 1506, [GrinchRamData()]), + # "The Copter Race Contest - Hard": GrinchLocationData("The Copter Race Contest", ["Supadow Minigames", "The Copter Race Contest"], 1507, [GrinchRamData()]), + # "The Copter Race Contest - Real Tough": GrinchLocationData("The Copter Race Contest", ["Supadow Minigames", "The Copter Race Contest"], 1508, [GrinchRamData()]), + # "Bike Race - 1st Place": GrinchLocationData("Bike Race", ["Supadow Minigames", "Bike Race"], 1509, [GrinchRamData()]), + # "Bike Race - Top 2": GrinchLocationData("Bike Race", ["Supadow Minigames", "Bike Race"], 1510, [GrinchRamData()]), + # "Bike Race - Top 3": GrinchLocationData("Bike Race", ["Supadow Minigames", "Bike Race"], 1511, [GrinchRamData()]), + # Sleigh Part Locations + "WV - Exhaust Pipes": GrinchLocationData( + "Whoville", + ["Sleigh Ride", "Whoville"], + 1600, + [GrinchRamData(0x0101FB, binary_bit_pos=2)], + ), + "WF - Skis": GrinchLocationData( + "Who Forest", + ["Sleigh Ride", "Who Forest"], + 1601, + [GrinchRamData(0x0101FB, binary_bit_pos=3)], + ), + "WD - Tires": GrinchLocationData( + "Who Dump", + ["Sleigh Ride", "Who Dump"], + 1602, + [GrinchRamData(0x0101FB, binary_bit_pos=4)], + ), + "WL - Submarine World - Twin-End Tuba": GrinchLocationData( + "Submarine World", + ["Sleigh Ride", "Who Lake", "South Shore"], + 1603, + [GrinchRamData(0x0101FB, binary_bit_pos=6)], + ), + "WL - South Shore - GPS": GrinchLocationData( + "Who Lake", + ["Sleigh Ride", "Who Lake", "Submarine World"], + 1604, + [GrinchRamData(0x0101FB, binary_bit_pos=5)], + ), + # Mount Crumpit Locations + "MC - 1st Crate Squashed": GrinchLocationData( + "Mount Crumpit", ["Mount Crumpit"], 1700, [GrinchRamData(0x095343, value=1)] + ), + "MC - 2nd Crate Squashed": GrinchLocationData( + "Mount Crumpit", ["Mount Crumpit"], 1701, [GrinchRamData(0x095343, value=2)] + ), + "MC - 3rd Crate Squashed": GrinchLocationData( + "Mount Crumpit", ["Mount Crumpit"], 1702, [GrinchRamData(0x095343, value=3)] + ), + "MC - 4th Crate Squashed": GrinchLocationData( + "Mount Crumpit", ["Mount Crumpit"], 1703, [GrinchRamData(0x095343, value=4)] + ), + "MC - 5th Crate Squashed": GrinchLocationData( + "Mount Crumpit", ["Mount Crumpit"], 1704, [GrinchRamData(0x095343, value=5)] + ), } -def grinch_locations_to_id() -> dict[str,int]: + +def grinch_locations_to_id() -> dict[str, int]: location_mappings: dict[str, int] = {} for LocationName, LocationData in grinch_locations.items(): - location_mappings.update({LocationName: GrinchLocation.get_apid(LocationData.id)}) - return location_mappings \ No newline at end of file + location_mappings.update( + {LocationName: GrinchLocation.get_apid(LocationData.id)} + ) + return location_mappings diff --git a/worlds/grinch/Options.py b/worlds/grinch/Options.py index e6bdbb69..b39b444e 100644 --- a/worlds/grinch/Options.py +++ b/worlds/grinch/Options.py @@ -1,13 +1,26 @@ from dataclasses import dataclass -from Options import FreeText, NumericOption, Toggle, DefaultOnToggle, Choice, TextChoice, Range, NamedRange, OptionList, \ - PerGameCommonOptions, OptionSet +from Options import ( + FreeText, + NumericOption, + Toggle, + DefaultOnToggle, + Choice, + TextChoice, + Range, + NamedRange, + OptionList, + PerGameCommonOptions, + OptionSet, +) + class StartingArea(Choice): """ Here, you can select which area you'll start the game with. [NOT IMPLEMENTED] Whichever one you pick is the region you'll have access to at the start of the Multiworld. """ + option_whoville = 0 option_who_forest = 1 option_who_dump = 2 @@ -15,14 +28,17 @@ class StartingArea(Choice): default = 0 display_name = "Starting Area" -class ProgressiveVacuum(Toggle):#DefaultOnToggle + +class ProgressiveVacuum(Toggle): # DefaultOnToggle """ Determines whether you get access to main areas progressively [NOT IMPLEMENTED] Enabled: Whoville > Who Forest > Who Dump > Who Lake """ + display_name = "Progressive Vacuum Tubes" + class Missionsanity(Choice): """ How mission checks are randomized in the pool [NOT IMPLEMENTED] @@ -32,6 +48,7 @@ class Missionsanity(Choice): Individual: Individual tasks for one mission, such as individual snowmen squashed, are checks. Both: Both individual tasks and mission completion are randomized. """ + display_name = "Mission Locations" option_none = 0 option_completion = 1 @@ -39,6 +56,7 @@ class Missionsanity(Choice): option_both = 3 default = 1 + class ExcludeEnvironments(OptionSet): """ Allows entire environments to be an excluded location to ensure you are not logically required to enter the environment along @@ -51,50 +69,80 @@ class ExcludeEnvironments(OptionSet): "Ski Resort", "Civic Center", "Minefield", "Power Plant", "Generator Building", "Scout's Hut", "North Shore", "Mayor's Villa", "Sleigh Ride" """ - display_name = "Exclude Environments" - valid_keys = {"Whoville", "Who Forest", "Who Dump", "Who Lake", "Post Office", "Clock Tower", "City Hall", - "Ski Resort", "Civic Center", "Minefield", "Power Plant", "Generator Building", "Scout's Hut", - "North Shore", "Mayor's Villa", "Sleigh Ride"} -class ProgressiveGadget(Toggle):#DefaultOnToggle + display_name = "Exclude Environments" + valid_keys = { + "Whoville", + "Who Forest", + "Who Dump", + "Who Lake", + "Post Office", + "Clock Tower", + "City Hall", + "Ski Resort", + "Civic Center", + "Minefield", + "Power Plant", + "Generator Building", + "Scout's Hut", + "North Shore", + "Mayor's Villa", + "Sleigh Ride", + } + + +class ProgressiveGadget(Toggle): # DefaultOnToggle """ Determines whether you get access to a gadget as individual blueprint count. [NOT IMPLEMENTED] """ + display_name = "Progressive Gadgets" + class Supadow(Toggle): """Enables completing minigames through the Supadows in Mount Crumpit as checks. NOT IMPLEMENTED]""" + display_name = "Supadow Minigames" + class Gifts(Range): """ Considers how many gifts must be squashed per check. Enabling this will also enable squashing all gifts in a region mission along side this. [NOT IMPLEMENTED] """ + display_name = "Gifts Squashed per Check" range_start = 0 range_end = 300 default = 0 + class Moverando(Toggle): - """Randomizes Grinch's moveset along with randomizing max into the pool. [NOT IMPLEMENTED] - """ + """Randomizes Grinch's moveset along with randomizing max into the pool. [NOT IMPLEMENTED]""" + display_name = "Moves Randomized" + class UnlimitedEggs(Toggle): """Determine whether or not you run out of rotten eggs when you utilize your gadgets.""" + display_name = "Unlimited Rotten Eggs" + class RingLinkOption(Toggle): """Whenever this is toggled, your ammo is linked with other ringlink-compatible games that also have this enabled.""" + display_name = "Ring Link" + class TrapLinkOption(Toggle): """If a trap is sent from Grinch, traps that are compatible with other games are triggered as well. [NOT IMPLEMENTED]""" + display_name = "Trap Link" + @dataclass -class GrinchOptions(PerGameCommonOptions):#DeathLinkMixin +class GrinchOptions(PerGameCommonOptions): # DeathLinkMixin starting_area: StartingArea progressive_vacuum: ProgressiveVacuum missionsanity: Missionsanity diff --git a/worlds/grinch/RamHandler.py b/worlds/grinch/RamHandler.py index 3e0275ea..6b40e6bb 100644 --- a/worlds/grinch/RamHandler.py +++ b/worlds/grinch/RamHandler.py @@ -1,12 +1,66 @@ +from enum import STRICT, IntEnum from typing import NamedTuple, Optional +class UpdateMethod(IntEnum, boundary=STRICT): + SET = 1 + ADD = 2 + SUBTRACT = 3 + FREEZE = 4 + + class GrinchRamData(NamedTuple): + """A Representation of an update to RAM data for The Grinch. + + ram_address (int): The RAM address that we are updating, usually passed in with hex, representation (0x11111111) + value (int; Optional): The value we are using to set, add, or subtract from the RAM Address Value. Defaults to 1 if binary_bit_pos is passed in + binary_bit_pos: (int; Optional): If passed in, we are looking for a specific bit within the byte of the ram_address. This is represented as a small-endian bit position, meaning the right-most bit is 0, and the left-most bit is 7 + byte_size: (int: Default: 1): The size of the RAM Address address we are looking for. + update_method (UpdateMethod; Default: SET): Determines what we are doing to the RAM Address. We can either SET the address, simply assigning a value. We can ADD or SUBTRACT, modifying hte existing value by a set amount. And we can FREEZE the address, preventing it from updating in the future + min_count: The minimum amount that a value can go down to using SUBTRACT + max_count: The maximum amount that a value can go down to using ADD + """ + ram_address: int - value: Optional[int] = None #none is empty/null + value: Optional[int] = None # none is empty/null # Either set or add either hex or unsigned values through Client.py # Hex uses 0x00, unsigned are base whole numbers binary_bit_pos: Optional[int] = None - bit_size: int = 1 - update_existing_value: bool = False - max_count: int = 0 \ No newline at end of file + byte_size: int = 1 + update_method: UpdateMethod = UpdateMethod.SET + min_count: int = 0 + max_count: int = 255 + + def __init__( + self, + ram_address: int, + value: Optional[int], + byte_size: int, + update_method: UpdateMethod, + min_count: int, + max_count: int, + ): + self.ram_address = ram_address + + if value: + self.value = value + else: + self.value = 1 + + if byte_size: + self.byte_size = byte_size + + if update_method: + self.update_method = update_method + + if min_count and min_count > -1: + self.min_count = min_count + + if max_count and max_count > -1: + self.max_count = max_count + elif max_count and max_count > ((2 ** (self.byte_size * 8)) - 1): + raise ValueError( + "max_count cannot be larger than the RAM addresses max possible value" + ) + else: + self.max_count = (2 ** (self.byte_size * 8)) - 1 diff --git a/worlds/grinch/Regions.py b/worlds/grinch/Regions.py index da1e3068..2335a9cb 100644 --- a/worlds/grinch/Regions.py +++ b/worlds/grinch/Regions.py @@ -13,7 +13,7 @@ mainareas_list = [ "Whoville", "Who Forest", "Who Dump", - "Who Lake" + "Who Lake", ] subareas_list = [ @@ -29,29 +29,35 @@ subareas_list = [ "Scout's Hut", "North Shore", "Mayor's Villa", - "Sleigh Room" + "Sleigh Room", ] supadow_list = [ "Spin N' Win Supadow", "Dankamania Supadow", "The Copter Race Contest Supadow", - "Bike Race" + "Bike Race", ] + def create_regions(world: "GrinchWorld"): for mainarea in mainareas_list: - #Each area in mainarea, create a region for the given player - world.multiworld.regions.append(Region(mainarea, world.player, world.multiworld)) + # Each area in mainarea, create a region for the given player + world.multiworld.regions.append( + Region(mainarea, world.player, world.multiworld) + ) for subarea in subareas_list: - #Each area in subarea, create a region for the given player + # Each area in subarea, create a region for the given player world.multiworld.regions.append(Region(subarea, world.player, world.multiworld)) for supadow in supadow_list: - #Each area in supadow, create a region for the given player + # Each area in supadow, create a region for the given player world.multiworld.regions.append(Region(supadow, world.player, world.multiworld)) + # TODO Optimize this function -def grinchconnect(world: "GrinchWorld", current_region_name: str, connected_region_name: str): +def grinchconnect( + world: "GrinchWorld", current_region_name: str, connected_region_name: str +): current_region = world.get_region(current_region_name) connected_region = world.get_region(connected_region_name) required_items: list[list[str]] = access_rules_dict[connected_region.name] @@ -62,21 +68,26 @@ def grinchconnect(world: "GrinchWorld", current_region_name: str, connected_regi connected_region.connect(current_region) for access_rule in rule_list: for region_entrance in current_region.entrances: - if region_entrance.connected_region.name == current_region_name and \ - region_entrance.parent_region.name == connected_region_name: + if ( + region_entrance.connected_region.name == current_region_name + and region_entrance.parent_region.name == connected_region_name + ): if rule_list.index(access_rule) == 0: add_rule(region_entrance, access_rule) else: add_rule(region_entrance, access_rule, combine="or") for region_entrance in connected_region.entrances: - if region_entrance.connected_region.name == connected_region_name and \ - region_entrance.parent_region.name == current_region_name: + if ( + region_entrance.connected_region.name == connected_region_name + and region_entrance.parent_region.name == current_region_name + ): if rule_list.index(access_rule) == 0: add_rule(region_entrance, access_rule) else: add_rule(region_entrance, access_rule, combine="or") -#What regions are connected to each other + +# What regions are connected to each other def connect_regions(world: "GrinchWorld"): grinchconnect(world, "Mount Crumpit", "Whoville") grinchconnect(world, "Mount Crumpit", "Who Forest") diff --git a/worlds/grinch/Rules.py b/worlds/grinch/Rules.py index 96bb149a..fac34e55 100644 --- a/worlds/grinch/Rules.py +++ b/worlds/grinch/Rules.py @@ -4,9 +4,10 @@ import Utils from BaseClasses import CollectionState from worlds.AutoWorld import World from worlds.generic.Rules import add_rule -from .Items import * +from .Items import grinch_items -#Adds all rules from access_rules_dict to locations + +# Adds all rules from access_rules_dict to locations def set_location_rules(world: World): all_locations = world.get_locations() for location in all_locations: @@ -18,6 +19,7 @@ def set_location_rules(world: World): else: add_rule(location, access_rule, "or") + def interpret_rule(rule_set: list[list[str]], player: int): # If a region/location does not have any items required, make the section(s) return no logic. if len(rule_set) < 1: @@ -27,344 +29,727 @@ def interpret_rule(rule_set: list[list[str]], player: int): access_list: list[Callable[[CollectionState], bool]] = [] for item_set in rule_set: - access_list.append(lambda state, items=tuple(item_set): state.has_all(items, player)) + access_list.append( + lambda state, items=tuple(item_set): state.has_all(items, player) + ) return access_list - #Each item in the list is a separate list of rules. Each separate list is just an "OR" condition. -rules_dict: dict[str,list[list[str]]] = { - "WV - First Visit": [ - [] + # Each item in the list is a separate list of rules. Each separate list is just an "OR" condition. + + +access_rules_dict: dict[str, list[list[str]]] = { + "Whoville": [ + [ + grinch_items.keys.WHOVILLE, + ] ], - "WV - Post Office - First Visit": [ - [] + "Post Office": [ + [ + grinch_items.level_items.WV_WHO_CLOAK, + ] ], - "WV - City Hall - First Visit": [ - [] + "City Hall": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ] ], - "WV - Clock Tower - First Visit": [ - [] + "Clock Tower": [[]], + "Who Forest": [ + [ + grinch_items.keys.WHO_FOREST, + ], ], - "WF - First Visit": [ - [] + "Ski Resort": [ + [ + grinch_items.level_items.WF_CABLE_CAR_ACCESS_CARD, + ] ], - "WF - Ski Resort - First Visit": [ - [] + "Civic Center": [ + [ + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + ], ], - "WF - Civic Center - First Visit": [ - [] + "Who Dump": [ + [ + grinch_items.keys.WHO_DUMP, + ], ], - "WD - First Visit": [ - [] + "Minefield": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], - "WD - Minefield - First Visit": [ - [] + "Power Plant": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], ], - "WD - Power Plant - First Visit": [ - [] + "Generator Building": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], ], - "WD - Generator Building - First Visit": [ - [] + "Who Lake": [ + [ + grinch_items.keys.WHO_LAKE, + ], ], - "WL - South Shore - First Visit": [ - [] + "Scout's Hut": [ + [ + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_SPRING, + ], ], - "WL - Submarine World - First Visit": [ - [] + "North Shore": [ + [ + grinch_items.level_items.WL_SCOUT_CLOTHESL, + ] ], - "WL - Scout's Hut - First Visit": [ - [] + "Mayor's Villa": [ + [ + grinch_items.level_items.WL_SCOUT_CLOTHESL, + ] ], - "WL - North Shore - First Visit": [ - [] + "Submarine World": [ + [ + grinch_items.gadgets.MARINE_MOBILE, + ] ], - "WL - Mayor's Villa - First Visit": [ - [] - ], - "WV - Post Office - Shuffling The Mail": [ - [] - ], - "WV - Smashing Snowmen": [ - [] - # "move_rando" - # [PC] + "Sleigh Room": [ + [ + grinch_items.keys.SLEIGH_ROOM_KEY, + ] ], + "Spin N' Win": [[]], + "Dankamania": [], + "The Copter Race Contest": [[]], + "Bike Race": [[]], +} + + +rules_dict: dict[str, list[list[str]]] = { + # Rules applied to regions first via the access_list, so "First Visit" checks should ALWAYS be empty + # First Visit Checks (ALWAYS empty) + "WV - First Visit": [[]], + "WV - Post Office - First Visit": [[]], + "WV - City Hall - First Visit": [[]], + "WV - Clock Tower - First Visit": [[]], + "WF - First Visit": [[]], + "WF - Ski Resort - First Visit": [[]], + "WF - Civic Center - First Visit": [[]], + "WD - First Visit": [[]], + "WD - Minefield - First Visit": [[]], + "WD - Power Plant - First Visit": [[]], + "WD - Generator Building - First Visit": [[]], + "WL - South Shore - First Visit": [[]], + "WL - Submarine World - First Visit": [[]], + "WL - Scout's Hut - First Visit": [[]], + "WL - North Shore - First Visit": [[]], + "WL - Mayor's Villa - First Visit": [[]], + # Whoville Missions + "WV - Post Office - Shuffling The Mail": [[]], + "WV - Smashing Snowmen": [[]], "WV - Painting The Mayor's Posters": [ - [PB] + [ + grinch_items.level_items.WV_PAINT_BUCKET, + ] ], "WV - Launching Eggs Into Houses": [ - [REL] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ] ], "WV - City Hall - Modifying The Mayor's Statue": [ - [ST] - # "move_rando" - # [ST, SN], - # [ST, SS] + [ + grinch_items.level_items.WV_SCULPTING_TOOLS, + ] ], "WV - Clock Tower - Advancing The Countdown-To-Xmas Clock": [ - [HMR, RS] + [ + grinch_items.level_items.WV_HAMMER, + grinch_items.gadgets.ROCKET_SPRING, + ] ], "WV - Squashing All Gifts": [ - [GC, SS, REL, WC, RS] + [ + grinch_items.gadgets.GRINCH_COPTER, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.level_items.WV_WHO_CLOAK, + grinch_items.gadgets.ROCKET_SPRING, + ] ], + # Who Forest Missions "WF - Making Xmas Trees Droop": [ - [REL] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ] # "move_rando" - # [REL, BB] + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, BB] ], "WF - Sabotaging Snow Cannon With Glue": [ - [GB, RS], - [GB, GC] + [ + grinch_items.level_items.WF_GLUE_BUCKET, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.level_items.WF_GLUE_BUCKET, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - Putting Beehives In Cabins": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - Ski Resort - Sliming The Mayor's Skis": [ - [SS, REL] + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ] ], "WF - Civic Center - Replacing The Candles On The Cake With Fireworks": [ - [REL, GC], - [REL, OCD, RS] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.ROCKET_SPRING, + ], # "move_rando" - # [REL, GC], - # [REL, OCD, RS, SN], - # [REL, OCD, RS, SS] + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.GRINCH_COPTER], + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, grinch_items.gadgets.ROCKET_SPRING, SN], + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, grinch_items.gadgets.ROCKET_SPRING, grinch_items.gadgets.SLIME_SHOOTER] ], "WF - Squashing All Gifts": [ - [GC, CCAC, SS, REL], - [OCD, RS, CCAC, SS, REL] + [ + grinch_items.gadgets.GRINCH_COPTER, + grinch_items.level_items.WF_CABLE_CAR_ACCESS_CARD, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ], + [ + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.level_items.WF_CABLE_CAR_ACCESS_CARD, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ], ], + # Who Dump Missions "WD - Stealing Food From Birds": [ - [RS, REL] + [ + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ] # "move_rando" - # [RS, REL, PC] + # [grinch_items.gadgets.ROCKET_SPRING, grinch_items.gadgets.ROCKET_EGG_LAUNCHER, PC] ], "WD - Feeding The Computer With Robot Parts": [ - [RS, REL] + [ + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ] # "move_rando" - # [RS, REL, PC] + # [grinch_items.gadgets.ROCKET_SPRING, grinch_items.gadgets.ROCKET_EGG_LAUNCHER, PC] ], "WD - Infesting The Mayor's House With Rats": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], # "move_rando" - # [REL, RS, PC], - # [REL, GC, PC] + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.ROCKET_SPRING, PC], + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.GRINCH_COPTER, PC] ], "WD - Conducting The Stinky Gas To Who-Bris' Shack": [ - [RS, REL] + [ + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ] # "move_rando" - # [RS, REL, PC] + # [grinch_items.gadgets.ROCKET_SPRING, grinch_items.gadgets.ROCKET_EGG_LAUNCHER, PC] ], "WD - Minefield - Shaving Who Dump Guardian": [ - [SC, GC], - [SC, SS, RS] + [ + grinch_items.level_items.WL_SCOUT_CLOTHES, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.level_items.WL_SCOUT_CLOTHES, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], # "move_rando" - # [SC, GC, SN], - # [SC, SS, RS, SN] + # [grinch_items.level_items.WL_SCOUT_CLOTHES, grinch_items.gadgets.GRINCH_COPTER, SN], + # [grinch_items.level_items.WL_SCOUT_CLOTHES, grinch_items.gadgets.SLIME_SHOOTER, grinch_items.gadgets.ROCKET_SPRING, SN] ], "WD - Generator Building - Short-Circuiting Power-Plant": [ - [REL, GC], - [REL, OCD, SS, RS] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], ], "WD - Squashing All Gifts": [ - [GC, RS, SS, REL], - [OCD, RS, SS, REL] + [ + grinch_items.gadgets.GRINCH_COPTER, + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ], + [ + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ], ], + # Who Lake Missions "WL - South Shore - Putting Thistles In Shorts": [ - [REL, OCD], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WL - South Shore - Sabotaging The Tents": [ - [OCD, RS], - [GC] + [ + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.ROCKET_SPRING, + ], + [grinch_items.gadgets.GRINCH_COPTER], ], "WL - North Shore - Drilling Holes In Canoes": [ - [DRL] - ], - "WL - Submarine World - Modifying The Marine Mobile": [ - [] + [ + grinch_items.level_items.WL_DRILL, + ] ], + "WL - Submarine World - Modifying The Marine Mobile": [[]], "WL - Mayor's Villa - Hooking The Mayor's Bed To The Motorboat": [ - [RP, HK, REL, SCL] + [ + grinch_items.level_items.WL_ROPE, + grinch_items.level_items.WL_HOOK, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.level_items.WL_SCOUT_CLOTHES, + ] ], "WL - Squashing All Gifts": [ - [GC, MM, SCL, REL, HK, RP], - [OCD, RS, MM, SCL, REL, HK, RP] + [ + grinch_items.gadgets.GRINCH_COPTER, + grinch_items.gadgets.MARINE_MOBILE, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.level_items.WL_SCOUT_CLOTHES, + grinch_items.level_items.WL_HOOK, + grinch_items.level_items.WL_ROPE, + ], + [ + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.MARINE_MOBILE, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.level_items.WL_SCOUT_CLOTHES, + grinch_items.level_items.WL_HOOK, + grinch_items.level_items.WL_ROPE, + ], ], - "WV - Binoculars BP on Post Office Roof": [ + # Whoville Blueprints + "WV - Binoculars BP on Post Office Roof": [[]], + "WV - City Hall - Binoculars BP left side of Library": [[]], + "WV - City Hall - Binoculars BP front side of Library": [[]], + "WV - City Hall - Binoculars BP right side of Library": [[]], + "WV - TEL BP left of City Hall": [[]], + "WV - REL BP left of Clock Tower": [[]], + "WV - Post Office - REL BP inside Silver Room": [[]], + "WV - Post Office - REL BP at Entrance Door after Migrinch_items.gadgets.SLIME_SHOOTERion Completion": [ [] ], - "WV - City Hall - Binoculars BP left side of Library": [ - [] - ], - "WV - City Hall - Binoculars BP front side of Library": [ - [] - ], - "WV - City Hall - Binoculars BP right side of Library": [ - [] - ], - "WV - REL BP left of City Hall": [ - [] - ], - "WV - REL BP left of Clock Tower": [ - [] - ], - "WV - Post Office - REL BP inside Silver Room": [ - [WC] + "WV - City Hall - GC BP in Safe Room": [[]], + "WV - City Hall - GC BP in Statue Room": [[]], + "WV - Clock Tower - GC BP in Bedroom": [ + [grinch_items.gadgets.ROCKET_SPRING] # "move_rando" - # [WC, MX] + # [MX, grinch_items.gadgets.ROCKET_SPRING] ], - "WV - Post Office - REL BP at Entrance Door after Mission Completion": [ - [WC] - # "move_rando" - # [WC, MX] - ], - "WF - RS BP behind Vacuum Tube": [ - [] - ], - "WF - RS BP in front of 2nd House near Vacuum Tube": [ - [] - ], - "WF - RS BP near Tree House on Ground": [ - [] - ], - "WF - RS BP behind Cable Car House": [ - [] - ], - "WF - RS BP near Who Snowball in Cave": [ - [] - ], - "WF - RS BP on Branch Platform closest to Glue Cannon": [ - [] - ], - "WF - RS BP on Branch Platform Near Beast": [ - [] - ], - "WF - RS BP on Branch Platform Elevated next to House": [ - [] + "WV - Clock Tower - GC BP in Bell Room": [ + [ + grinch_items.gadgets.ROCKET_SPRING, + ] ], + # Who Forest Blueprints + "WF - RS BP behind Vacuum Tube": [[]], + "WF - RS BP in front of 2nd House near Vacuum Tube": [[]], + "WF - RS BP near Tree House on Ground": [[]], + "WF - RS BP behind Cable Car House": [[]], + "WF - RS BP near Who Snowball in Cave": [[]], + "WF - RS BP on Branch Platform closest to Glue Cannon": [[]], + "WF - RS BP on Branch Platform Near Beast": [[]], + "WF - RS BP on Branch Platform Elevated next to House": [[]], "WF - RS BP on Tree House": [ - [REL], - [GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + ], + [ + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - SS BP in Branch Platform Elevated House": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - SS BP in Branch Platform House next to Beast": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - SS BP in House in front of Civic Center Cave": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - SS BP in House next to Tree House": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], - "WF - SS BP in House across from Tree House": [ - [REL, RS], - [REL, GC] + "WF - SS BP in House acrogrinch_items.gadgets.SLIME_SHOOTER from Tree House": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - SS BP in 2nd House near Vacuum Tube Right Side": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - SS BP in 2nd House near Vacuum Tube Left Side": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - SS BP in 2nd House near Vacuum Tube inbetween Blueprints": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WF - SS BP in House near Vacuum Tube": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], + "WF - Ski Resort - GC BP inside Dog's Fence": [[]], + "WF - Ski Resort - GC BP in Max Cave": [ + [] + # "move_rando" + # [MX] + ], + "WF - Civic Center - GC BP on Left Side in Bat Cave Wall": [ + [ + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.ROCKET_SPRING, + ], + ], + "WF - Civic Center - GC BP in Frozen Ice": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.ROCKET_SPRING, + ], + ], + # Who Dump Blueprints "WD - OCD BP inside Middle Pipe": [ - [REL, RS], - [REL, GC], - [SS, RS], - [SS, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WD - OCD BP inside Right Pipe": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WD - OCD BP in Vent to Mayor's House": [ - [REL, RS], - [REL, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WD - OCD BP inside Left Pipe": [ - [REL, RS], - [REL, GC], - [SS, RS], - [SS, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WD - OCD BP near Right Side of Power Plant Wall": [ - [REL, RS], - [REL, GC], - [SS, RS], - [SS, GC] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WD - OCD BP near Who-Bris' Shack": [ - [REL, RS] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ] ], "WD - Minefield - OCD BP on Left Side of House": [ [] # "move_rando" - # [REL, GC], - # [REL, SS, RS] + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.GRINCH_COPTER], + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.SLIME_SHOOTER, grinch_items.gadgets.ROCKET_SPRING] # [MX] ], "WD - Minefield - OCD BP on Right Side of Shack": [ - [GC], - [SS, RS] + [ + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], ], "WD - Minefield - OCD BP inside Guardian's House": [ [] # "move_rando" - # [REL, GC], - # [REL, SS, RS] + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.GRINCH_COPTER], + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.SLIME_SHOOTER, grinch_items.gadgets.ROCKET_SPRING] # [MX] ], - "WL - South Shore - MM BP on Bridge to Scout's Hut": [ + "WD - Power Plant - GC BP in Max Cave": [ [] + # "move_rando" + # [MX] ], - "WL - South Shore - MM BP across from Tent near Porcupine": [ - [] + "WD - Power Plant - GC BP After First Gate": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.GRINCH_COPTER, + ], + # "move_rando" + # [MX, grinch_items.gadgets.ROCKET_EGG_LAUNCHER, grinch_items.gadgets.ROCKET_SPRING] ], - "WL - South Shore - MM BP near Outhouse": [ - [] + "WD - Generator Building - GC BP on the Highest Platform": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], ], - "WL - South Shore - MM BP near Hill Bridge": [ - [] + "WD - Generator Building - GC BP at the Entrance after Migrinch_items.gadgets.SLIME_SHOOTERion Completion": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], ], + # Who Lake Blueprints + "WL - South Shore - MM BP on Bridge to Scout's Hut": [[]], + "WL - South Shore - MM BP across from Tent near Porcupine": [[]], + "WL - South Shore - MM BP near Outhouse": [[]], + "WL - South Shore - MM BP near Hill Bridge": [[]], "WL - South Shore - MM BP on Scout's Hut Roof": [ - [RS], - [GC] + [ + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WL - South Shore - MM BP on Grass Platform": [ - [RS], - [GC] + [ + grinch_items.gadgets.ROCKET_SPRING, + ], + [ + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WL - South Shore - MM BP across Zipline Platform": [ - [RS, OCD], - [GC] + [ + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + ], + [ + grinch_items.gadgets.GRINCH_COPTER, + ], ], "WL - South Shore - MM BP behind Summer Beast": [ - [REL, OCD], - [GC] - ], - "WL - North Shore - MM BP below Bridge": [ - [] - ], - "WL - North Shore - MM BP behind Skunk Hut": [ - [] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.OCTOPUS_CLIMBING_DEVICE, + ], + [ + grinch_items.gadgets.GRINCH_COPTER, + ], ], + "WL - North Shore - MM BP below Bridge": [[]], + "WL - North Shore - MM BP behind Skunk Hut": [[]], "WL - North Shore - MM BP inside Skunk Hut": [ [] # "move_rando" @@ -375,182 +760,128 @@ rules_dict: dict[str,list[list[str]]] = { # "move_rando" # [MX] ], - "WL - North Shore - MM BP inside Boulder Box near Bridge": [ - [] - ], - "WL - North Shore - MM BP inside Boulder Box behind Skunk Hut": [ - [] - ], - "WL - North Shore - MM BP inside Drill House": [ - [] - ], - "WL - North Shore - MM BP on Crow Platform near Drill House": [ - [] - ], - "WV - City Hall - GC BP in Safe Room": [ - [] - ], - "WV - City Hall - GC BP in Statue Room": [ - [] - ], - "WV - Clock Tower - GC BP in Bedroom": [ - [RS] - # "move_rando" - # [MX, RS] - ], - "WV - Clock Tower - GC BP in Bell Room": [ - [RS] - ], - "WF - Ski Resort - GC BP inside Dog's Fence": [ - [] - ], - "WF - Ski Resort - GC BP in Max Cave": [ - [] - # "move_rando" - # [MX] - ], - "WF - Civic Center - GC BP on Left Side in Bat Cave Wall": [ - [GC], - [OCD, RS] - ], - "WF - Civic Center - GC BP in Frozen Ice": [ - [REL, GC], - [REL, OCD, RS], - [SS, GC], - [SS, OCD, RS] - ], - "WD - Power Plant - GC BP in Max Cave": [ - [] - # "move_rando" - # [MX] - ], - "WD - Power Plant - GC BP After First Gate": [ - [REL, RS], - [GC] - # "move_rando" - # [MX, REL, RS] - ], - "WD - Generator Building - GC BP on the Highest Platform": [ - [REL, GC], - [REL, OCD, SS, RS] - ], - "WD - Generator Building - GC BP at the Entrance after Mission Completion": [ - [REL, GC], - [REL, OCD, SS, RS] - ], + "WL - North Shore - MM BP inside Boulder Box near Bridge": [[]], + "WL - North Shore - MM BP inside Boulder Box behind Skunk Hut": [[]], + "WL - North Shore - MM BP inside Drill House": [[]], + "WL - North Shore - MM BP on Crow Platform near Drill House": [[]], "WL - Submarine World - GC BP Just Below Water Surface": [ - [MM] + [grinch_items.gadgets.MARINE_MOBILE] ], "WL - Submarine World - GC BP Underwater": [ - [MM] + [ + grinch_items.gadgets.MARINE_MOBILE, + ] ], "WL - Mayor's Villa - GC BP on Tree Branch": [ - [GC], - [REL, RS] + [ + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], ], "WL - Mayor's Villa - GC BP in Pirate's Cave": [ - [GC], - [REL, RS] + [ + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.ROCKET_SPRING, + ], + ], + # Finale + "WV - Exhaust Pipes": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.keys.SLEIGH_ROOM_KEY, + ] + ], + "WF - Skis": [ + [ + grinch_items.keys.SLEIGH_ROOM_KEY, + ] + ], + "WD - Tires": [ + [ + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.keys.SLEIGH_ROOM_KEY, + ] + ], + "WL - Submarine World - Twin-End Tuba": [ + [ + grinch_items.gadgets.MARINE_MOBILE, + grinch_items.keys.SLEIGH_ROOM_KEY, + ] + ], + "WL - South Shore - GPS": [ + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.keys.SLEIGH_ROOM_KEY, + ] ], "MC - Sleigh Ride - Stealing All Gifts": [ # ["Exhaust Pipes", "Tires", "Skis", "Twin-End Tuba"] - [REL, WV, WF, WD, WL, RS, MM] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.keys.WHOVILLE, + grinch_items.keys.WHO_FOREST, + grinch_items.keys.WHO_DUMP, + grinch_items.keys.WHO_LAKE, + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.MARINE_MOBILE, + ] ], "MC - Sleigh Ride - Neutralizing Santa": [ # ["Exhaust Pipes", "Tires", "Skis", "Twin-End Tuba"] - [REL, WV, WF, WD, WL, RS, MM] - ], - "WV - Post Office - Heart of Stone": [ - [] - ], - "WF - Ski Resort - Heart of Stone": [ - [] + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.keys.WHOVILLE, + grinch_items.keys.WHO_FOREST, + grinch_items.keys.WHO_DUMP, + grinch_items.keys.WHO_LAKE, + grinch_items.gadgets.ROCKET_SPRING, + grinch_items.gadgets.MARINE_MOBILE, + ] ], + # Hearts of Stone + "WV - Post Office - Heart of Stone": [[]], + "WF - Ski Resort - Heart of Stone": [[]], "WD - Minefield - Heart of Stone": [ - [GC], - [REL, SS, RS] + [ + grinch_items.gadgets.GRINCH_COPTER, + ], + [ + grinch_items.gadgets.ROCKET_EGG_LAUNCHER, + grinch_items.gadgets.SLIME_SHOOTER, + grinch_items.gadgets.ROCKET_SPRING, + ], ], "WL - North Shore - Heart of Stone": [ [] # "move_rando" # [MX] ], - "Spin N' Win - Easy": [ - [] - ], - "Spin N' Win - Hard": [ - [] - ], - "Spin N' Win - Real Tough": [ - [] - ], - "Dankamania - Easy - 15 Points": [ - [] - ], - "Dankamania - Hard - 15 Points": [ - [] - ], - "Dankamania - Real Tough - 15 Points": [ - [] - ], - "The Copter Race Contest - Easy": [ - [] - ], - "The Copter Race Contest - Hard": [ - [] - ], - "The Copter Race Contest - Real Tough": [ - [] - ], - "Bike Race - 1st Place": [ - [] - ], - "Bike Race - Top 2": [ - [] - ], - "Bike Race - Top 3": [ - [] - ], - "WV - Exhaust Pipes": [ - [WV, REL, SR] - ], - "WF - Skis": [ - [WF, SR] - ], - "WD - Tires": [ - [WD, RS, REL, SR] - ], - "WL - Submarine World - Twin-End Tuba": [ - [WL, MM, SR] - ], - "WL - South Shore - GPS": [ - [WL, REL, SR] - ], - "MC - 1st Crate Squashed": [ - [] - # "move_rando" - # [PC] - ], - "MC - 2nd Crate Squashed": [ - [] - # "move_rando" - # [PC] - ], - "MC - 3rd Crate Squashed": [ - [] - # "move_rando" - # [PC] - ], - "MC - 4th Crate Squashed": [ - [] - # "move_rando" - # [PC] - ], - "MC - 5th Crate Squashed": [ - [] - # "move_rando" - # [PC] - ] + # Supadows + "Spin N' Win - Easy": [[]], + "Spin N' Win - Hard": [[]], + "Spin N' Win - Real Tough": [[]], + "Dankamania - Easy - 15 Points": [[]], + "Dankamania - Hard - 15 Points": [[]], + "Dankamania - Real Tough - 15 Points": [[]], + "The Copter Race Contest - Easy": [[]], + "The Copter Race Contest - Hard": [[]], + "The Copter Race Contest - Real Tough": [[]], + "Bike Race - 1st Place": [[]], + "Bike Race - Top 2": [[]], + "Bike Race - Top 3": [[]], + # Intro + "MC - 1st Crate Squashed": [[]], + "MC - 2nd Crate Squashed": [[]], + "MC - 3rd Crate Squashed": [[]], + "MC - 4th Crate Squashed": [[]], + "MC - 5th Crate Squashed": [[]], # "Green Present": [ # [] # ], @@ -558,7 +889,7 @@ rules_dict: dict[str,list[list[str]]] = { # [] # ], # "Pink Present": [ - # [REL], + # [grinch_items.gadgets.ROCKET_EGG_LAUNCHER], # [move_rando] # [PC] # ], @@ -568,97 +899,3 @@ rules_dict: dict[str,list[list[str]]] = { # [PC] # ] } - - - -access_rules_dict: dict[str,list[list[str]]] = { - "Whoville": [ - [WV] - ], - "Post Office": [ - [WC] - ], - "City Hall": [ - [REL] - ], - "Clock Tower": [ - [] - # "move_rando" - # [SN] - ], - "Who Forest": [ - [WF], - # [VT: 1] - ], - "Ski Resort": [ - [CCAC] - ], - "Civic Center": [ - [GC], - [OCD] - ], - "Who Dump": [ - [WD], - # [VT: 2] - ], - "Minefield": [ - [REL, RS], - [REL, GC] - # "move_rando" - # [REL, RS, PC], - # [REL, GC, PC] - ], - "Power Plant": [ - [REL, GC], - [SS, GC], - [REL, OCD, SS, RS] - # "move_rando" - # [REL, GC, PC], - # [SS, GC, PC], - # [REL, OCD, SS, RS, PC] - ], - "Generator Building": [ - [REL, GC], - [REL, OCD, SS, RS] - ], - "Who Lake": [ - [WL], - # [VT: 3] - ], - "Scout's Hut": [ - [GC], - [RS] - ], - "North Shore": [ - [SCL] - ], - "Mayor's Villa": [ - [SCL] - ], - "Submarine World": [ - [MM] - ], - "Sleigh Room": [ - [SR] - ], - "Spin N' Win": [ - [] - # ["Spin N' Win Door Unlock"], - # ["Progressive Supadow Door Unlock"] - ], - "Dankamania": [ - [] - # ["Dankamania Door Unlock"], - # ["Progressive Supadow Door Unlock: 2"] - ], - "The Copter Race Contest": [ - [] - # ["The Copter Race Contest Door Unlock"], - # ["Progressive Supadow Door Unlock: 3"] - ], - "Bike Race": [ - [] - # ["Bike Race Access"], - # ["Progressive Supadow Door Unlock: 4"] - ] -} \ No newline at end of file