diff --git a/__init__.py b/__init__.py index a06a73aca..0a420b5ed 100644 --- a/__init__.py +++ b/__init__.py @@ -162,6 +162,7 @@ def copy_dependencies(zip_path, file): from randomizer.Enums.Maps import Maps from randomizer.Enums.Minigames import Minigames from randomizer.Enums.Locations import Locations as DK64RLocations + from randomizer.Enums.Regions import Regions from randomizer.Enums.Settings import ( Enemies, GlitchesSelected, @@ -184,6 +185,7 @@ def copy_dependencies(zip_path, file): from worlds.LauncherComponents import Component, SuffixIdentifier, components, Type, icon_paths import randomizer.ShuffleExits as ShuffleExits from archipelago.FillSettings import fillsettings + from archipelago import Tracker from Utils import open_filename import shutil import zlib @@ -283,8 +285,19 @@ class EnableMinimalLogic(settings.Bool): This allows hosts to disable the minimal logic option if they don't want it on their server. """ + class UTPackPath(settings.UserFilePath): + """Path to external Universal Tracker pack .zip file. + + Download the DK64 tracker pack from https://github.com/UmedMuzl/dk64pt/releases + and point this setting to the downloaded .zip file to enable map tracking in Universal Tracker. + Leave empty to disable map tracking. + """ + + description = "Universal Tracker Pack Path (Optional)" + release_branch: ReleaseVersion = ReleaseVersion("master") enable_minimal_logic_dk64: EnableMinimalLogic | bool = False + ut_pack_path: typing.Union[UTPackPath, str] = UTPackPath("") class DK64Web(WebWorld): """WebWorld for DK64.""" @@ -325,6 +338,7 @@ class DK64World(World): item_name_to_id = {name: data.code for name, data in full_item_table.items()} location_name_to_id = all_locations + tracker_world: typing.ClassVar = Tracker.tracker_world def blueprint_item_group() -> str: """Item group for blueprints.""" @@ -872,6 +886,42 @@ def _convert_to_cumulative_prices(self, individual_prices, shop_locations, max_c return cumulative_prices + def _restore_custom_location_names(self, custom_location_names: dict): + """Restore custom location names from slot data for UT regeneration.""" + from randomizer.Lists.Location import LocationListOriginal as VanillaLocationList + from archipelago.Regions import BASE_ID + + if not custom_location_names: + return + + print(f"[DK64 UT] Restoring {len(custom_location_names)} custom location names") + + # Build enum_to_index mapping + enum_to_index = {location: index for index, location in enumerate(VanillaLocationList)} + # Build reverse mapping: location_id -> location_enum + index_to_enum = {index: location for location, index in enum_to_index.items()} + + restored_count = 0 + sample_names = [] + for loc_id_str, data in custom_location_names.items(): + loc_id = int(loc_id_str) + # Calculate the enum from the location ID + index = loc_id - BASE_ID + if index in index_to_enum: + location_enum = index_to_enum[index] + if location_enum in self.spoiler.LocationList: + # Restore the custom name + if isinstance(data, dict) and "name" in data: + new_name = data["name"] + self.spoiler.LocationList[location_enum].name = new_name + restored_count += 1 + if restored_count <= 5: + sample_names.append(f" {new_name}") + + print(f"[DK64 UT] Restored {restored_count} names, samples:") + for name in sample_names: + print(name) + def _generate_archipelago_prices(self): """Generate custom shop prices for Archipelago. @@ -1093,8 +1143,61 @@ def generate_early(self): self.spoiler.LocationList[DK64RLocations.FactoryDonkeyDKArcade].name = "Factory Donkey DK Arcade Round 1" self.spoiler.settings.shuffled_location_types.append(Types.ArchipelagoItem) + # For UT regeneration, restore DK portal locations + if hasattr(settings, "ut_dk_portal_locations"): + self.spoiler.human_entry_doors = settings.ut_dk_portal_locations + + # Handle custom location shuffling BEFORE regions are created + # This needs to happen early so the logic system knows about the new locations + from randomizer.Lists.CustomLocations import resetCustomLocations + from randomizer.ShuffleCrowns import ShuffleCrowns + from randomizer.ShuffleCrates import ShuffleMelonCrates + from randomizer.ShufflePatches import ShufflePatches + + resetCustomLocations(self.spoiler) + + # Check if this is a UT regeneration - use generation_is_fake flag + is_ut_regen = hasattr(self.multiworld, "generation_is_fake") + print(f"[DK64] Is UT regen: {is_ut_regen}, has generation_is_fake: {hasattr(self.multiworld, 'generation_is_fake')}") + + # Store custom location flags + do_crown_shuffle = self.spoiler.settings.crown_placement_rando + do_patch_shuffle = self.spoiler.settings.random_patches + do_crate_shuffle = self.spoiler.settings.random_crates + print(f"[DK64] Shuffle flags - Crowns: {do_crown_shuffle}, Patches: {do_patch_shuffle}, Crates: {do_crate_shuffle}") + + # Temporarily disable custom locations so Generate_Spoiler doesn't run them + self.spoiler.settings.crown_placement_rando = False + self.spoiler.settings.random_patches = False + self.spoiler.settings.random_crates = False + Generate_Spoiler(self.spoiler) + # Restore settings + self.spoiler.settings.crown_placement_rando = do_crown_shuffle + self.spoiler.settings.random_patches = do_patch_shuffle + self.spoiler.settings.random_crates = do_crate_shuffle + + if not is_ut_regen: + # Normal generation - run custom location shuffles + if do_crown_shuffle: + crown_replacements = {} + crown_human_replacements = {} + ShuffleCrowns(self.spoiler, crown_replacements, crown_human_replacements) + self.spoiler.crown_locations = crown_replacements + self.spoiler.human_crowns = dict(sorted(crown_human_replacements.items())) + print(f"[DK64] Shuffled {len([c for crowns in crown_replacements.values() for c in crowns])} battle arenas") + + if do_patch_shuffle: + human_patches = {} + self.spoiler.human_patches = ShufflePatches(self.spoiler, human_patches).copy() + print(f"[DK64] Shuffled {len(self.spoiler.dirt_patch_placement)} dirt patches") + + if do_crate_shuffle: + human_crates = {} + self.spoiler.human_crates = ShuffleMelonCrates(self.spoiler, human_crates).copy() + print(f"[DK64] Shuffled {len(self.spoiler.meloncrate_placement)} melon crates") + # Store/retrieve blocker values for seed group synchronization if self.options.loading_zone_rando.value not in [0, LoadingZoneRando.option_no]: if self.options.loading_zone_rando.value not in LoadingZoneRando.options.values(): @@ -1185,6 +1288,13 @@ def generate_early(self): Generate_Spoiler(self.spoiler) + # For UT: Restore custom location names after Generate_Spoiler + if hasattr(self.multiworld, "generation_is_fake") and hasattr(self.multiworld, "re_gen_passthrough"): + if "Donkey Kong 64" in self.multiworld.re_gen_passthrough: + passthrough = self.multiworld.re_gen_passthrough["Donkey Kong 64"] + custom_location_names = passthrough.get("CustomLocationNames", {}) + self._restore_custom_location_names(custom_location_names) + # Store/retrieve blocker values for seed group synchronization if self.options.loading_zone_rando.value not in [0, LoadingZoneRando.option_no]: if self.options.loading_zone_rando.value not in LoadingZoneRando.options.values(): @@ -1239,6 +1349,8 @@ def generate_early(self): if hasattr(self.multiworld, "re_gen_passthrough"): if "Donkey Kong 64" in self.multiworld.re_gen_passthrough: passthrough = self.multiworld.re_gen_passthrough["Donkey Kong 64"] + + # Restore enemy, minigame, shop, and portal data if passthrough["EnemyData"]: for location, data in passthrough["EnemyData"].items(): self.spoiler.enemy_location_list[DK64RLocations[location]] = EnemyLoc(Maps[data["map"]], Enemies[data["enemy"]], 0, [], False) @@ -1259,6 +1371,62 @@ def generate_early(self): except (KeyError, AttributeError): print(f"Warning: Could not restore price for location {location_name}") self.spoiler.settings.prices = restored_prices + if passthrough.get("DKPortalLocations") and passthrough["DKPortalLocations"]: + # Restore DK Portal locations + self.spoiler.human_entry_doors = passthrough["DKPortalLocations"] + + # Update entry handler region exits to point to the restored DK Portal locations + # This matches the behavior in DoorData.assignDKPortal() + from randomizer.Enums.Levels import Levels + from randomizer.Lists.DoorLocations import door_locations, LEVEL_ENTRY_HANDLER_REGIONS + from randomizer.LogicClasses import TransitionFront + + level_name_to_enum = { + "Jungle Japes": Levels.JungleJapes, + "Angry Aztec": Levels.AngryAztec, + "Frantic Factory": Levels.FranticFactory, + "Gloomy Galleon": Levels.GloomyGalleon, + "Fungi Forest": Levels.FungiForest, + "Crystal Caves": Levels.CrystalCaves, + "Creepy Castle": Levels.CreepyCastle, + } + + for level_name, door_name in self.spoiler.human_entry_doors.items(): + if door_name != "Vanilla": + level_enum = level_name_to_enum.get(level_name) + if level_enum is not None: + # Find the door with this name in the door_locations list + for door_data in door_locations[level_enum]: + if door_data.name == door_name: + # Update the entry handler region's exit to point to this door's logic region + placement_region = LEVEL_ENTRY_HANDLER_REGIONS[level_enum] + self.spoiler.RegionList[placement_region].exits[1] = TransitionFront(door_data.logicregion, lambda _: True) + break + + # Restore entrance randomization connections for yamlless generation + if passthrough.get("EntranceRando") and passthrough["EntranceRando"]: + # Store entrance connections for later restoration + # These will be applied in connect_entrances when we detect yamlless generation + self.saved_entrance_connections = passthrough["EntranceRando"] + + # Restore starting region for yamlless generation + if passthrough.get("StartingRegion") and passthrough["StartingRegion"]: + from randomizer.Enums.Regions import Regions + from randomizer.Enums.Maps import Maps + + starting_region_data = passthrough["StartingRegion"] + # Reconstruct the starting_region dictionary + self.spoiler.settings.starting_region = { + "region": Regions[starting_region_data["region"]], + "map": Maps[starting_region_data["map"]], + "exit": starting_region_data["exit"], + "region_name": starting_region_data["region_name"], + "exit_name": starting_region_data["exit_name"], + } + # Update GameStart region exits to point to the restored starting region + # This matches the behavior in Settings.RandomizeStartingLocation() + for x in range(2): + self.spoiler.RegionList[Regions.GameStart].exits[x + 1].dest = self.spoiler.settings.starting_region["region"] # Handle hint preparation by initiating some variables self.hint_data = { @@ -1300,6 +1468,12 @@ def exclude_locations(location_names: typing.List[str]): if excluded_locations: exclude_locations(excluded_locations) + # AFTER all regions are created, restore custom location shuffles for UT + # This must happen here (not in generate_early) to override default placements + if hasattr(self.multiworld, "generation_is_fake") and hasattr(self.multiworld, "re_gen_passthrough"): + if "Donkey Kong 64" in self.multiworld.re_gen_passthrough: + self._restore_shuffled_custom_locations() + def create_items(self) -> None: """Create the items.""" itempool: typing.List[DK64Item] = setup_items(self) @@ -1841,8 +2015,76 @@ def get_smaller_shops_data(self) -> dict: return smaller_shops_data + def get_custom_location_names(self) -> dict: + """Get the mapping of location IDs to custom location data. + + Returns a dictionary mapping location ID to a dict containing: + - 'name': the actual custom name assigned during shuffle + - 'flag': the flag ID used for checking completion in-game + Only includes locations whose names differ from the base location name. + """ + from randomizer.Enums.Locations import Locations as DK64RLocations + from randomizer.Lists.Location import LocationListOriginal as VanillaLocationList + from archipelago.Regions import BASE_ID + + custom_locations = {} + + # Get all custom location IDs + # Battle Arenas are not in a contiguous range, so list them explicitly + battle_arena_locations = [ + DK64RLocations.IslesBattleArena1, + DK64RLocations.IslesBattleArena2, + DK64RLocations.JapesBattleArena, + DK64RLocations.AztecBattleArena, + DK64RLocations.FactoryBattleArena, + DK64RLocations.GalleonBattleArena, + DK64RLocations.ForestBattleArena, + DK64RLocations.CavesBattleArena, + DK64RLocations.CastleBattleArena, + DK64RLocations.HelmBattleArena, + ] + dirt_range = range(DK64RLocations.RainbowCoin_Location00, DK64RLocations.RainbowCoin_Location15 + 1) + crate_range = range(DK64RLocations.MelonCrate_Location00, DK64RLocations.MelonCrate_Location12 + 1) + + custom_location_ids = set(battle_arena_locations) | set(dirt_range) | set(crate_range) + + # Build a mapping from enum to index in LocationListOriginal + enum_to_index = {location: index for index, location in enumerate(VanillaLocationList)} + + for location_enum in custom_location_ids: + if location_enum in self.spoiler.LocationList: + location_obj = self.spoiler.LocationList[location_enum] + + # Include all custom locations, even if names haven't changed + # This is necessary because flags can be shuffled even if names stay the same + if location_obj.name: + # Calculate the AP location ID using the INDEX, not the enum value + index = enum_to_index.get(location_enum) + if index is None: + continue + location_id = BASE_ID + index + # Get the flag ID from the location's default_mapid_data + flag_id = None + if location_obj.default_mapid_data and len(location_obj.default_mapid_data) > 0: + flag_id = location_obj.default_mapid_data[0].flag + custom_locations[location_id] = {"name": location_obj.name, "flag": flag_id} + + return custom_locations + def fill_slot_data(self) -> dict: """Fill the slot data.""" + # Debug: Check if shuffle attributes exist + print(f"[DK64 fill_slot_data START] Checking spoiler attributes:") + print(f" has crown_locations: {hasattr(self.spoiler, 'crown_locations')}") + print(f" has dirt_patch_placement: {hasattr(self.spoiler, 'dirt_patch_placement')}") + print(f" has meloncrate_placement: {hasattr(self.spoiler, 'meloncrate_placement')}") + if hasattr(self.spoiler, "crown_locations"): + print(f" crown_locations length: {len(self.spoiler.crown_locations) if self.spoiler.crown_locations else 0}") + if hasattr(self.spoiler, "dirt_patch_placement"): + print(f" dirt_patch_placement length: {len(self.spoiler.dirt_patch_placement) if self.spoiler.dirt_patch_placement else 0}") + if hasattr(self.spoiler, "meloncrate_placement"): + print(f" meloncrate_placement length: {len(self.spoiler.meloncrate_placement) if self.spoiler.meloncrate_placement else 0}") + # If hints are enabled, wait for hint compilation to complete if hasattr(self, "options") and self.options.hint_style > 0: self.hint_compilation_complete.wait() @@ -1979,7 +2221,19 @@ def fill_slot_data(self) -> dict: else {} ), "DKPortalLocations": (self.spoiler.human_entry_doors if hasattr(self.spoiler, "human_entry_doors") and self.spoiler.human_entry_doors else {}), + "CustomLocationNames": self.get_custom_location_names(), } + + # Debug logging for custom locations + custom_locs = slot_data.get("CustomLocationNames", {}) + if custom_locs: + print(f"[DK64 Generation] Sending {len(custom_locs)} custom locations in slot_data") + for i, (loc_id, data) in enumerate(list(custom_locs.items())[:5]): + if isinstance(data, dict): + print(f" Location {loc_id}: {data.get('name')} (flag: {data.get('flag')})") + else: + print(f" Location {loc_id}: {data}") + return slot_data def write_spoiler(self, spoiler_handle: typing.TextIO): @@ -2256,8 +2510,6 @@ def interpret_slot_data(self, slot_data: dict[str, any]) -> dict[str, any]: """Parse slot data for any logical bits that need to match the real generation. Used by Universal Tracker.""" # Parse the string data version = slot_data["Version"] - if version != self.ap_version: - print(f"Version mismatch: {version} != {self.ap_version}. You may experience unexpected behavior.") level_order = slot_data["LevelOrder"].split(", ") starting_kongs = slot_data["StartingKongs"].split(", ") @@ -2346,6 +2598,14 @@ def interpret_slot_data(self, slot_data: dict[str, any]) -> dict[str, any]: starting_region = slot_data.get("StartingRegion", {}) dk_portal_locations = slot_data.get("DKPortalLocations", {}) + # Custom location names for UT regeneration + custom_location_names = slot_data.get("CustomLocationNames", {}) + + # Custom location shuffle data for UT regeneration + crown_shuffle_data = slot_data.get("CrownShuffleData", None) + patch_shuffle_data = slot_data.get("PatchShuffleData", None) + crate_shuffle_data = slot_data.get("CrateShuffleData", None) + relevant_data = {} relevant_data["LevelOrder"] = dict(enumerate([Levels[level] for level in level_order], start=1)) relevant_data["StartingKongs"] = [Kongs[kong] for kong in starting_kongs] @@ -2398,4 +2658,11 @@ def interpret_slot_data(self, slot_data: dict[str, any]) -> dict[str, any]: relevant_data["KongModels"] = kong_models relevant_data["StartingRegion"] = starting_region relevant_data["DKPortalLocations"] = dk_portal_locations + relevant_data["CustomLocationNames"] = custom_location_names + if crown_shuffle_data is not None: + relevant_data["CrownShuffleData"] = crown_shuffle_data + if patch_shuffle_data is not None: + relevant_data["PatchShuffleData"] = patch_shuffle_data + if crate_shuffle_data is not None: + relevant_data["CrateShuffleData"] = crate_shuffle_data return relevant_data diff --git a/archipelago/DK64Client.py b/archipelago/DK64Client.py index 211102d04..1ae59ab3d 100644 --- a/archipelago/DK64Client.py +++ b/archipelago/DK64Client.py @@ -178,6 +178,9 @@ class DK64Client: item_names = None players = None _purchase_cache = {} + custom_check_id_to_name = {} + custom_check_id_to_flag = {} + custom_flag_to_check_id = {} # Reverse mapping: flag_id -> location_id ENABLE_DEATHLINK = False ENABLE_RINGLINK = False ENABLE_TAGLINK = False @@ -696,14 +699,25 @@ def getCheckStatus(self, check_type, flag_index=None, shop_index=None, level_ind async def readChecks(self, cb): """Run checks in parallel using asyncio.""" new_checks = [] - checks_to_read = self.remaining_checks + checks_to_read = self.remaining_checks.copy() for id in checks_to_read: - name = check_id_to_name.get(id) - # Try to get the check via location_name_to_flag - check = location_name_to_flag.get(name) + # Get location name (prefer custom name if available) + name = self.custom_check_id_to_name.get(id, check_id_to_name.get(id)) + + # Determine which flag to check for this location + check = None + + # For custom locations (crowns, dirt, crates), ONLY use the custom flag + # Do not fall back to location_name_to_flag as that would use vanilla flags + if id in self.custom_check_id_to_flag: + check = self.custom_check_id_to_flag.get(id) + else: + # For non-custom locations, use the vanilla flag mapping + check = location_name_to_flag.get(name) + if check: - # Assuming we did find it in location_name_to_flag + # Check if this flag is set in memory check_status = self.getCheckStatus("location", check) if check_status: self.remaining_checks.remove(id) @@ -1076,7 +1090,8 @@ def reset_checks(self): # Debug logging for shared shops shared_shop_ids = set() for location_id in actual_checks: - location_name = check_id_to_name.get(location_id, "") + # Use custom name if available, otherwise fall back to check_id_to_name + location_name = self.custom_check_id_to_name.get(location_id, check_id_to_name.get(location_id, "")) if "Shared" in location_name: shared_shop_ids.add(location_id) else: @@ -1086,6 +1101,7 @@ def reset_checks(self): self.client.pending_checks = [] self.found_checks = [] self.client.flag_lookup = None + self.custom_flag_to_check_id = {} self.handled_scouts = [] self.create_hints_params = [] @@ -1094,6 +1110,8 @@ def __init__(self, server_address: typing.Optional[str], password: typing.Option self.client = DK64Client() self.client.game = self.game.upper() self.slot_data = {} + self.custom_check_id_to_name = {} + self.custom_check_id_to_flag = {} self.reset_checks() super().__init__(server_address, password) @@ -1137,6 +1155,46 @@ async def send_checks(self): had_invalid_slot_data: typing.Optional[bool] = None + def update_custom_location_names(self): + """Update the check_id_to_name dictionary with custom location names from slot_data.""" + custom_location_data = self.slot_data.get("CustomLocationNames", {}) + if custom_location_data: + # Convert string keys back to integers and extract both name and flag + self.custom_check_id_to_name = {} + self.custom_check_id_to_flag = {} + for id_str, data in custom_location_data.items(): + loc_id = int(id_str) + if isinstance(data, dict): + self.custom_check_id_to_name[loc_id] = data.get("name") + if data.get("flag") is not None: + flag_id = data.get("flag") + self.custom_check_id_to_flag[loc_id] = flag_id + else: + # Backwards compatibility: if data is just a string (old format) + self.custom_check_id_to_name[loc_id] = data + + # Also update the client's dictionaries + self.client.custom_check_id_to_name = self.custom_check_id_to_name + self.client.custom_check_id_to_flag = self.custom_check_id_to_flag + + # Update the location_names lookup used by Archipelago's notification system + # We need to inject custom names so they take priority over base names + if hasattr(self, "location_names") and self.location_names: + try: + # Get the game's location store ChainMap + if self.game in self.location_names._game_store: + game_store = self.location_names._game_store[self.game] + + # Create our custom names dict + custom_names_dict = {loc_id: name for loc_id, name in self.custom_check_id_to_name.items() if name} + + # Use new_child() to prepend our custom names to the existing ChainMap + # This modifies the ChainMap in place and ensures any existing references see the update + updated_chain = game_store.new_child(custom_names_dict) + self.location_names._game_store[self.game] = updated_chain + except Exception as e: + logger.error(f"Failed to update location_names: {e}", exc_info=True) + def event_invalid_slot(self): """Handle an invalid slot event.""" # The next time we try to connect, reset the game loop for new auth @@ -1187,6 +1245,7 @@ def on_package(self, cmd: str, args: dict): if cmd == "Connected": self.game = self.slot_info[self.slot].game self.slot_data = args.get("slot_data", {}) + self.update_custom_location_names() self.setup_hint_locations() if self.slot_data.get("Version"): ap_version = get_ap_version() @@ -1248,7 +1307,8 @@ def on_package(self, cmd: str, args: dict): # If the location is in the list, remove it player_name = self.player_names.get(location.player) location_id = location.location - item_name = self.item_names.lookup_in_game(location.item, self.slot_info[location.player].game) + # Always use DK64's game context to get the correct item name for items in DK64 locations + item_name = self.item_names.lookup_in_game(location.item, self.game) self.client.locations_scouted[location_id] = {"player": player_name, "item_name": item_name} if isinstance(args, dict) and isinstance(args.get("data", {}), dict): source_name = args.get("data", {}).get("source", None) @@ -1663,7 +1723,8 @@ def on_item_get(dk64_checks): """Handle an item get.""" built_checks_list = [] for check in dk64_checks: - check_name = check_id_to_name.get(check) + # Use custom name if available, otherwise fall back to check_id_to_name + check_name = self.custom_check_id_to_name.get(check, check_id_to_name.get(check)) if check_name: built_checks_list.append(check) continue diff --git a/archipelago/FillSettings.py b/archipelago/FillSettings.py index b92269fe4..a94633670 100644 --- a/archipelago/FillSettings.py +++ b/archipelago/FillSettings.py @@ -99,7 +99,6 @@ def get_default_settings() -> dict: "boss_location_rando": True, "cannons_require_blast": True, "cb_medal_behavior_new": CBRequirement.pre_selected, - "cb_rando_enabled": False, "chunky_phase_slam_req": SlamRequirement.green, "coin_door_item": HelmDoorItem.opened, "coin_door_item_count": 1, @@ -107,7 +106,6 @@ def get_default_settings() -> dict: "crown_door_item": HelmDoorItem.opened, "crown_door_item_count": 1, "crown_enemy_difficulty": CrownEnemyDifficulty.easy, - "crown_placement_rando": False, "damage_amount": DamageAmount.default, "decouple_item_rando": False, "dim_solved_hints": False, @@ -268,9 +266,7 @@ def get_default_settings() -> dict: "progressive_hint_item": ProgressiveHintItem.off, "puzzle_rando_difficulty": PuzzleRando.medium, "race_coin_rando": False, - "random_crates": False, "random_fairies": False, - "random_patches": False, "random_starting_region": False, "random_starting_region_new": RandomStartingRegion.off, "randomize_enemy_sizes": False, @@ -318,6 +314,8 @@ def get_default_settings() -> dict: "wrinkly_available": True, "wrinkly_hints": WrinklyHints.standard, "wrinkly_location_rando": False, + "cb_rando_enabled": False, + "cb_rando_list_selected": [], } @@ -361,9 +359,15 @@ def apply_archipelago_settings(settings_dict: dict, options, multiworld) -> None elif options.galleon_water_level == GalleonWaterLevel.option_raised: settings_dict["galleon_water"] = GalleonWaterSetting.raised else: - settings_dict["galleon_water"] = GalleonWaterSetting.vanilla + settings_dict["galleon_water"] = GalleonWaterSetting.lowered settings_dict["no_consumable_upgrades"] = options.remove_bait_potions.value + # Custom location settings + settings_dict["crown_placement_rando"] = options.crown_placement_rando.value + settings_dict["random_crates"] = options.random_crates.value + settings_dict["random_patches"] = options.random_patches.value + # settings_dict["cb_rando_enabled"] = options.cb_rando_enabled.value + def apply_blocker_settings(settings_dict: dict, options) -> None: """Apply level blocker settings.""" @@ -904,6 +908,10 @@ def handle_fake_generation_settings(settings: Settings, multiworld) -> None: passthrough = multiworld.re_gen_passthrough["Donkey Kong 64"] settings.level_order = passthrough["LevelOrder"] + # Store custom location names for later restoration (after spoiler is created) + if passthrough.get("CustomLocationNames"): + settings.ut_custom_location_names = passthrough["CustomLocationNames"] + # Switch logic lifted out of level shuffle due to static levels for UT if settings.alter_switch_allocation: for x in range(8): @@ -963,6 +971,30 @@ def handle_fake_generation_settings(settings: Settings, multiworld) -> None: settings.shuffled_location_types.append(Types.Candy) settings.shuffled_location_types.append(Types.Snide) + # Restore starting region + if passthrough.get("StartingRegion"): + from randomizer.Enums.Regions import Regions + from randomizer.Enums.Maps import Maps as DK64Maps + + starting_region_data = passthrough["StartingRegion"] + # Ensure all fields exist and are not None + if all(key in starting_region_data and starting_region_data[key] is not None for key in ["region", "map", "exit", "region_name", "exit_name"]): + try: + settings.starting_region = { + "region": Regions[starting_region_data["region"]], + "map": DK64Maps[starting_region_data["map"]], + "exit": starting_region_data["exit"], + "region_name": starting_region_data["region_name"], + "exit_name": starting_region_data["exit_name"], + } + except (KeyError, TypeError) as e: + # If there's an error converting the data, just skip it + pass + + # Store DK Portal locations for later restoration (after spoiler is created) + if passthrough.get("DKPortalLocations"): + settings.ut_dk_portal_locations = passthrough["DKPortalLocations"] + def fillsettings(options, multiworld, random_obj): """Fill and configure all DK64 settings.""" diff --git a/archipelago/Options.py b/archipelago/Options.py index 9a1db0500..dfe0fee96 100644 --- a/archipelago/Options.py +++ b/archipelago/Options.py @@ -413,6 +413,34 @@ class SwitchSanity(Choice): default = 0 +class CrownPlacementRando(Toggle): + """Randomizes the locations of Battle Arena crown pads to alternate positions throughout the levels.""" + + display_name = "Crown Placement Randomization" + + +class RandomCrates(Toggle): + """Randomizes the locations of Melon Crates to alternate positions throughout the levels.""" + + display_name = "Random Melon Crates" + + +class RandomPatches(Toggle): + """Randomizes the locations of Dirt Patches (Rainbow Coins) to alternate positions throughout the levels.""" + + display_name = "Random Dirt Patches" + + +## TODO: Figure this out +# class CBRando(Toggle): +# """Randomizes the locations of Colored Bananas throughout the levels. + +# This does NOT make individual bananas checks - they remain collectibles that count toward medals. +# """ + +# display_name = "Colored Banana Randomization" + + class LogicType(Choice): """Determines what type of logic is needed to beat the seed. @@ -1468,6 +1496,10 @@ class DK64Options(PerGameCommonOptions): level_blockers: LevelBlockers open_lobbies: OpenLobbies switchsanity: SwitchSanity + crown_placement_rando: CrownPlacementRando + random_crates: RandomCrates + random_patches: RandomPatches + # cb_rando_enabled: CBRando climbing_shuffle: ClimbingShuffle starting_kong_count: StartingKongCount starting_move_count: StartingMoveCount @@ -1603,6 +1635,15 @@ class DK64Options(PerGameCommonOptions): DKPortalLocationRando, ], ), + OptionGroup( + "Custom Locations", + [ + CrownPlacementRando, + RandomCrates, + RandomPatches, + # CBRando, + ], + ), OptionGroup( "Logic", [ diff --git a/archipelago/Regions.py b/archipelago/Regions.py index 20cd18394..e58ab8a0e 100644 --- a/archipelago/Regions.py +++ b/archipelago/Regions.py @@ -111,6 +111,19 @@ def create_regions(multiworld: MultiWorld, player: int, spoiler: Spoiler, option # okay okay OKAY you get a logicVarHolder object for JUST THIS ONCE. Codes these days... logic_holder = LogicVarHolder(spoiler, player) + # Build location table from spoiler's LocationList (which may have custom locations) + all_locations_dynamic = { + spoiler.LocationList[location].name: (BASE_ID + index) for index, location in enumerate(DK64RLocation.LocationListOriginal) if spoiler.LocationList[location].type != Types.EnemyPhoto + } + all_locations_dynamic.update({"Victory": 0x00}) # Temp for generating goal location + + # Debug: check for custom location names + custom_names = [name for name in all_locations_dynamic.keys() if "Battle Arena" in name or "Melon Crate" in name or "Dirt:" in name] + if custom_names and len(custom_names) > 0: + print(f"[DK64 create_regions] Found {len(custom_names)} custom locations, samples:") + for name in custom_names[:5]: + print(f" {name}") + # Pick random 10 shops to make shared # Only if shared shops are enabled in settings if options.enable_shared_shops.value: @@ -126,8 +139,8 @@ def create_regions(multiworld: MultiWorld, player: int, spoiler: Spoiler, option shared_shop_vendors = set() # Pre-process to identify which vendor/level combinations will have shared shops - for region_id in all_logic_regions: - region_obj = all_logic_regions[region_id] + for region_id in logic_holder.spoiler.RegionList: + region_obj = logic_holder.spoiler.RegionList[region_id] location_logics = [loc for loc in region_obj.locations if (not loc.isAuxiliaryLocation) or region_id.name == "FactoryBaboonBlast"] for location_logic in location_logics: @@ -150,8 +163,8 @@ def create_regions(multiworld: MultiWorld, player: int, spoiler: Spoiler, option # for location_name, location_id in all_locations.items(): # print(f"{location_name}: {location_id}") - for region_id in all_logic_regions: - region_obj = all_logic_regions[region_id] + for region_id in logic_holder.spoiler.RegionList: + region_obj = logic_holder.spoiler.RegionList[region_id] # Filtering out auxiliary locations is detrimental to glitch logic, but is necessary to ensure each location placed exactly once location_logics = [loc for loc in region_obj.locations if (not loc.isAuxiliaryLocation) or region_id.name == "FactoryBaboonBlast"] # V1 LIMITATION: Helm must be skip_start @@ -171,16 +184,17 @@ def create_regions(multiworld: MultiWorld, player: int, spoiler: Spoiler, option if (region_id == Regions.HideoutHelmEntry and spoiler.settings.helm_chunky) or (region_id == Regions.HideoutHelmChunkyRoom and not spoiler.settings.helm_chunky): location_logics = [loc for loc in location_logics if loc.id not in (Locations.HelmChunky1, Locations.HelmChunky2)] collectibles = [] - if region_id in all_collectible_regions.keys(): + # Use spoiler.CollectibleRegions which reflects CB randomization if enabled + if region_id in logic_holder.spoiler.CollectibleRegions.keys(): collectible_types = [Collectibles.bunch, Collectibles.banana, Collectibles.balloon] collectible_types.append(Collectibles.coin) - collectibles = [col for col in all_collectible_regions[region_id] if col.type in collectible_types] + collectibles = [col for col in logic_holder.spoiler.CollectibleRegions[region_id] if col.type in collectible_types] events = [event for event in region_obj.events] # if region_obj.level == Levels.Shops: - # multiworld.regions.append(create_shop_region(multiworld, player, region_id.name, region_obj, location_logics, spoiler.settings)) + # multiworld.regions.append(create_shop_region(multiworld, player, region_id.name, region_obj, location_logics, spoiler.settings, all_locations_dynamic)) # else: - multiworld.regions.append(create_region(multiworld, player, region_id.name, region_obj.level, location_logics, collectibles, events, logic_holder)) + multiworld.regions.append(create_region(multiworld, player, region_id.name, region_obj.level, location_logics, collectibles, events, logic_holder, all_locations_dynamic)) def create_region( @@ -192,6 +206,7 @@ def create_region( collectibles: typing.List[Collectible], events: typing.List[Event], logic_holder: LogicVarHolder, + all_locations_dynamic: typing.Dict[str, int], ) -> Region: """Create a region for the given player's world.""" new_region = Region(region_name, player, multiworld) @@ -220,6 +235,9 @@ def create_region( # Dropsanity would otherwise flood the world with irrelevant locked locations, greatly slowing seed gen if location_obj.type == Types.Enemies and Types.Enemies not in logic_holder.settings.shuffled_location_types: continue + # Skip boulder/holdable items if not shuffled + if location_obj.type == Types.BoulderItem and Types.BoulderItem not in logic_holder.settings.shuffled_location_types: + continue # Skip shared shops that are not in the available pool if location_obj.type == Types.Shop and location_obj.kong == Kongs.any: if location_logic.id not in logic_holder.available_shared_shops: @@ -239,7 +257,7 @@ def create_region( # Skip locations marked as inaccessible by smaller shops if hasattr(location_obj, "smallerShopsInaccessible") and location_obj.smallerShopsInaccessible and logic_holder.settings.smaller_shops: continue - loc_id = all_locations.get(location_obj.name, 0) + loc_id = all_locations_dynamic.get(location_obj.name, 0) # Universal Tracker: don't add this location if it has no item if hasattr(multiworld, "generation_is_fake"): if hasattr(multiworld, "re_gen_passthrough"): @@ -503,7 +521,9 @@ def create_region( # CURRENTLY UNUSED - for some reason some Lanky shops are inaccessible?? -def create_shop_region(multiworld: MultiWorld, player: int, region_name: str, region_obj: DK64Region, location_logics: typing.List[LocationLogic], settings: Settings) -> Region: +def create_shop_region( + multiworld: MultiWorld, player: int, region_name: str, region_obj: DK64Region, location_logics: typing.List[LocationLogic], settings: Settings, all_locations_dynamic: typing.Dict[str, int] +) -> Region: """Create a region for the given player's world.""" # Shop regions have relatively straightforward logic that can be streamlined for performance purposes new_region = Region(region_name, player, multiworld) @@ -513,14 +533,14 @@ def create_shop_region(multiworld: MultiWorld, player: int, region_name: str, re for kong in range(5): blueprint_obj = DK64RItem.ItemList[Items.DonkeyBlueprint + kong] location_name = "Turn In " + blueprint_obj.name - loc_id = all_locations.get(location_name, 0) + loc_id = all_locations_dynamic.get(location_name, 0) location = DK64Location(player, location_name, loc_id, new_region) set_rule(location, lambda state, blueprint_name=blueprint_obj.name: state.has(blueprint_name, player)) location.place_locked_item(DK64Item(blueprint_obj.name, ItemClassification.progression_skip_balancing, None, player)) new_region.locations.append(location) # The one special child here is Cranky Generic, home of Jetpac, the only shop location with any relevant logic elif region_name == "Cranky Generic": - location = DK64Location(player, "Jetpac", all_locations.get("Jetpac", 0), new_region) + location = DK64Location(player, "Jetpac", all_locations_dynamic.get("Jetpac", 0), new_region) set_rule(location, lambda state, player=player, location_logic=location_logics[0]: hasDK64RLocation(state, player, location_logic)) new_region.locations.append(location) settings.location_pool_size += 1 @@ -530,7 +550,7 @@ def create_shop_region(multiworld: MultiWorld, player: int, region_name: str, re location_obj = DK64RLocation.LocationListOriginal[location_logic.id] if location_obj.kong == Kongs.any: continue # We need to eliminate shared shop locations so shops don't have both a shared item and Kong items - loc_id = all_locations.get(location_obj.name, 0) + loc_id = all_locations_dynamic.get(location_obj.name, 0) location = DK64Location(player, location_obj.name, loc_id, new_region) required_kong_name = location_obj.kong.name.title() set_rule(location, lambda state, required_kong_name=required_kong_name: state.has(required_kong_name, player)) @@ -710,64 +730,68 @@ def connect_regions(world: World, settings: Settings, spoiler: Spoiler = None): # Random Starting Region: Create "exit level" connection from spawn point # When spawning in a level, you can use the "Exit Level" menu option to return to the lobby. # This connection uses the actual exit transition logic (not free) to respect entrance rando. - if spoiler and settings.starting_region: + if spoiler and hasattr(settings, "starting_region") and settings.starting_region: starting_region_id = settings.starting_region.get("region") - starting_region_obj = all_logic_regions.get(starting_region_id) - - if starting_region_obj: - starting_level = starting_region_obj.level - - # Map each level to its exit transition - level_exit_transitions = { - Levels.JungleJapes: Transitions.JapesToIsles, - Levels.AngryAztec: Transitions.AztecToIsles, - Levels.FranticFactory: Transitions.FactoryToIsles, - Levels.GloomyGalleon: Transitions.GalleonToIsles, - Levels.FungiForest: Transitions.ForestToIsles, - Levels.CrystalCaves: Transitions.CavesToIsles, - Levels.CreepyCastle: Transitions.CastleToIsles, - } - - # Only create exit level connection for non-Isles levels - if starting_level in level_exit_transitions: - exit_transition_id = level_exit_transitions[starting_level] - starting_region_name = starting_region_id.name if hasattr(starting_region_id, "name") else str(starting_region_id) - - # Find the exit transition in the level's entry handler region - # Entry handlers have the "exit level" transition defined in their exits - level_to_entry_handler = { - Levels.JungleJapes: Regions.JungleJapesEntryHandler, - Levels.AngryAztec: Regions.AngryAztecEntryHandler, - Levels.FranticFactory: Regions.FranticFactoryEntryHandler, - Levels.GloomyGalleon: Regions.GloomyGalleonEntryHandler, - Levels.FungiForest: Regions.FungiForestEntryHandler, - Levels.CrystalCaves: Regions.CrystalCavesEntryHandler, - Levels.CreepyCastle: Regions.CreepyCastleEntryHandler, + if starting_region_id is None: + # starting_region dict exists but is empty or missing region key + pass + else: + starting_region_obj = all_logic_regions.get(starting_region_id) + + if starting_region_obj: + starting_level = starting_region_obj.level + + # Map each level to its exit transition + level_exit_transitions = { + Levels.JungleJapes: Transitions.JapesToIsles, + Levels.AngryAztec: Transitions.AztecToIsles, + Levels.FranticFactory: Transitions.FactoryToIsles, + Levels.GloomyGalleon: Transitions.GalleonToIsles, + Levels.FungiForest: Transitions.ForestToIsles, + Levels.CrystalCaves: Transitions.CavesToIsles, + Levels.CreepyCastle: Transitions.CastleToIsles, } - if starting_level in level_to_entry_handler: - entry_handler_region = level_to_entry_handler[starting_level] - entry_handler_obj = all_logic_regions.get(entry_handler_region) - - if entry_handler_obj: - # Find the exit transition in the entry handler's exits - exit_transition = None - for exit in entry_handler_obj.exits: - if exit.exitShuffleId == exit_transition_id: - exit_transition = exit - break - - # Create connection using the exit transition's logic - if exit_transition: - target_region_name = exit_transition.dest.name - # Use the actual transition logic (respects entrance rando and logic requirements) - connect( - world, - starting_region_name, - target_region_name, - lambda state, player=world.player, exit=exit_transition: hasDK64RTransition(state, player, exit), - "Exit Level from spawn: " + starting_region_name, - ) + # Only create exit level connection for non-Isles levels + if starting_level in level_exit_transitions: + exit_transition_id = level_exit_transitions[starting_level] + starting_region_name = starting_region_id.name if hasattr(starting_region_id, "name") else str(starting_region_id) + + # Find the exit transition in the level's entry handler region + # Entry handlers have the "exit level" transition defined in their exits + level_to_entry_handler = { + Levels.JungleJapes: Regions.JungleJapesEntryHandler, + Levels.AngryAztec: Regions.AngryAztecEntryHandler, + Levels.FranticFactory: Regions.FranticFactoryEntryHandler, + Levels.GloomyGalleon: Regions.GloomyGalleonEntryHandler, + Levels.FungiForest: Regions.FungiForestEntryHandler, + Levels.CrystalCaves: Regions.CrystalCavesEntryHandler, + Levels.CreepyCastle: Regions.CreepyCastleEntryHandler, + } + + if starting_level in level_to_entry_handler: + entry_handler_region = level_to_entry_handler[starting_level] + entry_handler_obj = all_logic_regions.get(entry_handler_region) + + if entry_handler_obj: + # Find the exit transition in the entry handler's exits + exit_transition = None + for exit in entry_handler_obj.exits: + if exit.exitShuffleId == exit_transition_id: + exit_transition = exit + break + + # Create connection using the exit transition's logic + if exit_transition: + target_region_name = exit_transition.dest.name + # Use the actual transition logic (respects entrance rando and logic requirements) + connect( + world, + starting_region_name, + target_region_name, + lambda state, player=world.player, exit=exit_transition: hasDK64RTransition(state, player, exit), + "Exit Level from spawn: " + starting_region_name, + ) # For tracker regeneration with LZR, also handle deathwarps and exit level connections if pairings: diff --git a/archipelago/Tracker.py b/archipelago/Tracker.py new file mode 100644 index 000000000..faf56b25c --- /dev/null +++ b/archipelago/Tracker.py @@ -0,0 +1,1052 @@ +"""Universal Tracker integration for DK64.""" + +from typing import Any + + +def dk64_map_to_tab_index(data: Any) -> int: + """Map DK64 game map ID to flat sub-area index for UT navigation. + + Returns the flat index across ALL sub-areas in map_page_groups. + """ + # Handle empty or None data + if data is None or data == "" or data == b"": + return 0 + + # Convert to int if needed + try: + if isinstance(data, str): + data = data.strip() + if not data: + return 0 + map_id = int(data) if not isinstance(data, int) else data + except (ValueError, TypeError): + return 0 + + map_to_flat_index = { + # DK Isles (indices 0-10) + 34: 0, + 189: 0, + 97: 0, # isles + 176: 1, + 171: 1, # training + 169: 2, # japeslobby + 173: 3, # azteclobby + 175: 4, # factorylobby + 174: 5, # galleonlobby + 178: 6, # forestlobby + 194: 7, # caveslobby + 193: 8, # castlelobby + 170: 9, # helmlobby + 195: 10, # snidelobby + 203: 0, + 204: 0, + 205: 0, + 206: 0, + 207: 0, + 214: 0, # K. Rool phases -> isles + 15: 10, # Snide's -> snidelobby + # Jungle Japes (indices 11-14) + 7: 11, + 12: 11, + 13: 11, + 37: 11, # japes main area (beehive, painting room, blast) + 33: 12, # japesunder + 4: 13, + 6: 13, # japesmountain (includes minecarts) + # shellhive (14) - no specific map ID, part of main japes + # Angry Aztec (indices 15-22) + 38: 15, + 14: 15, + 41: 15, # aztec main area + 16: 16, # tinytemple + 20: 17, # llamatemple + 19: 18, # dk5dt + 21: 19, # diddy5dt + 23: 20, # lanky5dt + 22: 21, # tiny5dt + 24: 22, # chunky5dt + # Frantic Factory (index 23) + 26: 23, + 27: 23, + 29: 23, + 36: 23, + 110: 23, # factory + # Gloomy Galleon (index 24) + 30: 24, + 49: 24, + 45: 24, + 31: 24, + 39: 24, + 44: 24, + 179: 24, # galleon + 51: 24, + 46: 24, + 43: 24, + 47: 24, + 54: 24, + # Fungi Forest (indices 25-28) + 48: 25, + 55: 25, + 64: 25, + 71: 25, + 70: 25, + 63: 25, + 52: 25, # forest main + 56: 25, + 57: 25, + 58: 25, + 188: 25, + 61: 26, # frontmill + 62: 27, + 60: 27, # rearmill + 59: 28, # barn + # Crystal Caves (index 29) + 72: 29, + 82: 29, + 98: 29, + 86: 29, + 100: 29, + 85: 29, + 84: 29, # caves + 95: 29, + 89: 29, + 91: 29, + 92: 29, + 200: 29, + 94: 29, + 93: 29, + 90: 29, + 186: 29, + # Creepy Castle (indices 30-36) + 87: 30, + 164: 30, + 114: 30, + 105: 30, + 168: 30, + 167: 30, + 166: 30, + 187: 30, # castle exterior + 151: 31, # dungeontunnel + 163: 32, # dungeon + 183: 33, + 108: 33, # crypthub + 112: 34, + 106: 34, # crypt + 88: 35, # ballroom + 113: 36, + 185: 36, # museum + # Hideout Helm (index 37) + 17: 37, # helm + } + + flat_index = map_to_flat_index.get(map_id, 0) + return flat_index + + +# PopTracker section name to Archipelago location ID mapping +# Format: "Parent/Section Name": location_id +# Auto-generated from location_mapping.lua (837 locations total) +poptracker_name_mapping = { + "Japes Lobby Entrance/Isles Japes Lobby Entrance Item": 14041140, + "Tiny Feather Cage/Isles Tiny Feather Cage": 14041141, + "Upper Krem Isles/Isles Tiny Saxophone Pad": 14041142, + "Isles Lanky Grape Cage/Isles Lanky Grape Cage": 14041143, + "Chunky Pineapple Cage/Isles Chunky Pineapple Cage": 14041144, + "Isles Chunky Triangle Pad/Isles Chunky Triangle Pad": 14041145, + "Chunky Pound the X/Isles Chunky Pound the X": 14041146, + "Isles Fairy (Small Island)/Isles Fairy (Small Island)": 14041147, + "Upper Krem Isles/Isles Fairy (Upper Krem Isles)": 14041148, + "K. Lumsy Prison/Isles Lanky Sprint Cage": 14041149, + "Banana Fairy Island/The Banana Fairy's Gift": 14041150, + "Banana Fairy Island/Returning the Banana Fairies": 14041151, + "Isles Lanky Instrument Pad/Isles Lanky Japes Instrument": 14041152, + "Isles Tiny Aztec Lobby Barrel/Isles Tiny Aztec Lobby Barrel": 14041153, + "Isles DK Coconut Cage/Isles Donkey Coconut Cage": 14041154, + "Isles Diddy Snide Barrel/Isles Diddy Snides Spring Barrel": 14041155, + "Isles Battle Arena 1/Isles Battle Arena 1 (Snide's Room: Under Rock)": 14041156, + "Isles DK Bongo Pad/Isles Donkey Bongos Pad": 14041157, + "Isles Factory Lobby Box/Isles Kasplat: Factory Lobby Box": 14041158, + "Isles Factory Lobby Box/Isles Fairy (Factory Lobby)": 14041159, + "Isles Tiny Galleon Lobby Swim/Isles Tiny Galleon Lobby Swim": 14041160, + "Isles Kasplat: Galleon Lobby/Isles Kasplat: Galleon Lobby": 14041161, + "Isles Diddy Peanut Cage/Isles Diddy Peanut Cage": 14041162, + "Isles Diddy Summit Barrel/Isles Diddy Summit Barrel": 14041163, + "Isles Battle Arena 2 (Fungi Lobby)/Isles Battle Arena 2 (Fungi Lobby: Gorilla Gone Box)": 14041164, + "Isles Fairy (Fungi Lobby)/Isles Fairy (Forest Lobby)": 14041165, + "Isles DK Caves Lava/Isles Donkey Caves Lava": 14041166, + "Isles Diddy Guitar Pad/Isles Diddy Guitar Pad": 14041167, + "Isles Kasplat: Caves Lobby Punch/Isles Kasplat: Caves Lobby Punch": 14041168, + "Upper Castle Lobby/Isles Lanky Castle Lobby Barrel": 14041169, + "Isles Kasplat: Castle Lobby/Isles Kasplat: Castle Lobby": 14041170, + "Isles Chunky Helm Lobby Barrel/Isles Chunky Helm Lobby Barrel": 14041171, + "Isles Kasplat: Helm Lobby/Isles Kasplat: Helm Lobby": 14041172, + "Medals/Japes Donkey Medal": 14041174, + "Medals/Japes Diddy Medal": 14041175, + "Medals/Japes Lanky Medal": 14041176, + "Medals/Japes Tiny Medal": 14041177, + "Medals/Japes Chunky Medal": 14041178, + "Diddy Cage/Japes Cage: Diddy Kong": 14041179, + "Diddy Cage/Japes in Front of Diddy Cage": 14041180, + "Diddy Cage/Japes Free Diddy Item": 14041181, + "Japes DK Floor Cage Banana/Japes Donkey Floor Cage Banana": 14041182, + "Japes DK Baboon Blast/Japes Donkey Baboon Blast": 14041183, + "Japes Diddy Timed Cage Banana/Japes Diddy Timed Cage Banana": 14041184, + "Japes Diddy Top of Mountain/Japes Diddy Top of Mountain": 14041185, + "Japes Lanky Timed Cage Banana/Japes Lanky Timed Cage Banana": 14041186, + "Japes Tiny Timed Cage Banana/Japes Tiny Timed Cage Banana": 14041187, + "Japes Chunky Boulder/Japes Chunky Boulder": 14041188, + "Japes Chunky Timed Cage Banana/Japes Chunky Timed Cage Banana": 14041189, + "Japes Battle Arena (Near Funky)/Japes Battle Arena (Near Funky)": 14041190, + "Japes Diddy Peanut Tunnel/Japes Diddy Peanut Tunnel": 14041191, + "Japes Lanky Grape Gate Barrel/Japes Lanky Grape Gate Barrel": 14041192, + "Japes Tiny Feather Gate Barrel/Japes Tiny Feather Gate Barrel": 14041193, + "Japes Kasplat: Hive Tunnel Lower/Japes Kasplat: Hive Tunnel Lower": 14041194, + "Japes Kasplat: Hive Tunnel Upper/Japes Kasplat: Hive Tunnel Upper": 14041195, + "Japes Tiny Stump/Japes Tiny Stump": 14041196, + "Japes Chunky Giant Bonus Barrel/Japes Chunky Giant Bonus Barrel": 14041197, + "Japes Tiny Beehive/Japes Tiny Beehive": 14041198, + "Japes Lanky Slope Barrel/Japes Lanky Slope Barrel": 14041199, + "Japes Kasplat: Near Painting Room/Japes Kasplat: Near Painting Room": 14041200, + "Japes Kasplat: By Lanky Slope Bonus/Japes Kasplat: By Lanky Slope Bonus": 14041201, + "Japes Fairy (Rambi Door Pool)/Japes Fairy (Rambi Door Pool)": 14041202, + "Painting Room/Japes Lanky Painting Room Zingers": 14041203, + "Painting Room/Japes Fairy (Painting Room)": 14041204, + "Japes Diddy Minecart/Japes Diddy Minecart": 14041205, + "Japes Chunky Underground/Japes Chunky Underground": 14041206, + "Japes Kasplat: Underground/Japes Kasplat: Underground": 14041207, + "Medals/Japes Boss Defeated": 14041208, + "Medals/Aztec Donkey Medal": 14041209, + "Medals/Aztec Diddy Medal": 14041210, + "Medals/Aztec Lanky Medal": 14041211, + "Medals/Aztec Tiny Medal": 14041212, + "Medals/Aztec Chunky Medal": 14041213, + "Aztec DK Free Llama Blast/Aztec Donkey Free Llama Blast": 14041214, + "Aztec Chunky Vases/Aztec Chunky Vases": 14041215, + "Aztec Kasplat: Behind DK Stone Door/Aztec Kasplat: Behind DK Stone Door": 14041216, + "Aztec Kasplat: On Tiny Temple/Aztec Kasplat: On Tiny Temple": 14041217, + "Aztec Tiny Klaptrap Room/Aztec Tiny Klaptrap Room": 14041218, + "Aztec Chunky Klaptrap Room/Aztec Chunky Klaptrap Room": 14041219, + "Tiny's Cage/Aztec Cage: Tiny Kong": 14041220, + "Tiny's Cage/Aztec Free Tiny Item": 14041221, + "Aztec Lanky Vulture Shooting/Aztec Lanky Vulture Shooting": 14041222, + "Aztec Battle Arena (Tiny Temple: Vulture Room)/Aztec Battle Arena (Tiny Temple: Vulture Room)": 14041223, + "Aztec DK Sealed Quicksand Tunnel Barrel/Aztec Donkey Sealed Quicksand Tunnel Barrel": 14041224, + "Aztec Diddy Ram Gongs/Aztec Diddy Ram Gongs": 14041225, + "Aztec Diddy Vulture Race/Aztec Diddy Vulture Race": 14041226, + "Aztec Chunky Giant Caged Barrel/Aztec Chunky Giant Caged Barrel": 14041227, + "Aztec Kasplat: Hunky Chunky Barrel/Aztec Kasplat: Hunky Chunky Barrel": 14041228, + "5 Door Temple/Aztec Donkey 5 Door Temple": 14041229, + "5 Door Temple/Aztec Diddy 5 Door Temple": 14041230, + "5 Door Temple/Aztec Lanky 5 Door Temple": 14041231, + "5 Door Temple/Aztec Tiny 5 Door Temple": 14041232, + "5 Door Temple/Aztec Fairy (Tiny 5-Door Temple)": 14041233, + "5 Door Temple/Aztec Chunky 5 Door Temple": 14041234, + "5 Door Temple/Aztec Kasplat: Chunky 5-Door Temple": 14041235, + "Aztec Tiny Beetle Race/Aztec Tiny Beetle Race": 14041236, + "Lanky's Cage/Aztec Cage: Lanky Kong": 14041237, + "Lanky's Cage/Aztec Free Lanky Item": 14041238, + "Aztec Lanky Llama Temple Barrel/Aztec Lanky Llama Temple Barrel": 14041239, + "Aztec Lanky Matching Game/Aztec Lanky Matching Game": 14041240, + "Aztec Fairy (Llama Temple)/Aztec Fairy (Llama Temple)": 14041241, + "Aztec Tiny Llama Temple Lava Pedestals/Aztec Tiny Llama Temple Lava Pedestals": 14041242, + "Aztec Kasplat: Llama Temple Lava/Aztec Kasplat: Llama Temple Lava": 14041243, + "Medals/Aztec Boss Defeated": 14041244, + "Medals/Factory Donkey Medal": 14041245, + "Medals/Factory Diddy Medal": 14041246, + "Medals/Factory Lanky Medal": 14041247, + "Medals/Factory Tiny Medal": 14041248, + "Medals/Factory Chunky Medal": 14041249, + "Factory DK Number Game/Factory Donkey Number Game": 14041250, + "Factory Diddy Block Tower/Factory Diddy Block Tower": 14041251, + "Factory Lanky Testing Room Barrel/Factory Lanky Testing Room Barrel": 14041252, + "Factory Tiny Dartboard/Factory Tiny Dartboard": 14041253, + "Factory Kasplat: Block Tower/Factory Kasplat: Block Tower": 14041254, + "Factory Fairy (Number Game)/Factory Fairy (Number Game)": 14041255, + "Factory Fairy (Near Funky's)/Factory Fairy (Near Funky's)": 14041256, + "Factory Diddy Charge Enemies/Factory Diddy Charge Enemies": 14041257, + "Factory Lanky Piano Game/Factory Lanky Piano Game": 14041258, + "Factory Chunky Toy Monster/Factory Chunky Toy Monster": 14041259, + "Factory Kasplat: R&D/Factory Kasplat: Research and Development": 14041260, + "Factory Battle Arena (Under Grate)/Factory Battle Arena (Under R&D Grate)": 14041261, + "Factory Tiny Car Race/Factory Tiny Car Race": 14041262, + "Factory Diddy Storage Room Barrel/Factory Diddy Storage Room Barrel": 14041263, + "Factory DK Power Hut/Factory Donkey Power Hut": 14041264, + "Chunky's Cage/Factory Cage: Chunky Kong": 14041265, + "DK Arcade/DK Arcade Round 2": 14041266, + "Factory DK Blast Course/Factory Donkey DK Arcade Round 1": 14041267, + "Chunky's Cage/Factory Free Chunky Item": 14041268, + "Factory Tiny Mini by Arcade/Factory Tiny Mini by Arcade": 14041269, + "Factory Chunky Dark Room/Factory Chunky Dark Room": 14041270, + "Factory Chunky Barrel by Arcade/Factory Chunky Barrel by Arcade": 14041271, + "Factory Kasplat: Base of Production/Factory Kasplat: Base of Production": 14041272, + "Factory Kasplat: Pole to Arcade/Factory Kasplat: Pole to Arcade": 14041273, + "Factory DK Crusher Room/Factory Donkey Crusher Room": 14041274, + "Factory Diddy Production Spring/Factory Diddy Production Spring": 14041275, + "Factory Lanky Production Handstand/Factory Lanky Production Handstand": 14041276, + "Factory Tiny Production Twirl/Factory Tiny Production Twirl": 14041277, + "Factory Chunky Production Timer/Factory Chunky Production Timer": 14041278, + "Factory Kasplat: Upper Production Pipe/Factory Kasplat: Upper Production Pipe": 14041279, + "Medals/Factory Boss Defeated": 14041280, + "Medals/Galleon Donkey Medal": 14041281, + "Medals/Galleon Diddy Medal": 14041282, + "Medals/Galleon Lanky Medal": 14041283, + "Medals/Galleon Tiny Medal": 14041284, + "Medals/Galleon Chunky Medal": 14041285, + "Galleon Chunky Chest/Galleon Chunky Chest": 14041286, + "Galleon Kasplat: Past Vines/Galleon Kasplat: Past Vines": 14041287, + "Galleon Battle Arena (Under Cranky)/Galleon Battle Arena (Under Cranky)": 14041288, + "Galleon Fairy (In Punch Chest)/Galleon Fairy (In Punch Chest)": 14041289, + "Galleon Chunky Cannon Game/Galleon Chunky Cannon Game": 14041290, + "Galleon Kasplat: Cannon Game Room/Galleon Kasplat: Cannon Game Room": 14041291, + "Galleon Diddy Top of Lighthouse/Galleon Diddy Top of Lighthouse": 14041292, + "Galleon Lanky Enguarde Chest/Galleon Lanky Enguarde Chest": 14041293, + "Galleon Kasplat: Lighthouse Alcove/Galleon Kasplat: Lighthouse Alcove": 14041294, + "Lighthouse/Galleon Donkey Lighthouse": 14041295, + "Galleon Tiny Mermaid Reward/Galleon Tiny Mermaid Reward": 14041296, + "Galleon Chunky Seasick/Galleon Chunky Seasick": 14041297, + "Galleon Seal/Galleon Donkey Free the Seal": 14041298, + "Galleon Kasplat: Musical Cactus/Galleon Kasplat: Musical Cactus": 14041299, + "Galleon Seal/Galleon Donkey Seal Race": 14041300, + "Galleon Diddy Gold Tower Barrel/Galleon Diddy Gold Tower Barrel": 14041301, + "Galleon Lanky Gold Tower Barrel/Galleon Lanky Gold Tower Barrel": 14041302, + "Galleon Kasplat: Diddy Gold Tower/Galleon Kasplat: Diddy Gold Tower": 14041303, + "Galleon Tiny Submarine Barrel/Galleon Tiny Submarine Barrel": 14041304, + "Galleon Diddy Mechfish/Galleon Diddy Mechfish": 14041305, + "2-Door Ship/Galleon Lanky 2 Door Ship": 14041306, + "2-Door Ship/Galleon Tiny 2 Door Ship": 14041307, + "Galleon DK 5-Door Ship/Galleon Donkey 5 Door Ship": 14041308, + "Galleon Diddy 5-Door Ship/Galleon Diddy 5 Door Ship": 14041309, + "Galleon Lanky 5-Door Ship/Galleon Lanky 5 Door Ship": 14041310, + "Galleon Tiny 5-Door Ship/Galleon Tiny 5 Door Ship": 14041311, + "Galleon Tiny 5-Door Ship/Galleon Fairy (In Tiny's 5-Door Ship)": 14041312, + "Galleon Chunky 5-Door Ship/Galleon Chunky 5 Door Ship": 14041313, + "Treasure Chest/Treasure Chest Far Left Clam": 14041314, + "Treasure Chest/Treasure Chest Center Clam": 14041315, + "Treasure Chest/Treasure Chest Far Right Clam": 14041316, + "Treasure Chest/Treasure Chest Close Right Clam": 14041317, + "Treasure Chest/Treasure Chest Close Left Clam": 14041318, + "Medals/Galleon Boss Defeated": 14041319, + "Medals/Forest Donkey Medal": 14041320, + "Medals/Forest Diddy Medal": 14041321, + "Medals/Forest Lanky Medal": 14041322, + "Medals/Forest Tiny Medal": 14041323, + "Medals/Forest Chunky Medal": 14041324, + "Forest Chunky Minecart/Forest Chunky Minecart": 14041325, + "Forest Diddy Top of Mushroom Barrel/Forest Diddy Top of Mushroom Barrel": 14041326, + "Inside the Mushroom/Forest Tiny Mushroom Barrel": 14041327, + "Forest DK Baboon Blast/Forest Donkey Baboon Blast": 14041328, + "Forest Kasplat: Lower Mushroom Exterior/Forest Kasplat: Low Mushroom Exterior": 14041329, + "Inside the Mushroom/Forest Donkey Mushroom Cannons": 14041330, + "Inside the Mushroom/Forest Kasplat: Inside Giant Mushroom": 14041331, + "Forest Kasplat: Mushroom Night Door/Forest Kasplat: Mushroom Night Door": 14041332, + "Forest Battle Arena: High Ladder Platform/Forest Battle Arena (Giant Mushroom High Ladder Platform)": 14041333, + "Face Puzzle Room/Forest Chunky Face Puzzle": 14041334, + "Zinger Room/Forest Lanky Zinger Bounce": 14041335, + "Forest Lanky Coloured Mushroom Slam/Forest Lanky Colored Mushroom Slam": 14041336, + "Forest Diddy Owl Race/Forest Diddy Owl Race": 14041337, + "Forest Lanky Rabbit Race/Forest Lanky Rabbit Race": 14041338, + "Forest Kasplat: Under Owl Tree/Forest Kasplat: Under Owl Tree": 14041339, + "Forest Anthill/Forest Tiny Anthill Banana": 14041340, + "Forest DK Mill Levers/Forest Donkey Mill Levers": 14041341, + "Winch Room/Forest Diddy Winch Cage": 14041342, + "Forest Tiny Spider Boss/Forest Tiny Spider Boss": 14041343, + "Forest Chunky Keg Crushing/Forest Chunky Keg Crushing": 14041344, + "Dark Rafters/Forest Diddy Dark Rafters": 14041345, + "Dark Rafters/Forest Fairy (Dark Rafters)": 14041346, + "Forest Lanky Attic Shooting/Forest Lanky Attic Shooting": 14041347, + "Forest Kasplat: Behind DK's Barn/Forest Kasplat: Behind DK's Barn": 14041348, + "Forest Donkey Thornvine Barn Barrel/Forest Donkey Thornvine Barn Barrel": 14041349, + "Forest Fairy (Thornvine Barn)/Forest Fairy (Thornvine Barn)": 14041350, + "Forest Tiny Top of Beanstalk/Forest Tiny Top of the Beanstalk": 14041351, + "Forest Chunky Apple Rescue/Forest Chunky Apple Rescue": 14041352, + "Forest Anthill/Forest Second Anthill Reward": 14041353, + "Medals/Forest Boss Defeated": 14041354, + "Medals/Caves Donkey Medal": 14041355, + "Medals/Caves Diddy Medal": 14041356, + "Medals/Caves Lanky Medal": 14041357, + "Medals/Caves Tiny Medal": 14041358, + "Medals/Caves Chunky Medal": 14041359, + "Caves DK Baboon Blast/Caves Donkey Baboon Blast": 14041360, + "Caves Diddy Jetpack Barrel/Caves Diddy Jetpack Barrel": 14041361, + "Caves Tiny Mini Cave Barrel/Caves Tiny Mini Cave Barrel": 14041362, + "Caves Tiny Monkeyport Igloo/Caves Tiny Monkeyport Igloo": 14041363, + "Caves Chunky Gorilla Gone/Caves Chunky Gorilla Gone": 14041364, + "Caves Kasplat: Near Ice Castle/Caves Kasplat: Near Ice Castle": 14041365, + "Caves Kasplat: Mini Room by Funky/Caves Kasplat: Mini Room by Funky": 14041366, + "Caves Kasplat: On the Pillar/Caves Kasplat: On the Pillar": 14041367, + "Caves Kasplat: By the Far Warp 2/Caves Kasplat: By the Far Warp 2": 14041368, + "Caves Lanky Beetle Race/Caves Lanky Beetle Race": 14041369, + "Caves Lanky Ice Castle Slam Challenge/Caves Lanky Ice Castle Slam Challenge": 14041370, + "Caves Chunky Transparent Igloo/Caves Chunky Transparent Igloo": 14041371, + "Caves Kasplat: On 5-Door Igloo/Caves Kasplat: On 5-Door Igloo": 14041372, + "Caves DK 5 Door Igloo/Caves Donkey 5 Door Igloo": 14041373, + "Caves Diddy 5 Door Igloo/Caves Diddy 5 Door Igloo": 14041374, + "Caves Lanky 5 Door Igloo/Caves Lanky 5 Door Igloo": 14041375, + "Caves Tiny 5 Door Igloo/Caves Tiny 5 Door Igloo": 14041376, + "Caves Tiny 5 Door Igloo/Caves Fairy (Tiny Igloo)": 14041377, + "Caves Chunky 5 Door Igloo/Caves Chunky 5 Door Igloo": 14041378, + "Rotating Cabin/Caves Donkey Rotating Cabin": 14041379, + "Rotating Cabin/Caves Battle Arena (Rotating Room: Left Portion)": 14041380, + "Caves DK 5 Door Cabin/Caves Donkey 5 Door Cabin": 14041381, + "Caves Diddy 5 Door Cabin Lower/Caves Diddy 5 Door Cabin Lower": 14041382, + "Caves Diddy 5 Door Cabin Upper/Caves Diddy 5 Door Cabin Upper": 14041383, + "Caves Diddy 5 Door Cabin Upper/Caves Fairy (Diddy Candles Cabin)": 14041384, + "Caves Lanky Sprint Cabin/Caves Lanky Sprint Cabin": 14041385, + "Caves Tiny 5 Door Cabin/Caves Tiny 5 Door Cabin": 14041386, + "Caves Chunky 5 Door Cabin/Caves Chunky 5 Door Cabin": 14041387, + "Medals/Caves Boss Defeated": 14041388, + "Medals/Castle Donkey Medal": 14041389, + "Medals/Castle Diddy Medal": 14041390, + "Medals/Castle Lanky Medal": 14041391, + "Medals/Castle Tiny Medal": 14041392, + "Medals/Castle Chunky Medal": 14041393, + "Castle Diddy Above Castle/Castle Diddy Above Castle": 14041394, + "Castle Kasplat: Near Upper Warp 2/Castle Kasplat: Near Upper Warp 2": 14041395, + "Castle Kasplat: On a Lone Platform/Castle Kasplat: On a lone platform": 14041396, + "Inside the Tree/Castle Donkey Tree Sniping": 14041397, + "Inside the Tree/Castle Chunky Tree Sniping Barrel": 14041398, + "Inside the Tree/Castle Kasplat: Inside the Tree": 14041399, + "Inside the Tree/Castle Fairy (Tree Sniper Room)": 14041400, + "Castle DK Library/Castle Donkey Library": 14041401, + "Castle Diddy Ballroom/Castle Diddy Ballroom": 14041402, + "Castle Fairy (Near Car Race)/Castle Fairy (Near Car Race)": 14041403, + "Castle Tiny Car Race/Castle Tiny Car Race": 14041404, + "Castle Lanky Tower/Castle Lanky Tower": 14041405, + "Greenhouse/Castle Lanky Greenhouse": 14041406, + "Greenhouse/Castle Battle Arena (Greenhouse: Center)": 14041407, + "Castle Tiny Trashcan/Castle Tiny Trash Can": 14041408, + "Castle Chunky Shed/Castle Chunky Shed": 14041409, + "Castle Chunky Museum/Castle Chunky Museum": 14041410, + "Castle Kasplat: Lower Cave Center/Castle Kasplat: Lower Cave Center": 14041411, + "Castle Diddy Crypt/Castle Diddy Crypt": 14041412, + "Castle Chunky Crypt/Castle Chunky Crypt": 14041413, + "Castle DK Minecart/Castle Donkey Minecart": 14041414, + "Mausoleum/Castle Lanky Mausoleum": 14041415, + "Mausoleum/Castle Tiny Mausoleum": 14041416, + "Castle Tiny Over Chasm/Castle Tiny Over Chasm": 14041417, + "Castle Kasplat: Near Candy's/Castle Kasplat: Near Candy's": 14041418, + "Castle DK Dungeon/Castle Donkey Dungeon": 14041419, + "Castle Diddy Dungeon/Castle Diddy Dungeon": 14041420, + "Castle Lanky Dungeon/Castle Lanky Dungeon": 14041421, + "Medals/Castle Boss Defeated": 14041422, + "Helm Battle Arena/Helm Battle Arena (Top of Blast-o-Matic)": 14041433, + "Helm DK Medal/Helm Donkey Medal": 14041434, + "Helm Chunky Medal/Helm Chunky Medal": 14041435, + "Helm Tiny Medal/Helm Tiny Medal": 14041436, + "Helm Lanky Medal/Helm Lanky Medal": 14041437, + "Helm Diddy Medal/Helm Diddy Medal": 14041438, + "Helm Fairy (Key 8 Room)/Helm Fairy (Key 8 Room (1))": 14041439, + "Helm Fairy (Key 8 Room)/Helm Fairy (Key 8 Room (2))": 14041440, + "The End of Helm/The End of Helm": 14041441, + "Isles Cranky/Isles Cranky Shared": 14041442, + "Japes Cranky/Japes Cranky Donkey": 14041443, + "Japes Cranky/Japes Cranky Diddy": 14041444, + "Japes Cranky/Japes Cranky Lanky": 14041445, + "Japes Cranky/Japes Cranky Tiny": 14041446, + "Japes Cranky/Japes Cranky Chunky": 14041447, + "Japes Funky/Japes Funky Donkey": 14041448, + "Japes Funky/Japes Funky Diddy": 14041449, + "Japes Funky/Japes Funky Lanky": 14041450, + "Japes Funky/Japes Funky Tiny": 14041451, + "Japes Funky/Japes Funky Chunky": 14041452, + "Aztec Cranky/Aztec Cranky Donkey": 14041453, + "Aztec Cranky/Aztec Cranky Diddy": 14041454, + "Aztec Candy/Aztec Candy Donkey": 14041455, + "Aztec Candy/Aztec Candy Diddy": 14041456, + "Aztec Candy/Aztec Candy Lanky": 14041457, + "Aztec Candy/Aztec Candy Tiny": 14041458, + "Aztec Candy/Aztec Candy Chunky": 14041459, + "Factory Cranky/Factory Cranky Donkey": 14041460, + "Factory Cranky/Factory Cranky Diddy": 14041461, + "Factory Cranky/Factory Cranky Lanky": 14041462, + "Factory Cranky/Factory Cranky Tiny": 14041463, + "Factory Cranky/Factory Cranky Chunky": 14041464, + "Factory Funky/Factory Funky Shared": 14041465, + "Galleon Candy/Galleon Candy Shared": 14041466, + "Forest Cranky/Forest Cranky Shared": 14041467, + "Forest Funky/Forest Funky Shared": 14041468, + "Caves Cranky/Caves Cranky Lanky": 14041469, + "Caves Cranky/Caves Cranky Tiny": 14041470, + "Caves Cranky/Caves Cranky Chunky": 14041471, + "Caves Funky/Caves Funky Shared": 14041472, + "Caves Candy/Caves Candy Shared": 14041473, + "Castle Cranky/Castle Cranky Shared": 14041474, + "Castle Funky/Castle Funky Shared": 14041475, + "Castle Candy/Castle Candy Shared": 14041476, + "Isles Cranky/Jetpac": 14041477, + "Japes Cranky/Japes Cranky Shared": 14041478, + "Japes Funky/Japes Funky Shared": 14041479, + "Aztec Cranky/Aztec Cranky Shared": 14041480, + "Aztec Cranky/Aztec Cranky Lanky": 14041481, + "Aztec Cranky/Aztec Cranky Tiny": 14041482, + "Aztec Cranky/Aztec Cranky Chunky": 14041483, + "Aztec Funky/Aztec Funky Shared": 14041484, + "Aztec Funky/Aztec Funky Donkey": 14041485, + "Aztec Funky/Aztec Funky Diddy": 14041486, + "Aztec Funky/Aztec Funky Lanky": 14041487, + "Aztec Funky/Aztec Funky Tiny": 14041488, + "Aztec Funky/Aztec Funky Chunky": 14041489, + "Aztec Candy/Aztec Candy Shared": 14041490, + "Factory Cranky/Factory Cranky Shared": 14041491, + "Factory Funky/Factory Funky Donkey": 14041492, + "Factory Funky/Factory Funky Diddy": 14041493, + "Factory Funky/Factory Funky Lanky": 14041494, + "Factory Funky/Factory Funky Tiny": 14041495, + "Factory Funky/Factory Funky Chunky": 14041496, + "Factory Candy/Factory Candy Shared": 14041497, + "Factory Candy/Factory Candy Donkey": 14041498, + "Factory Candy/Factory Candy Diddy": 14041499, + "Factory Candy/Factory Candy Lanky": 14041500, + "Factory Candy/Factory Candy Tiny": 14041501, + "Factory Candy/Factory Candy Chunky": 14041502, + "Galleon Cranky/Galleon Cranky Shared": 14041503, + "Galleon Cranky/Galleon Cranky Donkey": 14041504, + "Galleon Cranky/Galleon Cranky Diddy": 14041505, + "Galleon Cranky/Galleon Cranky Lanky": 14041506, + "Galleon Cranky/Galleon Cranky Tiny": 14041507, + "Galleon Cranky/Galleon Cranky Chunky": 14041508, + "Galleon Funky/Galleon Funky Shared": 14041509, + "Galleon Funky/Galleon Funky Donkey": 14041510, + "Galleon Funky/Galleon Funky Diddy": 14041511, + "Galleon Funky/Galleon Funky Lanky": 14041512, + "Galleon Funky/Galleon Funky Tiny": 14041513, + "Galleon Funky/Galleon Funky Chunky": 14041514, + "Galleon Candy/Galleon Candy Donkey": 14041515, + "Galleon Candy/Galleon Candy Diddy": 14041516, + "Galleon Candy/Galleon Candy Lanky": 14041517, + "Galleon Candy/Galleon Candy Tiny": 14041518, + "Galleon Candy/Galleon Candy Chunky": 14041519, + "Forest Cranky/Forest Cranky Donkey": 14041520, + "Forest Cranky/Forest Cranky Diddy": 14041521, + "Forest Cranky/Forest Cranky Lanky": 14041522, + "Forest Cranky/Forest Cranky Tiny": 14041523, + "Forest Cranky/Forest Cranky Chunky": 14041524, + "Forest Funky/Forest Funky Donkey": 14041525, + "Forest Funky/Forest Funky Diddy": 14041526, + "Forest Funky/Forest Funky Lanky": 14041527, + "Forest Funky/Forest Funky Tiny": 14041528, + "Forest Funky/Forest Funky Chunky": 14041529, + "Caves Cranky/Caves Cranky Shared": 14041530, + "Caves Cranky/Caves Cranky Donkey": 14041531, + "Caves Cranky/Caves Cranky Diddy": 14041532, + "Caves Funky/Caves Funky Donkey": 14041533, + "Caves Funky/Caves Funky Diddy": 14041534, + "Caves Funky/Caves Funky Lanky": 14041535, + "Caves Funky/Caves Funky Tiny": 14041536, + "Caves Funky/Caves Funky Chunky": 14041537, + "Caves Candy/Caves Candy Donkey": 14041538, + "Caves Candy/Caves Candy Diddy": 14041539, + "Caves Candy/Caves Candy Lanky": 14041540, + "Caves Candy/Caves Candy Tiny": 14041541, + "Caves Candy/Caves Candy Chunky": 14041542, + "Castle Cranky/Castle Cranky Donkey": 14041543, + "Castle Cranky/Castle Cranky Diddy": 14041544, + "Castle Cranky/Castle Cranky Lanky": 14041545, + "Castle Cranky/Castle Cranky Tiny": 14041546, + "Castle Cranky/Castle Cranky Chunky": 14041547, + "Castle Funky/Castle Funky Donkey": 14041548, + "Castle Funky/Castle Funky Diddy": 14041549, + "Castle Funky/Castle Funky Lanky": 14041550, + "Castle Funky/Castle Funky Tiny": 14041551, + "Castle Funky/Castle Funky Chunky": 14041552, + "Castle Candy/Castle Candy Donkey": 14041553, + "Castle Candy/Castle Candy Diddy": 14041554, + "Castle Candy/Castle Candy Lanky": 14041555, + "Castle Candy/Castle Candy Tiny": 14041556, + "Castle Candy/Castle Candy Chunky": 14041557, + "Isles Cranky/Isles Cranky Donkey": 14041558, + "Isles Cranky/Isles Cranky Diddy": 14041559, + "Isles Cranky/Isles Cranky Lanky": 14041560, + "Isles Cranky/Isles Cranky Tiny": 14041561, + "Isles Cranky/Isles Cranky Chunky": 14041562, + "Turn in 1 Blueprint/Turning In 1 Blueprint": 14041563, + "Turn in 2 Blueprints/Turning In 2 Blueprints": 14041564, + "Turn in 3 Blueprints/Turning In 3 Blueprints": 14041565, + "Turn in 4 Blueprints/Turning In 4 Blueprints": 14041566, + "Turn in 5 Blueprints/Turning In 5 Blueprints": 14041567, + "Turn in 6 Blueprints/Turning In 6 Blueprints": 14041568, + "Turn in 7 Blueprints/Turning In 7 Blueprints": 14041569, + "Turn in 8 Blueprints/Turning In 8 Blueprints": 14041570, + "Turn in 9 Blueprints/Turning In 9 Blueprints": 14041571, + "Turn in 10 Blueprints/Turning In 10 Blueprints": 14041572, + "Turn in 11 Blueprints/Turning In 11 Blueprints": 14041573, + "Turn in 12 Blueprints/Turning In 12 Blueprints": 14041574, + "Turn in 13 Blueprints/Turning In 13 Blueprints": 14041575, + "Turn in 14 Blueprints/Turning In 14 Blueprints": 14041576, + "Turn in 15 Blueprints/Turning In 15 Blueprints": 14041577, + "Turn in 16 Blueprints/Turning In 16 Blueprints": 14041578, + "Turn in 17 Blueprints/Turning In 17 Blueprints": 14041579, + "Turn in 18 Blueprints/Turning In 18 Blueprints": 14041580, + "Turn in 19 Blueprints/Turning In 19 Blueprints": 14041581, + "Turn in 20 Blueprints/Turning In 20 Blueprints": 14041582, + "Turn in 21 Blueprints/Turning In 21 Blueprints": 14041583, + "Turn in 22 Blueprints/Turning In 22 Blueprints": 14041584, + "Turn in 23 Blueprints/Turning In 23 Blueprints": 14041585, + "Turn in 24 Blueprints/Turning In 24 Blueprints": 14041586, + "Turn in 25 Blueprints/Turning In 25 Blueprints": 14041587, + "Turn in 26 Blueprints/Turning In 26 Blueprints": 14041588, + "Turn in 27 Blueprints/Turning In 27 Blueprints": 14041589, + "Turn in 28 Blueprints/Turning In 28 Blueprints": 14041590, + "Turn in 29 Blueprints/Turning In 29 Blueprints": 14041591, + "Turn in 30 Blueprints/Turning In 30 Blueprints": 14041592, + "Turn in 31 Blueprints/Turning In 31 Blueprints": 14041593, + "Turn in 32 Blueprints/Turning In 32 Blueprints": 14041594, + "Turn in 33 Blueprints/Turning In 33 Blueprints": 14041595, + "Turn in 34 Blueprints/Turning In 34 Blueprints": 14041596, + "Turn in 35 Blueprints/Turning In 35 Blueprints": 14041597, + "Turn in 36 Blueprints/Turning In 36 Blueprints": 14041598, + "Turn in 37 Blueprints/Turning In 37 Blueprints": 14041599, + "Turn in 38 Blueprints/Turning In 38 Blueprints": 14041600, + "Turn in 39 Blueprints/Turning In 39 Blueprints": 14041601, + "Turn in 40 Blueprints/Turning In 40 Blueprints": 14041602, + "Japes DK Wrinkly Door/Japes Donkey Hint Door": 14041603, + "Japes Diddy Wrinkly Door/Japes Diddy Hint Door": 14041604, + "Japes Lanky Wrinkly Door/Japes Lanky Hint Door": 14041605, + "Japes Tiny Wrinkly Door/Japes Tiny Hint Door": 14041606, + "Japes Chunky Wrinkly Door/Japes Chunky Hint Door": 14041607, + "Aztec DK Wrinkly Door/Aztec Donkey Hint Door": 14041608, + "Aztec Diddy Wrinkly Door/Aztec Diddy Hint Door": 14041609, + "Aztec Lanky Wrinkly Door/Aztec Lanky Hint Door": 14041610, + "Aztec Tiny Wrinkly Door/Aztec Tiny Hint Door": 14041611, + "Aztec Chunky Wrinkly Door/Aztec Chunky Hint Door": 14041612, + "Factory DK Wrinkly Door/Factory Donkey Hint Door": 14041613, + "Factory Diddy Wrinkly Door/Factory Diddy Hint Door": 14041614, + "Factory Lanky Wrinkly Door/Factory Lanky Hint Door": 14041615, + "Factory Tiny Wrinkly Door/Factory Tiny Hint Door": 14041616, + "Factory Chunky Wrinkly Door/Factory Chunky Hint Door": 14041617, + "Galleon DK Hint Door/Galleon Donkey Hint Door": 14041618, + "Galleon Diddy Hint Door/Galleon Diddy Hint Door": 14041619, + "Galleon Lanky Hint Door/Galleon Lanky Hint Door": 14041620, + "Galleon Tiny Hint Door/Galleon Tiny Hint Door": 14041621, + "Galleon Chunky Hint Door/Galleon Chunky Hint Door": 14041622, + "Forest DK Hint Door/Forest Donkey Hint Door": 14041623, + "Forest Diddy Hint Door/Forest Diddy Hint Door": 14041624, + "Forest Lanky Hint Door/Forest Lanky Hint Door": 14041625, + "Forest Tiny Hint Door/Forest Tiny Hint Door": 14041626, + "Forest Chunky Hint Door/Forest Chunky Hint Door": 14041627, + "Caves DK Hint Door/Caves Donkey Hint Door": 14041628, + "Caves Diddy Hint Door/Caves Diddy Hint Door": 14041629, + "Caves Lanky Hint Door/Caves Lanky Hint Door": 14041630, + "Caves Tiny Hint Door/Caves Tiny Hint Door": 14041631, + "Caves Chunky Hint Door/Caves Chunky Hint Door": 14041632, + "Castle DK Hint Door/Castle Donkey Hint Door": 14041633, + "Castle Diddy Hint Door/Castle Diddy Hint Door": 14041634, + "Castle Lanky Hint Door/Castle Lanky Hint Door": 14041635, + "Castle Tiny Hint Door/Castle Tiny Hint Door": 14041636, + "Castle Chunky Hint Door/Castle Chunky Hint Door": 14041637, + "Japes Dirt: Painting Hill/Japes Dirt: Painting Hill": 14041673, + "5 Door Temple/Aztec Dirt: Chunky Temple": 14041674, + "Factory Dirt: Dark Room/Factory Dirt: Dark Room": 14041675, + "Isles Dirt: Cabin Isle/Isles Dirt: Cabin Isle": 14041676, + "Isles Dirt: Under Caves Lobby/Isles Dirt: Under Caves Lobby": 14041677, + "Isles Dirt: Aztec Roof/Isles Dirt: Aztec Roof": 14041678, + "Aztec Dirt: Oasis/Aztec Dirt: Oasis": 14041679, + "Forest Dirt: Near Mills Grass/Forest Dirt: Mills Grass": 14041680, + "Forest Dirt: Beanstalk/Forest Dirt: Beanstalk": 14041681, + "Lighthouse/Galleon Dirt: Lighthouse": 14041682, + "Caves Dirt: Giant Kosha/Caves Dirt: Giant Kosha": 14041683, + "Castle Dirt: Top Floor/Castle Dirt: Top Floor": 14041684, + "K. Lumsy Prison/Isles Dirt: Back of Prison": 14041685, + "Isles Dirt: Training Grounds Rear Tunnel/Isles Dirt: Training Grounds Rear Tunnel": 14041686, + "Isles Dirt: Banana Hoard/Isles Dirt: Banana Hoard": 14041687, + "Upper Castle Lobby/Isles Dirt: Castle Lobby": 14041688, + "Japes Crate: Behind the Mountain/Japes Crate: Behind the Mountain": 14041689, + "Japes Crate: In the Rambi Cave/Japes Crate: In the Rambi Cave": 14041690, + "Aztec Crate: Llama Temple/Aztec Crate: Llama Temple Entrance": 14041691, + "Factory Crate: Near Funky/Factory Crate: Near Funky": 14041692, + "Factory Crate: Near Candy/Factory Crate: Near Candy": 14041693, + "Galleon Crate: Near Cactus/Galleon Crate: Near Cactus": 14041694, + "Aztec Crate: On Llama Temple/Aztec Crate: On Llama Temple": 14041695, + "Aztec Crate: Near Gong Tower/Aztec Crate: Near Gong Tower": 14041696, + "Forest Crate: Near Owl Tree/Forest Crate: Near Owl Tree": 14041697, + "Forest Crate: Near Thornvine Barn/Forest Crate: Near Thornvine Barn": 14041698, + "Forest Crate: Behind Dark Attic/Forest Crate: Behind Dark Attic": 14041699, + "Forest Crate: In Thornvine Barn/Forest Crate: In Thornvine Barn": 14041700, + "Castle Crate: Behind Mausoleum Entrance/Castle Crate: Behind Mausoleum Entrance": 14041701, + "Isles Boulder: Near Level 2/Isles Boulder: Near Level 2": 14041702, + "Isles Chunky Triangle Pad/Isles Boulder: Near Level 6": 14041703, + "Aztec Boulder: Tunnel/Aztec Boulder: Tunnel": 14041704, + "Caves Boulder: Small/Caves Boulder: Small": 14041705, + "Caves Boulder: Large/Caves Boulder: Large": 14041706, + "Castle Boulder: Museum/Castle Boulder: Museum": 14041707, + "Isles Lanky Instrument Pad/Isles Boulder: Japes Lobby": 14041708, + "Isles Boulder: Castle Lobby/Isles Boulder: Castle Lobby": 14041709, + "Isles Boulder: Caves Lobby/Isles Boulder: Caves Lobby": 14041710, + "Forest Keg: Mill Front Near/Forest Keg: Mill Front Near": 14041711, + "Forest Keg: Mill Front Far/Forest Keg: Mill Front Far": 14041712, + "Forest Keg: Mill Back/Forest Keg: Mill Back": 14041713, + "Aztec Chunky Vases/Aztec Vase: Circle": 14041714, + "Aztec Chunky Vases/Aztec Vase: Colon": 14041715, + "Aztec Chunky Vases/Aztec Vase: Triangle": 14041716, + "Aztec Chunky Vases/Aztec Vase: Plus": 14041717, + "Jungle Japes Enemy: Start/Japes Enemy: Start": 14041718, + "Jungle Japes Enemy: Diddy Cavern/Japes Enemy: Diddy Cavern": 14041719, + "Jungle Japes Enemy: Tunnel (0)/Japes Enemy: Tunnel (0)": 14041720, + "Jungle Japes Enemy: Tunnel (1)/Japes Enemy: Tunnel (1)": 14041721, + "Jungle Japes Enemy: Storm (0)/Japes Enemy: Storm (0)": 14041722, + "Jungle Japes Enemy: Storm (1)/Japes Enemy: Storm (1)": 14041723, + "Jungle Japes Enemy: Storm (2)/Japes Enemy: Storm (2)": 14041724, + "Jungle Japes Enemy: Hive (0)/Japes Enemy: Hive (0)": 14041725, + "Jungle Japes Enemy: Hive (1)/Japes Enemy: Hive (1)": 14041726, + "Jungle Japes Enemy: Hive (2)/Japes Enemy: Hive (2)": 14041727, + "Jungle Japes Enemy: Hive (3)/Japes Enemy: Hive (3)": 14041728, + "Jungle Japes Enemy: Hive (4)/Japes Enemy: Hive (4)": 14041729, + "Jungle Japes Enemy: Killed In Demo/Japes Enemy: Killed In Demo": 14041730, + "Jungle Japes Enemy: Near Underground/Japes Enemy: Near Underground": 14041731, + "Jungle Japes Enemy: Near Painting (0)/Japes Enemy: Near Painting (0)": 14041732, + "Jungle Japes Enemy: Near Painting (1)/Japes Enemy: Near Painting (1)": 14041733, + "Jungle Japes Enemy: Near Painting (2)/Japes Enemy: Near Painting (2)": 14041734, + "Jungle Japes Enemy: Mountain/Japes Enemy: Mountain": 14041735, + "Jungle Japes Enemy: Feather Tunnel/Japes Enemy: Feather Tunnel": 14041736, + "Jungle Japes Enemy: Middle Tunnel/Japes Enemy: Middle Tunnel": 14041737, + "Jungle Japes Lobby Enemy: Enemy (0)/Isles Japes Lobby Enemy: Enemy (0)": 14041738, + "Jungle Japes Lobby Enemy: Enemy (1)/Isles Japes Lobby Enemy: Enemy (1)": 14041739, + "Japes Mountain Enemy: Start (0)/Japes Mountain Enemy: Start (0)": 14041740, + "Japes Mountain Enemy: Start (1)/Japes Mountain Enemy: Start (1)": 14041741, + "Japes Mountain Enemy: Start (2)/Japes Mountain Enemy: Start (2)": 14041742, + "Japes Mountain Enemy: Start (3)/Japes Mountain Enemy: Start (3)": 14041743, + "Japes Mountain Enemy: Start (4)/Japes Mountain Enemy: Start (4)": 14041744, + "Japes Mountain Enemy: Near Gate Switch (0)/Japes Mountain Enemy: Near Gate Switch (0)": 14041745, + "Japes Mountain Enemy: Near Gate Switch (1)/Japes Mountain Enemy: Near Gate Switch (1)": 14041746, + "Japes Mountain Enemy: Hi Lo/Japes Mountain Enemy: Hi Lo": 14041747, + "Japes Mountain Enemy: Conveyor (0)/Japes Mountain Enemy: Conveyor (0)": 14041748, + "Japes Mountain Enemy: Conveyor (1)/Japes Mountain Enemy: Conveyor (1)": 14041749, + "Japes Tiny Hive Enemy: First Room/Japes Tiny Hive Enemy: First Room": 14041750, + "Japes Tiny Hive Enemy: Second Room (0)/Japes Tiny Hive Enemy: Second Room (0)": 14041751, + "Japes Tiny Hive Enemy: Second Room (1)/Japes Tiny Hive Enemy: Second Room (1)": 14041752, + "Japes Tiny Hive Enemy: Third Room (0)/Japes Tiny Hive Enemy: Third Room (0)": 14041753, + "Japes Tiny Hive Enemy: Third Room (1)/Japes Tiny Hive Enemy: Third Room (1)": 14041754, + "Japes Tiny Hive Enemy: Third Room (2)/Japes Tiny Hive Enemy: Third Room (2)": 14041755, + "Japes Tiny Hive Enemy: Third Room (3)/Japes Tiny Hive Enemy: Third Room (3)": 14041756, + "Japes Tiny Hive Enemy: Main Room/Japes Tiny Hive Enemy: Main Room": 14041757, + "Angry Aztec Enemy: Vase Room (0)/Aztec Enemy: Vase Room (0)": 14041758, + "Angry Aztec Enemy: Vase Room (1)/Aztec Enemy: Vase Room (1)": 14041759, + "Angry Aztec Enemy: Vase Room (2)/Aztec Enemy: Vase Room (2)": 14041760, + "Angry Aztec Enemy: Tunnel Pad (0)/Aztec Enemy: Tunnel Pad (0)": 14041761, + "Angry Aztec Enemy: Tunnel Cage (0)/Aztec Enemy: Tunnel Cage (0)": 14041762, + "Angry Aztec Enemy: Tunnel Cage (1)/Aztec Enemy: Tunnel Cage (1)": 14041763, + "Angry Aztec Enemy: Tunnel Cage (2)/Aztec Enemy: Tunnel Cage (2)": 14041764, + "Angry Aztec Enemy: Starting Tunnel (0)/Aztec Enemy: Starting Tunnel (0)": 14041765, + "Angry Aztec Enemy: Starting Tunnel (1)/Aztec Enemy: Starting Tunnel (1)": 14041766, + "Angry Aztec Enemy: Oasis Door/Aztec Enemy: Oasis Door": 14041767, + "Angry Aztec Enemy: Tunnel Cage (3)/Aztec Enemy: Tunnel Cage (3)": 14041768, + "Angry Aztec Enemy: Outside Llama/Aztec Enemy: Outside Llama": 14041769, + "Angry Aztec Enemy: Outside Tower/Aztec Enemy: Outside Tower": 14041770, + "Angry Aztec Enemy: Tunnel Pad (1)/Aztec Enemy: Tunnel Pad (1)": 14041771, + "Angry Aztec Enemy: Near Candy/Aztec Enemy: Near Candy": 14041772, + "Angry Aztec Enemy: Around Totem/Aztec Enemy: Around Totem": 14041773, + "Angry Aztec Enemy: Starting Tunnel (2)/Aztec Enemy: Starting Tunnel (2)": 14041774, + "Angry Aztec Enemy: Starting Tunnel (3)/Aztec Enemy: Starting Tunnel (3)": 14041775, + "Angry Aztec Enemy: Outside Snide/Aztec Enemy: Outside Snide": 14041776, + "Angry Aztec Enemy: Outside 5DT/Aztec Enemy: Outside 5DT": 14041777, + "Angry Aztec Enemy: Near Sealed Quicksand Tunnel/Aztec Enemy: Near Sealed Quicksand Tunnel": 14041778, + "Aztec Donkey 5DTemple Enemy: Start Trap (0)/Aztec Donkey 5DTemple Enemy: Start Trap (0)": 14041779, + "Aztec Donkey 5DTemple Enemy: Start Trap (1)/Aztec Donkey 5DTemple Enemy: Start Trap (1)": 14041780, + "Aztec Donkey 5DTemple Enemy: Start Trap (2)/Aztec Donkey 5DTemple Enemy: Start Trap (2)": 14041781, + "Aztec Donkey 5DTemple Enemy: End Trap (0)/Aztec Donkey 5DTemple Enemy: End Trap (0)": 14041782, + "Aztec Donkey 5DTemple Enemy: End Trap (1)/Aztec Donkey 5DTemple Enemy: End Trap (1)": 14041783, + "Aztec Donkey 5DTemple Enemy: End Trap (2)/Aztec Donkey 5DTemple Enemy: End Trap (2)": 14041784, + "Aztec Donkey 5DTemple Enemy: End Path (0)/Aztec Donkey 5DTemple Enemy: End Path (0)": 14041785, + "Aztec Donkey 5DTemple Enemy: End Path (1)/Aztec Donkey 5DTemple Enemy: End Path (1)": 14041786, + "Aztec Donkey 5DTemple Enemy: Start Path/Aztec Donkey 5DTemple Enemy: Start Path": 14041787, + "Aztec Diddy 5DTemple Enemy: End Trap (0)/Aztec Diddy 5DTemple Enemy: End Trap (0)": 14041788, + "Aztec Diddy 5DTemple Enemy: End Trap (1)/Aztec Diddy 5DTemple Enemy: End Trap (1)": 14041789, + "Aztec Diddy 5DTemple Enemy: End Trap (2)/Aztec Diddy 5DTemple Enemy: End Trap (2)": 14041790, + "Aztec Diddy 5DTemple Enemy: Start Left (0)/Aztec Diddy 5DTemple Enemy: Start Left (0)": 14041791, + "Aztec Diddy 5DTemple Enemy: Start Left (1)/Aztec Diddy 5DTemple Enemy: Start Left (1)": 14041792, + "Aztec Diddy 5DTemple Enemy: Reward/Aztec Diddy 5DTemple Enemy: Reward": 14041793, + "Aztec Diddy 5DTemple Enemy: Second Switch/Aztec Diddy 5DTemple Enemy: Second Switch": 14041794, + "Aztec Lanky 5DTemple Enemy: Joining Paths/Aztec Lanky 5DTemple Enemy: Joining Paths": 14041795, + "Aztec Lanky 5DTemple Enemy: End Trap/Aztec Lanky 5DTemple Enemy: End Trap": 14041796, + "Aztec Lanky 5DTemple Enemy: Reward/Aztec Lanky 5DTemple Enemy: Reward": 14041797, + "Aztec Tiny 5DTemple Enemy: Start Right Front/Aztec Tiny 5DTemple Enemy: Start Right Front": 14041798, + "Aztec Tiny 5DTemple Enemy: Start Left Back/Aztec Tiny 5DTemple Enemy: Start Left Back": 14041799, + "Aztec Tiny 5DTemple Enemy: Start Right Back/Aztec Tiny 5DTemple Enemy: Start Right Back": 14041800, + "Aztec Tiny 5DTemple Enemy: Start Left Front/Aztec Tiny 5DTemple Enemy: Start Left Front": 14041801, + "Aztec Tiny 5DTemple Enemy: Reward (0)/Aztec Tiny 5DTemple Enemy: Reward (0)": 14041802, + "Aztec Tiny 5DTemple Enemy: Reward (1)/Aztec Tiny 5DTemple Enemy: Reward (1)": 14041803, + "Aztec Tiny 5DTemple Enemy: Dead End (0)/Aztec Tiny 5DTemple Enemy: Dead End (0)": 14041804, + "Aztec Tiny 5DTemple Enemy: Dead End (1)/Aztec Tiny 5DTemple Enemy: Dead End (1)": 14041805, + "Aztec Chunky 5DTemple Enemy: Start Right/Aztec Chunky 5DTemple Enemy: Start Right": 14041806, + "Aztec Chunky 5DTemple Enemy: Start Left/Aztec Chunky 5DTemple Enemy: Start Left": 14041807, + "Aztec Chunky 5DTemple Enemy: Second Right/Aztec Chunky 5DTemple Enemy: Second Right": 14041808, + "Aztec Chunky 5DTemple Enemy: Second Left/Aztec Chunky 5DTemple Enemy: Second Left": 14041809, + "Aztec Chunky 5DTemple Enemy: Reward/Aztec Chunky 5DTemple Enemy: Reward": 14041810, + "Aztec Llama Temple Enemy: Kong Free Instrument/Aztec Llama Temple Enemy: Kong Free Instrument": 14041811, + "Aztec Llama Temple Enemy: Dino Instrument/Aztec Llama Temple Enemy: Dino Instrument": 14041812, + "Aztec Llama Temple Enemy: Matching (0)/Aztec Llama Temple Enemy: Matching0": 14041813, + "Aztec Llama Temple Enemy: Matching (1)/Aztec Llama Temple Enemy: Matching1": 14041814, + "Aztec Llama Temple Enemy: Right/Aztec Llama Temple Enemy: Right": 14041815, + "Aztec Llama Temple Enemy: Left/Aztec Llama Temple Enemy: Left": 14041816, + "Aztec Llama Temple Enemy: Melon Crate/Aztec Llama Temple Enemy: Melon Crate": 14041817, + "Aztec Llama Temple Enemy: Slam Switch/Aztec Llama Temple Enemy: Slam Switch": 14041818, + "Aztec Tiny Temple Enemy: Guard Rotating (0)/Aztec Tiny Temple Enemy: Guard Rotating (0)": 14041819, + "Aztec Tiny Temple Enemy: Guard Rotating (1)/Aztec Tiny Temple Enemy: Guard Rotating (1)": 14041820, + "Aztec Tiny Temple Enemy: Main Room (0)/Aztec Tiny Temple Enemy: Main Room (0)": 14041821, + "Aztec Tiny Temple Enemy: Main Room (1)/Aztec Tiny Temple Enemy: Main Room (1)": 14041822, + "Aztec Tiny Temple Enemy: Main Room (2)/Aztec Tiny Temple Enemy: Main Room (2)": 14041823, + "Aztec Tiny Temple Enemy: Kong Room (0)/Aztec Tiny Temple Enemy: Kong Room (0)": 14041824, + "Aztec Tiny Temple Enemy: Kong Room (1)/Aztec Tiny Temple Enemy: Kong Room (1)": 14041825, + "Aztec Tiny Temple Enemy: Kong Room (2)/Aztec Tiny Temple Enemy: Kong Room (2)": 14041826, + "Aztec Tiny Temple Enemy: Kong Room (3)/Aztec Tiny Temple Enemy: Kong Room (3)": 14041827, + "Aztec Tiny Temple Enemy: Kong Room (4)/Aztec Tiny Temple Enemy: Kong Room (4)": 14041828, + "Frantic Factory Enemy: Candy Cranky (0)/Factory Enemy: Candy Cranky (0)": 14041829, + "Frantic Factory Enemy: Candy Cranky (1)/Factory Enemy: Candy Cranky (1)": 14041830, + "Frantic Factory Enemy: Lobby Left/Factory Enemy: Lobby Left": 14041831, + "Frantic Factory Enemy: Lobby Right/Factory Enemy: Lobby Right": 14041832, + "Frantic Factory Enemy: Storage Room/Factory Enemy: Storage Room": 14041833, + "Frantic Factory Enemy: Block Tower (0)/Factory Enemy: Block Tower (0)": 14041834, + "Frantic Factory Enemy: Block Tower (1)/Factory Enemy: Block Tower (1)": 14041835, + "Frantic Factory Enemy: Block Tower (2)/Factory Enemy: Block Tower (2)": 14041836, + "Frantic Factory Enemy: Tunnel To Hatch/Factory Enemy: Tunnel To Hatch": 14041837, + "Frantic Factory Enemy: Tunnel To Prod (0)/Factory Enemy: Tunnel To Prod (0)": 14041838, + "Frantic Factory Enemy: Tunnel To Prod (1)/Factory Enemy: Tunnel To Prod (1)": 14041839, + "Frantic Factory Enemy: Tunnel To Block Tower/Factory Enemy: Tunnel To Block Tower": 14041840, + "Frantic Factory Enemy: Tunnel To Race (0)/Factory Enemy: Tunnel To Race (0)": 14041841, + "Frantic Factory Enemy: Tunnel To Race (1)/Factory Enemy: Tunnel To Race (1)": 14041842, + "Frantic Factory Enemy: Low Warp 4/Factory Enemy: Low Warp 4": 14041843, + "Frantic Factory Enemy: Diddy Switch/Factory Enemy: Diddy Switch": 14041844, + "Frantic Factory Enemy: To Block Tower Tunnel/Factory Enemy: To Block Tower Tunnel": 14041845, + "Frantic Factory Enemy: Dark Room (0)/Factory Enemy: Dark Room (0)": 14041846, + "Frantic Factory Enemy: Dark Room (1)/Factory Enemy: Dark Room (1)": 14041847, + "Frantic Factory Lobby Enemy: Enemy (0)/Isles Factory Lobby Enemy: Enemy (0)": 14041848, + "Gloomy Galleon Enemy: Chest Room (0)/Galleon Enemy: Chest Room (0)": 14041849, + "Gloomy Galleon Enemy: Chest Room (1)/Galleon Enemy: Chest Room (1)": 14041850, + "Gloomy Galleon Enemy: Near Vine Cannon/Galleon Enemy: Near Vine Cannon": 14041851, + "Gloomy Galleon Enemy: Cranky Cannon/Galleon Enemy: Cranky Cannon": 14041852, + "Gloomy Galleon Enemy: Peanut Tunnel/Galleon Enemy: Peanut Tunnel": 14041853, + "Gloomy Galleon Enemy: Coconut Tunnel/Galleon Enemy: Coconut Tunnel": 14041854, + "Lighthouse/Galleon Lighthouse Enemy: Enemy (0)": 14041855, + "Lighthouse/Galleon Lighthouse Enemy: Enemy (1)": 14041856, + "Fungi Forest Enemy: Hollow Tree (0)/Forest Enemy: Hollow Tree (0)": 14041857, + "Fungi Forest Enemy: Hollow Tree (1)/Forest Enemy: Hollow Tree (1)": 14041858, + "Fungi Forest Enemy: Hollow Tree Entrance/Forest Enemy: Hollow Tree Entrance": 14041859, + "Fungi Forest Enemy: Tree Melon Crate (0)/Forest Enemy: Tree Melon Crate (0)": 14041860, + "Fungi Forest Enemy: Tree Melon Crate (1)/Forest Enemy: Tree Melon Crate (1)": 14041861, + "Fungi Forest Enemy: Tree Melon Crate (2)/Forest Enemy: Tree Melon Crate (2)": 14041862, + "Fungi Forest Enemy: Apple Gauntlet (0)/Forest Enemy: Apple Gauntlet (0)": 14041863, + "Fungi Forest Enemy: Apple Gauntlet (1)/Forest Enemy: Apple Gauntlet (1)": 14041864, + "Fungi Forest Enemy: Apple Gauntlet (2)/Forest Enemy: Apple Gauntlet (2)": 14041865, + "Fungi Forest Enemy: Apple Gauntlet (3)/Forest Enemy: Apple Gauntlet (3)": 14041866, + "Fungi Forest Enemy: Near Beanstalk (0)/Forest Enemy: Near Beanstalk (0)": 14041867, + "Fungi Forest Enemy: Near Beanstalk (1)/Forest Enemy: Near Beanstalk (1)": 14041868, + "Fungi Forest Enemy: Green Tunnel/Forest Enemy: Green Tunnel": 14041869, + "Fungi Forest Enemy: Near Low Warp 5/Forest Enemy: Near Low Warp 5": 14041870, + "Fungi Forest Enemy: Near Pink Tunnel Bounce Tag/Forest Enemy: Near Pink Tunnel Bounce Tag": 14041871, + "Fungi Forest Enemy: Near Giant Mushroom Rocketbarrel/Forest Enemy: Near Giant Mushroom Rocketbarrel": 14041872, + "Fungi Forest Enemy: Between Yellow Tunnel And RB/Forest Enemy: Between Yellow Tunnel And RB": 14041873, + "Fungi Forest Enemy: Near Cranky/Forest Enemy: Near Cranky": 14041874, + "Fungi Forest Enemy: Near Pink Tunnel Giant Mushroom/Forest Enemy: Near Pink Tunnel Giant Mushroom": 14041875, + "Fungi Forest Enemy: Giant Mushroom Rear Tag/Forest Enemy: Giant Mushroom Rear Tag": 14041876, + "Fungi Forest Enemy: Near Face Puzzle/Forest Enemy: Near Face Puzzle": 14041877, + "Fungi Forest Enemy: Near Crown/Forest Enemy: Near Crown": 14041878, + "Fungi Forest Enemy: Near High Warp 5/Forest Enemy: Near High Warp 5": 14041879, + "Fungi Forest Enemy: Top Of Mushroom/Forest Enemy: Top Of Mushroom": 14041880, + "Fungi Forest Enemy: Near Apple Dropoff/Forest Enemy: Near Apple Dropoff": 14041881, + "Fungi Forest Enemy: Near DKPortal/Forest Enemy: Near DKPortal": 14041882, + "Fungi Forest Enemy: Near Well Tag/Forest Enemy: Near Well Tag": 14041883, + "Fungi Forest Enemy: Yellow Tunnel (0)/Forest Enemy: Yellow Tunnel (0)": 14041884, + "Fungi Forest Enemy: Yellow Tunnel (1)/Forest Enemy: Yellow Tunnel (1)": 14041885, + "Fungi Forest Enemy: Yellow Tunnel (2)/Forest Enemy: Yellow Tunnel (2)": 14041886, + "Fungi Forest Enemy: Yellow Tunnel (3)/Forest Enemy: Yellow Tunnel (3)": 14041887, + "Fungi Forest Enemy: Near Snide/Forest Enemy: Near Snide": 14041888, + "Fungi Forest Enemy: Near the hidden Rainbow Coin/Forest Enemy: Near the hidden Rainbow Coin": 14041889, + "Fungi Forest Enemy: Near BBlast/Forest Enemy: Near BBlast": 14041890, + "Fungi Forest Enemy: Near Dark Attic/Forest Enemy: Near Dark Attic": 14041891, + "Fungi Forest Enemy: Near Well Exit/Forest Enemy: Near Well Exit": 14041892, + "Fungi Forest Enemy: Near Blue Tunnel/Forest Enemy: Near Blue Tunnel": 14041893, + "Fungi Forest Enemy: Thornvine (0)/Forest Enemy: Thornvine (0)": 14041894, + "Fungi Forest Enemy: Thornvine (1)/Forest Enemy: Thornvine (1)": 14041895, + "Fungi Forest Enemy: Thornvine (2)/Forest Enemy: Thornvine (2)": 14041896, + "Fungi Forest Enemy: Thornvine Entrance/Forest Enemy: Thornvine Entrance": 14041897, + "Forest Anthill/Forest Anthill Enemy: Gauntlet (0)": 14041898, + "Forest Anthill/Forest Anthill Enemy: Gauntlet (1)": 14041899, + "Forest Anthill/Forest Anthill Enemy: Gauntlet (2)": 14041900, + "Forest Anthill/Forest Anthill Enemy: Gauntlet (3)": 14041901, + "Winch Room/Forest Winch Room Enemy: Enemy": 14041902, + "Forest Thornvine Barn Enemy: Enemy/Forest Thornvine Barn Enemy: Enemy": 14041903, + "Forest Mill Front Enemy: Enemy/Forest Mill Front Enemy: Enemy": 14041904, + "Forest Mill Back Enemy: Enemy/Forest Mill Back Enemy: Enemy": 14041905, + "Inside the Mushroom/Forest Giant Mushroom Enemy: Above Night Door": 14041906, + "Inside the Mushroom/Forest Giant Mushroom Enemy: Path (0)": 14041907, + "Inside the Mushroom/Forest Giant Mushroom Enemy: Path (1)": 14041908, + "Zinger Room/Forest Lanky Zingers Room Enemy: Enemy (0)": 14041909, + "Zinger Room/Forest Lanky Zingers Room Enemy: Enemy (1)": 14041910, + "Face Puzzle Room/Forest Chunky Face Room Enemy: Enemy": 14041911, + "Crystal Caves Enemy: Start/Caves Enemy: Start": 14041912, + "Crystal Caves Enemy: Near Ice Castle/Caves Enemy: Near Ice Castle": 14041913, + "Crystal Caves Enemy: Outside 5DC/Caves Enemy: Outside 5DC": 14041914, + "Crystal Caves Enemy: 1DC Waterfall/Caves Enemy: 1DC Waterfall": 14041915, + "Crystal Caves Enemy: Near Funky/Caves Enemy: Near Funky": 14041916, + "Crystal Caves Enemy: Near Snide/Caves Enemy: Near Snide": 14041917, + "Crystal Caves Enemy: Near Bonus Room/Caves Enemy: Near Bonus Room": 14041918, + "Crystal Caves Enemy: 1DC Headphones/Caves Enemy: 1DC Headphones": 14041919, + "Caves DK 5 Door Igloo/Caves Donkey Igloo Enemy: Right": 14041920, + "Caves DK 5 Door Igloo/Caves Donkey Igloo Enemy: Left": 14041921, + "Caves Tiny 5 Door Igloo/Caves Tiny Igloo Enemy: Big Enemy": 14041922, + "Caves Lanky Sprint Cabin/Caves Lanky Cabin Enemy: Near": 14041923, + "Creepy Castle Enemy: Near Bridge (0)/Castle Enemy: Near Bridge (0)": 14041924, + "Creepy Castle Enemy: Near Bridge (1)/Castle Enemy: Near Bridge (1)": 14041925, + "Creepy Castle Enemy: Wooden Extrusion (0)/Castle Enemy: Wooden Extrusion (0)": 14041926, + "Creepy Castle Enemy: Wooden Extrusion (1)/Castle Enemy: Wooden Extrusion (1)": 14041927, + "Creepy Castle Enemy: Near Shed/Castle Enemy: Near Shed": 14041928, + "Creepy Castle Enemy: Near Library/Castle Enemy: Near Library": 14041929, + "Creepy Castle Enemy: Near Tower/Castle Enemy: Near Tower": 14041930, + "Creepy Castle Enemy: Museum Steps/Castle Enemy: Museum Steps": 14041931, + "Creepy Castle Enemy: Near Low Cave/Castle Enemy: Near Low Cave": 14041932, + "Creepy Castle Enemy: Path To Low Kasplat/Castle Enemy: Path To Low Kasplat": 14041933, + "Creepy Castle Enemy: Low TnS/Castle Enemy: Low TnS": 14041934, + "Creepy Castle Enemy: Path To Dungeon/Castle Enemy: Path To Dungeon": 14041935, + "Creepy Castle Enemy: Near Headphones/Castle Enemy: Near Headphones": 14041936, + "Creepy Castle Lobby Enemy: Left/Isles Castle Lobby Enemy: Left": 14041937, + "Creepy Castle Lobby Enemy: Far Right/Isles Castle Lobby Enemy: Far Right": 14041938, + "Creepy Castle Lobby Enemy: Near Right/Isles Castle Lobby Enemy: Near Right": 14041939, + "Castle Ballroom Enemy: Start/Castle Ballroom Enemy: Start": 14041940, + "Castle Dungeon Enemy: Face Room/Castle Dungeon Enemy: Face Room": 14041941, + "Castle Dungeon Enemy: Chair Room/Castle Dungeon Enemy: Chair Room": 14041942, + "Castle Dungeon Enemy: Outside Lanky Room/Castle Dungeon Enemy: Outside Lanky Room": 14041943, + "Castle Lower Cave Enemy: Near Crypt/Castle Lower Cave Enemy: Near Crypt": 14041944, + "Castle Lower Cave Enemy: Stair Right/Castle Lower Cave Enemy: Stair Right": 14041945, + "Castle Lower Cave Enemy: Stair Left/Castle Lower Cave Enemy: Stair Left": 14041946, + "Castle Lower Cave Enemy: Near Mausoleum/Castle Lower Cave Enemy: Near Mausoleum": 14041947, + "Castle Lower Cave Enemy: Near Funky/Castle Lower Cave Enemy: Near Funky": 14041948, + "Castle Lower Cave Enemy: Near Tag/Castle Lower Cave Enemy: Near Tag": 14041949, + "Castle Diddy Crypt/Castle Crypt Enemy: Diddy Coffin (0)": 14041950, + "Castle Diddy Crypt/Castle Crypt Enemy: Diddy Coffin (1)": 14041951, + "Castle Diddy Crypt/Castle Crypt Enemy: Diddy Coffin (2)": 14041952, + "Castle Diddy Crypt/Castle Crypt Enemy: Diddy Coffin (3)": 14041953, + "Castle Chunky Crypt/Castle Crypt Enemy: Chunky Coffin (0)": 14041954, + "Castle Chunky Crypt/Castle Crypt Enemy: Chunky Coffin (1)": 14041955, + "Castle Chunky Crypt/Castle Crypt Enemy: Chunky Coffin (2)": 14041956, + "Castle Chunky Crypt/Castle Crypt Enemy: Chunky Coffin (3)": 14041957, + "Castle DK Minecart/Castle Crypt Enemy: Minecart Entry": 14041958, + "Castle Crypt Enemy: Fork/Castle Crypt Enemy: Fork": 14041959, + "Castle Crypt Enemy: Near Diddy/Castle Crypt Enemy: Near Diddy": 14041960, + "Castle Crypt Enemy: Near Chunky/Castle Crypt Enemy: Near Chunky": 14041961, + "Mausoleum/Castle Mausoleum Enemy: Tiny Path": 14041962, + "Mausoleum/Castle Mausoleum Enemy: Lanky Path (0)": 14041963, + "Mausoleum/Castle Mausoleum Enemy: Lanky Path (1)": 14041964, + "Castle Upper Cave Enemy: Near Dungeon/Castle Upper Cave Enemy: Near Dungeon": 14041965, + "Castle Upper Cave Enemy: Near Pit/Castle Upper Cave Enemy: Near Pit": 14041966, + "Castle Upper Cave Enemy: Near Entrance/Castle Upper Cave Enemy: Near Entrance": 14041967, + "Castle DK Library/Castle Library Enemy: Fork Left (0)": 14041968, + "Castle DK Library/Castle Library Enemy: Fork Left (1)": 14041969, + "Castle DK Library/Castle Library Enemy: Fork Center": 14041970, + "Castle DK Library/Castle Library Enemy: Fork Right": 14041971, + "Castle Museum Enemy: Main Floor (0)/Castle Museum Enemy: Main Floor (0)": 14041972, + "Castle Museum Enemy: Main Floor (1)/Castle Museum Enemy: Main Floor (1)": 14041973, + "Castle Museum Enemy: Main Floor (2)/Castle Museum Enemy: Main Floor (2)": 14041974, + "Castle Museum Enemy: Main Floor (3)/Castle Museum Enemy: Main Floor (3)": 14041975, + "Castle Museum Enemy: Start/Castle Museum Enemy: Start": 14041976, + "Inside the Tree/Castle Tree Enemy: Start Room (0)": 14041977, + "Inside the Tree/Castle Tree Enemy: Start Room (1)": 14041978, + "Hideout Helm Enemy: Start (0)/Helm Enemy: Start (0)": 14041979, + "Hideout Helm Enemy: Start (1)/Helm Enemy: Start (1)": 14041980, + "Hideout Helm Enemy: Hill/Helm Enemy: Hill": 14041981, + "Hideout Helm Enemy: Switch Room (0)/Helm Enemy: Switch Room (0)": 14041982, + "Hideout Helm Enemy: Switch Room (1)/Helm Enemy: Switch Room (1)": 14041983, + "Hideout Helm Enemy: Mini Room (0)/Helm Enemy: Mini Room (0)": 14041984, + "Hideout Helm Enemy: Mini Room (1)/Helm Enemy: Mini Room (1)": 14041985, + "Hideout Helm Enemy: Mini Room (2)/Helm Enemy: Mini Room (2)": 14041986, + "Hideout Helm Enemy: Mini Room (3)/Helm Enemy: Mini Room (3)": 14041987, + "Hideout Helm Enemy: DKRoom/Helm Enemy: DKRoom": 14041988, + "Hideout Helm Enemy: Chunky Room (0)/Helm Enemy: Chunky Room (0)": 14041989, + "Hideout Helm Enemy: Chunky Room (1)/Helm Enemy: Chunky Room (1)": 14041990, + "Hideout Helm Enemy: Tiny Room/Helm Enemy: Tiny Room": 14041991, + "Hideout Helm Enemy: Lanky Room (0)/Helm Enemy: Lanky Room (0)": 14041992, + "Hideout Helm Enemy: Lanky Room (1)/Helm Enemy: Lanky Room (1)": 14041993, + "Hideout Helm Enemy: Diddy Room (0)/Helm Enemy: Diddy Room (0)": 14041994, + "Hideout Helm Enemy: Diddy Room (1)/Helm Enemy: Diddy Room (1)": 14041995, + "Hideout Helm Enemy: Nav Right/Helm Enemy: Nav Right": 14041996, + "Hideout Helm Enemy: Nav Left/Helm Enemy: Nav Left": 14041997, + "Isles Enemy: Pineapple Cage (0)/Isles Enemy: Pineapple Cage (0)": 14041998, + "Isles Enemy: Fungi Cannon (0)/Isles Enemy: Fungi Cannon (0)": 14041999, + "Isles Enemy: Japes Entrance/Isles Enemy: Japes Entrance": 14042000, + "Isles Enemy: Monkeyport Pad/Isles Enemy: Monkeyport Pad": 14042001, + "Isles Enemy: Upper Factory Path/Isles Enemy: Upper Factory Path": 14042002, + "Isles Enemy: Near Aztec/Isles Enemy: Near Aztec": 14042003, + "Isles Enemy: Fungi Cannon (1)/Isles Enemy: Fungi Cannon (1)": 14042004, + "Isles Enemy: Pineapple Cage (1)/Isles Enemy: Pineapple Cage (1)": 14042005, + "Isles Enemy: Lower Factory Path (0)/Isles Enemy: Lower Factory Path (0)": 14042006, + "Isles Enemy: Lower Factory Path (1)/Isles Enemy: Lower Factory Path (1)": 14042007, + "Medals/Japes Donkey Half Medal": 14042329, + "Medals/Japes Diddy Half Medal": 14042330, + "Medals/Japes Lanky Half Medal": 14042331, + "Medals/Japes Tiny Half Medal": 14042332, + "Medals/Japes Chunky Half Medal": 14042333, + "Medals/Aztec Donkey Half Medal": 14042334, + "Medals/Aztec Diddy Half Medal": 14042335, + "Medals/Aztec Lanky Half Medal": 14042336, + "Medals/Aztec Tiny Half Medal": 14042337, + "Medals/Aztec Chunky Half Medal": 14042338, + "Medals/Factory Donkey Half Medal": 14042339, + "Medals/Factory Diddy Half Medal": 14042340, + "Medals/Factory Lanky Half Medal": 14042341, + "Medals/Factory Tiny Half Medal": 14042342, + "Medals/Factory Chunky Half Medal": 14042343, + "Medals/Galleon Donkey Half Medal": 14042344, + "Medals/Galleon Diddy Half Medal": 14042345, + "Medals/Galleon Lanky Half Medal": 14042346, + "Medals/Galleon Tiny Half Medal": 14042347, + "Medals/Galleon Chunky Half Medal": 14042348, + "Medals/Forest Donkey Half Medal": 14042349, + "Medals/Forest Diddy Half Medal": 14042350, + "Medals/Forest Lanky Half Medal": 14042351, + "Medals/Forest Tiny Half Medal": 14042352, + "Medals/Forest Chunky Half Medal": 14042353, + "Medals/Caves Donkey Half Medal": 14042354, + "Medals/Caves Diddy Half Medal": 14042355, + "Medals/Caves Lanky Half Medal": 14042356, + "Medals/Caves Tiny Half Medal": 14042357, + "Medals/Caves Chunky Half Medal": 14042358, + "Medals/Castle Donkey Half Medal": 14042359, + "Medals/Castle Diddy Half Medal": 14042360, + "Medals/Castle Lanky Half Medal": 14042361, + "Medals/Castle Tiny Half Medal": 14042362, + "Medals/Castle Chunky Half Medal": 14042363, +} + + +# Universal Tracker integration configuration +tracker_world = { + "external_pack_key": "ut_pack_path", + "map_page_maps": ["maps/maps.json"], + "map_page_groups": [ + ("Overview", ["overview"]), + ("DK Isles", ["isles", "training", "snidelobby", "japeslobby", "azteclobby", "factorylobby", "galleonlobby", "forestlobby", "caveslobby", "castlelobby", "helmlobby"]), + ("Jungle Japes", ["japes", "japesunder", "japesmountain", "shellhive"]), + ("Angry Aztec", ["aztec", "tinytemple", "llamatemple", "dk5dt", "diddy5dt", "lanky5dt", "tiny5dt", "chunky5dt"]), + ("Frantic Factory", ["factory"]), + ("Gloomy Galleon", ["galleon"]), + ("Fungi Forest", ["forest", "frontmill", "rearmill", "barn"]), + ("Crystal Caves", ["caves"]), + ("Creepy Castle", ["castle", "ballroom", "museum", "crypthub", "crypt", "dungeontunnel", "dungeon"]), + ("Hideout Helm", ["helm"]), + ], + "map_page_locations": [ + "locations/overview.json", + "locations/japes.json", + "locations/aztec.json", + "locations/factory.json", + "locations/galleon.json", + "locations/forest.json", + "locations/caves.json", + "locations/castle.json", + "locations/helm.json", + "locations/isles.json", + "locations/shops.json", + "locations/snides.json", + "locations/japesdropsanity.json", + "locations/aztecdropsanity.json", + "locations/factorydropsanity.json", + "locations/galleondropsanity.json", + "locations/forestdropsanity.json", + "locations/cavesdropsanity.json", + "locations/castledropsanity.json", + "locations/helmdropsanity.json", + "locations/islesdropsanity.json", + ], + "map_page_setting_key": "DK64Rando_{team}_{player}_map", + "map_page_index": dk64_map_to_tab_index, + "poptracker_name_mapping": poptracker_name_mapping, +} diff --git a/randomizer/Lists/CustomLocations.py b/randomizer/Lists/CustomLocations.py index d463d75d9..821976a93 100644 --- a/randomizer/Lists/CustomLocations.py +++ b/randomizer/Lists/CustomLocations.py @@ -1572,7 +1572,11 @@ class LocationTypes(IntEnum): z=2385, max_size=64, logic_region=Regions.LlamaTemple, - logic=lambda l: Events.AztecLlamaSpit in l.Events and l.HasGun(Kongs.any) and l.swim and l.scope and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or (not l.istiny)), + logic=lambda l: Events.AztecLlamaSpit in l.Events + and l.HasGun(Kongs.any) + and l.swim + and l.scope + and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or l.isdonkey or l.isdiddy or l.islanky or l.ischunky), group=4, banned_types=[LocationTypes.CrownPad, LocationTypes.DirtPatch, LocationTypes.Bananaport], ), @@ -3855,7 +3859,7 @@ class LocationTypes(IntEnum): max_size=64, logic_region=Regions.IglooArea, group=3, - logic=lambda l: (l.HasGun(Kongs.any) and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or (not l.istiny))) or l.Slam, + logic=lambda l: (l.HasGun(Kongs.any) and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or l.isdonkey or l.isdiddy or l.islanky or l.ischunky)) or l.Slam, banned_types=[LocationTypes.CrownPad, LocationTypes.DirtPatch, LocationTypes.Bananaport], ), CustomLocation( @@ -6123,22 +6127,10 @@ class LocationTypes(IntEnum): z=1159, max_size=64, logic_region=Regions.TrainingGrounds, - logic=lambda l: l.HasGun(Kongs.any) and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or (not l.istiny)) and l.swim and l.scope, + logic=lambda l: l.HasGun(Kongs.any) and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or l.isdonkey or l.isdiddy or l.islanky or l.ischunky) and l.swim and l.scope, group=3, banned_types=[LocationTypes.CrownPad, LocationTypes.DirtPatch], ), - # CustomLocation( - # map=Maps.TrainingGrounds, - # name="Training Grounds: Under Water in Corner", - # x=1962, - # y=-187, - # z=1324, - # max_size=64, - # logic_region=Regions.TrainingGrounds, - # logic=lambda l: l.HasGun(Kongs.any) and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or (not l.istiny)) and l.swim and l.scope, - # group=2, - # banned_types=[LocationTypes.CrownPad, LocationTypes.DirtPatch], - # ), CustomLocation( map=Maps.TrainingGrounds, name="Training Grounds: Near Pool", diff --git a/randomizer/LogicFiles/AngryAztec.py b/randomizer/LogicFiles/AngryAztec.py index c70ab56db..358b6a7a7 100644 --- a/randomizer/LogicFiles/AngryAztec.py +++ b/randomizer/LogicFiles/AngryAztec.py @@ -210,7 +210,7 @@ TransitionFront(Regions.TinyTempleEntrance, lambda l: (Events.FedTotem in l.Events and l.feather and l.istiny) or l.CanPhase(), Transitions.AztecMainToTiny), TransitionFront(Regions.ChunkyTempleEntrance, lambda l: (Events.FedTotem in l.Events and l.pineapple and l.ischunky) or l.CanPhase() or (l.generalclips and l.ischunky and l.hunkyChunky), Transitions.AztecMainToChunky), TransitionFront(Regions.AztecTinyRace, lambda l: l.charge and l.jetpack and l.diddy and l.mini and l.saxophone and l.istiny, Transitions.AztecMainToRace), - TransitionFront(Regions.LlamaTemple, lambda l: l.canOpenLlamaTemple() or l.CanPhase() or (l.generalclips and not l.islanky), Transitions.AztecMainToLlama), + TransitionFront(Regions.LlamaTemple, lambda l: l.canOpenLlamaTemple() or l.CanPhase() or (l.generalclips and l.isdonkey or l.isdiddy or l.istiny or l.ischunky), Transitions.AztecMainToLlama), TransitionFront(Regions.AztecBaboonBlast, lambda l: l.blast and l.isdonkey), # , Transitions.AztecMainToBBlast), TransitionFront(Regions.Snide, lambda l: l.snideAccess), TransitionFront(Regions.FunkyAztec, lambda l: l.funkyAccess), diff --git a/randomizer/LogicFiles/CrystalCaves.py b/randomizer/LogicFiles/CrystalCaves.py index 871dbfc64..cc5e5855e 100644 --- a/randomizer/LogicFiles/CrystalCaves.py +++ b/randomizer/LogicFiles/CrystalCaves.py @@ -138,7 +138,7 @@ ), Regions.FrozenCastle: Region("Frozen Castle", HintRegion.MainCaves, Levels.CrystalCaves, False, None, [ - LocationLogic(Locations.CavesLankyCastle, lambda l: l.Slam and (l.islanky or (l.settings.free_trade_items and (not l.isdonkey or l.superSlam)))), + LocationLogic(Locations.CavesLankyCastle, lambda l: l.Slam and (l.islanky or (l.settings.free_trade_items and (l.isdiddy or l.istiny or l.ischunky or l.superSlam)))), LocationLogic(Locations.KremKap_CavesNPC_IceTomato, lambda l: l.camera), ], [], [ TransitionFront(Regions.CrystalCavesMain, lambda _: True, Transitions.CavesCastleToMain), diff --git a/randomizer/Patching/MirrorMode.py b/randomizer/Patching/MirrorMode.py index 2d7f8b513..056c32fc8 100644 --- a/randomizer/Patching/MirrorMode.py +++ b/randomizer/Patching/MirrorMode.py @@ -35,12 +35,13 @@ def readDataFromBytestream(data: bytearray, offset: int, size: int, signed: bool value = (1 << (8 * size)) - value return value + def writeValueToBytestream(data: bytearray, value: int, offset: int, size: int) -> bytearray: """Write data to a byte stream.""" values = [0] * size value = int(value) if value < 0: - value += (1 << (size * 8)) + value += 1 << (size * 8) for x in range(size): values[(size - x) - 1] = value & 0xFF value >>= 8 @@ -73,6 +74,7 @@ def ApplyMirrorMode(settings: Settings, ROM_COPY: LocalROM): dl_end = readDataFromBytestream(data, 0x48, 4) FlipDisplayList(ROM_COPY, data, dl_start, dl_end, tbl, file_index) + MISC_SCALES = { 0: 1, # Test Map 29: 1, # Power Shed @@ -87,6 +89,7 @@ def ApplyMirrorMode(settings: Settings, ROM_COPY: LocalROM): 188: 1, # Fungi Blast } + def applyCoordTransform(value: float, map_index: int = 0, apply_scaling: bool = False): """Apply the flipping coordinate transform.""" offset = 3000 @@ -94,6 +97,7 @@ def applyCoordTransform(value: float, map_index: int = 0, apply_scaling: bool = offset *= MISC_SCALES.get(map_index, 3) return offset - value + def ApplyMirrorModeNew(ROM_COPY: LocalROM): """Apply all Mirror Mode changes (testing).""" for map_index in range(216): @@ -176,7 +180,10 @@ def ApplyMirrorModeNew(ROM_COPY: LocalROM): block_end = readDataFromBytestream(file_data, ref, 4) ref += 4 block_count = int((block_end - start) / 0x18) - print(hex(block_end), hex(block_count), ) + print( + hex(block_end), + hex(block_count), + ) for _ in range(block_count): div = coldata["divisor"] for cs in range(3): @@ -207,6 +214,7 @@ def ApplyMirrorModeNew(ROM_COPY: LocalROM): map_exits = writeValueToBytestream(map_exits, new_value, offset, 2) writeRawFile(TableNames.Exits, map_index, False, map_exits, ROM_COPY) + def trimData(data: bytes, alignment: int = 0x10) -> bytes: """Trim a bytes object to remove trailing null bytes, and then align the size of the object to a certain modulo.""" if alignment <= 0: diff --git a/requirement_data.js b/requirement_data.js index d73e3236f..61ebdec14 100644 --- a/requirement_data.js +++ b/requirement_data.js @@ -70,11 +70,15 @@ const requirement_data = { new Requirement(10, [[Moves.Coconut, Moves.Strong]]), // 2 bunches in AngryAztecOasis new Requirement(30, [[Moves.Coconut, Moves.AztecTunnelDoor]]), // 1 balloon, 2 balloons in AngryAztecMain new Requirement(15, [ // 15 bananas in LlamaTemple + [Moves.Mini, Moves.AztecTunnelDoor], [Moves.Coconut, Moves.AztecTunnelDoor, Moves.AztecLlama], [Moves.Grape, Moves.AztecTunnelDoor, Moves.AztecLlama], [Moves.Feather, Moves.AztecTunnelDoor, Moves.AztecLlama], ]), new Requirement(20, [ // 4 bunches in AztecDonkeyQuicksandCave + [Moves.LevelSlam, Moves.Strong, Moves.Diddy, Moves.AztecTunnelDoor], + [Moves.LevelSlam, Moves.Strong, Moves.Tiny, Moves.AztecTunnelDoor], + [Moves.LevelSlam, Moves.Strong, Moves.Chunky, Moves.AztecTunnelDoor], [Moves.LevelSlam, Moves.Coconut, Moves.Strong, Moves.AztecTunnelDoor, Moves.AztecLlama], [Moves.LevelSlam, Moves.Strong, Moves.Grape, Moves.AztecTunnelDoor, Moves.AztecLlama], [Moves.LevelSlam, Moves.Strong, Moves.Feather, Moves.AztecTunnelDoor, Moves.AztecLlama], @@ -92,11 +96,7 @@ const requirement_data = { [Moves.ClimbingCheck, Moves.AztecTunnelDoor], [Moves.Rocket, Moves.AztecTunnelDoor], ]), - new Requirement(10, [ // 1 balloon in AztecDonkeyQuicksandCave - [Moves.LevelSlam, Moves.Coconut, Moves.Strong, Moves.Peanut, Moves.AztecTunnelDoor, Moves.AztecLlama, Moves.AztecW5Bonus], - [Moves.LevelSlam, Moves.Strong, Moves.Peanut, Moves.Grape, Moves.AztecTunnelDoor, Moves.AztecLlama, Moves.AztecW5Bonus], - [Moves.LevelSlam, Moves.Strong, Moves.Peanut, Moves.Feather, Moves.AztecTunnelDoor, Moves.AztecLlama, Moves.AztecW5Bonus], - ]), + new Requirement(10, [[Moves.LevelSlam, Moves.Strong, Moves.Peanut, Moves.AztecTunnelDoor, Moves.AztecW5Bonus]]), // 1 balloon in AztecDonkeyQuicksandCave ], "Lanky": [ new Requirement(5, [[Moves.Moveless]]), // 5 bananas in AngryAztecOasis @@ -104,38 +104,35 @@ const requirement_data = { new Requirement(25, [[Moves.ClimbingCheck, Moves.AztecTunnelDoor]]), // 5 bunches in AngryAztecMain new Requirement(14, [[Moves.Diving, Moves.Grape, Moves.TinyTempleIce]]), // 1 bunch, 9 bananas in TempleVultureRoom new Requirement(10, [[Moves.Grape, Moves.AztecTunnelDoor, Moves.Aztec5DT]]), // 1 balloon in LankyTemple - new Requirement(5, [[Moves.Vines, Moves.Grape, Moves.AztecTunnelDoor, Moves.AztecLlama]]), // 1 bunch in LlamaTempleMatching - new Requirement(20, [[Moves.Diving, Moves.Grape, Moves.AztecTunnelDoor, Moves.AztecLlama]]), // 2 balloons in LlamaTemple + new Requirement(20, [ // 2 balloons in LlamaTemple + [Moves.Diving, Moves.Grape, Moves.Mini, Moves.AztecTunnelDoor], + [Moves.Diving, Moves.Grape, Moves.AztecTunnelDoor, Moves.AztecLlama], + ]), new Requirement(11, [ // 1 bunch, 6 bananas in LlamaTemple + [Moves.Mini, Moves.AztecTunnelDoor], [Moves.Coconut, Moves.AztecTunnelDoor, Moves.AztecLlama], [Moves.Grape, Moves.AztecTunnelDoor, Moves.AztecLlama], [Moves.Feather, Moves.AztecTunnelDoor, Moves.AztecLlama], ]), + new Requirement(5, [ // 1 bunch in LlamaTempleMatching + [Moves.Vines, Moves.Grape, Moves.Mini, Moves.AztecTunnelDoor], + [Moves.Vines, Moves.Grape, Moves.IsDiddy, Moves.AztecTunnelDoor], + [Moves.Vines, Moves.Grape, Moves.IsTiny, Moves.AztecTunnelDoor], + [Moves.Vines, Moves.Grape, Moves.IsChunky, Moves.AztecTunnelDoor], + [Moves.Vines, Moves.Grape, Moves.AztecTunnelDoor, Moves.AztecLlama], + ]), ], "Tiny": [ - new Requirement(25, [[Moves.AztecTunnelDoor]]), // 1 bunch, 1 bunch, 10 bananas, 5 bananas in AngryAztecMain + new Requirement(28, [[Moves.AztecTunnelDoor]]), // 1 bunch, 1 bunch, 10 bananas, 5 bananas in AngryAztecMain; 3 bananas in LlamaTemple + new Requirement(10, [[Moves.Feather, Moves.AztecTunnelDoor]]), // 1 balloon in LlamaTemple + new Requirement(2, [[Moves.Mini, Moves.AztecTunnelDoor]]), // 2 bananas in LlamaTempleBack new Requirement(20, [[Moves.Diving, Moves.Feather, Moves.TinyTempleIce]]), // 2 balloons in TempleKONGRoom - new Requirement(10, [[Moves.Feather, Moves.AztecTunnelDoor, Moves.AztecLlama]]), // 1 balloon in LlamaTemple + new Requirement(10, [[Moves.LevelSlam, Moves.Mini, Moves.AztecTunnelDoor]]), // 2 bunches in LlamaTempleBack new Requirement(5, [[Moves.Diving, Moves.Feather, Moves.Mini, Moves.TinyTempleIce]]), // 5 bananas in TempleUnderwater new Requirement(25, [ // 5 bunches in AngryAztecMain [Moves.ClimbingCheck, Moves.AztecTunnelDoor], [Moves.Twirl, Moves.AztecTunnelDoor], ]), - new Requirement(3, [ // 3 bananas in LlamaTemple - [Moves.Coconut, Moves.AztecTunnelDoor, Moves.AztecLlama], - [Moves.Grape, Moves.AztecTunnelDoor, Moves.AztecLlama], - [Moves.Feather, Moves.AztecTunnelDoor, Moves.AztecLlama], - ]), - new Requirement(2, [ // 2 bananas in LlamaTempleBack - [Moves.Coconut, Moves.Mini, Moves.AztecTunnelDoor, Moves.AztecLlama], - [Moves.Grape, Moves.Mini, Moves.AztecTunnelDoor, Moves.AztecLlama], - [Moves.Feather, Moves.Mini, Moves.AztecTunnelDoor, Moves.AztecLlama], - ]), - new Requirement(10, [ // 2 bunches in LlamaTempleBack - [Moves.LevelSlam, Moves.Coconut, Moves.Mini, Moves.AztecTunnelDoor, Moves.AztecLlama], - [Moves.LevelSlam, Moves.Grape, Moves.Mini, Moves.AztecTunnelDoor, Moves.AztecLlama], - [Moves.LevelSlam, Moves.Feather, Moves.Mini, Moves.AztecTunnelDoor, Moves.AztecLlama], - ]), ], "Chunky": [ new Requirement(29, [[Moves.Pineapple]]), // 4 bananas, 5 bunches in TempleStart diff --git a/wiki/article_markdown/custom_locations/CustomLocationsMiscellaneous.MD b/wiki/article_markdown/custom_locations/CustomLocationsMiscellaneous.MD index 3f6c3c00c..2f185e041 100644 --- a/wiki/article_markdown/custom_locations/CustomLocationsMiscellaneous.MD +++ b/wiki/article_markdown/custom_locations/CustomLocationsMiscellaneous.MD @@ -124,7 +124,7 @@ | Aztec Llama Temple | Llama Temple: Vanilla Far Warp 1 | | `self.logic = lambda _: True` | | Aztec Llama Temple | Llama Temple: Vanilla Lava Warp 2 | | `self.logic = lambda _: True` | | Aztec Llama Temple | Llama Temple: Vanilla Close Warp 2 | | `self.logic = lambda _: True` | -| Aztec Llama Temple | In the Water | CrownPad, DirtPatch, Bananaport | `Events.AztecLlamaSpit in l.Events and l.HasGun(Kongs.any) and l.swim and l.scope and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or (not l.istiny))` | +| Aztec Llama Temple | In the Water | CrownPad, DirtPatch, Bananaport | `Events.AztecLlamaSpit in l.Events and l.HasGun(Kongs.any) and l.swim and l.scope and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or l.isdonkey or l.isdiddy or l.islanky or l.ischunky)` | | Aztec Llama Temple | Llama Temple: DK Switch | | `self.logic = lambda _: True` | | Aztec Llama Temple | Llama Temple: Lava Room | | `self.logic = lambda _: True` | @@ -333,7 +333,7 @@ | Crystal Caves | On igloo Pillar | MelonCrate | `(l.jetpack and l.isdiddy) or (l.twirl and l.istiny and (not l.isKrushaAdjacent(Kongs.tiny)))` | | Crystal Caves | On top of the Igloo | CrownPad, MelonCrate | `self.logic = lambda _: True` | | Crystal Caves | Under tag barrel near igloo | MelonCrate | `self.logic = lambda _: True` | -| Crystal Caves | In front of Igloo | CrownPad, DirtPatch, Bananaport | `(l.HasGun(Kongs.any) and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or (not l.istiny))) or l.Slam` | +| Crystal Caves | In front of Igloo | CrownPad, DirtPatch, Bananaport | `(l.HasGun(Kongs.any) and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or l.isdonkey or l.isdiddy or l.islanky or l.ischunky)) or l.Slam` | | Crystal Caves | In the mini cave | | `self.logic = lambda _: True` | | Crystal Caves | Near ice wall to boulder | | `self.logic = lambda _: True` | | Crystal Caves | In Giant Boulder Room | | `self.logic = lambda _: True` | @@ -538,7 +538,7 @@ | Training Grounds | Training Grounds: Near Mountain | | `l.climbing and ((l.twirl and l.istiny) or (l.monkey_maneuvers and l.isdonkey and (not l.isKrushaAdjacent(Kongs.donkey))))` | | Training Grounds | Training Grounds: Rear Cave | | `self.logic = lambda _: True` | | Training Grounds | Training Grounds: Banana Hoard (back) | | `(l.can_use_vines or l.CanMoonkick()) and l.climbing` | -| Training Grounds | Training Grounds: Underwater | CrownPad, DirtPatch | `l.HasGun(Kongs.any) and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or (not l.istiny)) and l.swim and l.scope` | +| Training Grounds | Training Grounds: Underwater | CrownPad, DirtPatch | `l.HasGun(Kongs.any) and ((l.istiny and l.isKrushaAdjacent(Kongs.tiny)) or l.isdonkey or l.isdiddy or l.islanky or l.ischunky) and l.swim and l.scope` | | Training Grounds | Training Grounds: Near Pool | | `self.logic = lambda _: True` | | Treehouse | Treehouse: back | | `self.logic = lambda _: True` | | Banana Fairy Room | Banana Fairy Room: Right of Queen | | `self.logic = lambda _: True` |